# Lyng time functions Lyng date and time support requires importing `lyng.time`. The module provides four related types: - `Instant` for absolute timestamps. - `Date` for calendar dates without time-of-day or timezone. - `DateTime` for calendar-aware points in time in a specific timezone. - `Duration` for absolute elapsed time. ## Time instant: `Instant` `Instant` represents some moment of time independently of the calendar. It is similar to SQL `TIMESTAMP` or Kotlin `Instant`. ### Constructing and converting import lyng.time val t1 = Instant() val t2 = Instant(1704110400) val t3 = Instant("2024-01-01T12:00:00.123456Z") val t4 = t3.truncateToMinute() assertEquals("2024-01-01T12:00:00Z", t4.toRFC3339()) val dt = t3.toDateTime("+02:00") assertEquals(14, dt.hour) val d = t3.toDate("Z") assertEquals(Date(2024, 1, 1), d) ### Instant members | member | description | |--------------------------------|------------------------------------------------------| | epochSeconds: Real | offset in seconds since Unix epoch | | epochWholeSeconds: Int | whole seconds since Unix epoch | | nanosecondsOfSecond: Int | nanoseconds within the current second | | isDistantFuture: Bool | true if it is `Instant.distantFuture` | | isDistantPast: Bool | true if it is `Instant.distantPast` | | truncateToMinute(): Instant | truncate to minute precision | | truncateToSecond(): Instant | truncate to second precision | | truncateToMillisecond(): Instant | truncate to millisecond precision | | truncateToMicrosecond(): Instant | truncate to microsecond precision | | toRFC3339(): String | format as RFC3339 string in UTC | | toDateTime(tz?): DateTime | localize to a timezone | | toDate(tz?): Date | convert to a calendar date in a timezone | ## Calendar date: `Date` `Date` represents a pure calendar date. It has no time-of-day and no attached timezone. Use it for values like birthdays, due dates, invoice dates, and SQL `DATE` columns. ### Constructing import lyng.time val today = Date() val d1 = Date(2026, 4, 15) val d2 = Date("2024-02-29") val d3 = Date.parseIso("2024-02-29") val d4 = Date(DateTime(2024, 5, 20, 15, 30, 45, "+02:00")) val d5 = Date(Instant("2024-01-01T23:30:00Z"), "+02:00") ### Date members | member | description | |--------------------------------|------------------------------------------------------------| | year: Int | year component | | month: Int | month component (1..12) | | day: Int | day of month (alias `dayOfMonth`) | | dayOfWeek: Int | day of week (1=Monday, 7=Sunday) | | dayOfYear: Int | day of year (1..365/366) | | isLeapYear: Bool | whether this date is in a leap year | | lengthOfMonth: Int | number of days in this month | | lengthOfYear: Int | 365 or 366 | | toIsoString(): String | ISO `YYYY-MM-DD` string | | toSortableString(): String | alias to `toIsoString()` | | toDateTime(tz="Z"): DateTime | start-of-day `DateTime` in the specified timezone | | atStartOfDay(tz="Z"): DateTime | alias to `toDateTime()` | | addDays(n): Date | add or subtract calendar days | | addMonths(n): Date | add or subtract months, normalizing end-of-month | | addYears(n): Date | add or subtract years | | daysUntil(other): Int | calendar days until `other` | | daysSince(other): Int | calendar days since `other` | | static today(tz?): Date | today in the specified timezone | | static parseIso(s): Date | parse ISO `YYYY-MM-DD` | ### Date arithmetic `Date` supports only whole-day arithmetic. This is deliberate: calendar dates should not silently accept sub-day durations. import lyng.time val d1 = Date(2026, 4, 15) val d2 = d1.addDays(10) assertEquals(Date(2026, 4, 25), d2) assertEquals(Date(2026, 4, 18), d1 + 3.days) assertEquals(Date(2026, 4, 12), d1 - 3.days) assertEquals(10, d1.daysUntil(d2)) assertEquals(10, d2.daysSince(d1)) assertEquals(10, d2 - d1) ### Date conversions import lyng.time val i = Instant("2024-01-01T23:30:00Z") assertEquals(Date(2024, 1, 1), i.toDate("Z")) assertEquals(Date(2024, 1, 2), i.toDate("+02:00")) val dt = DateTime(2024, 5, 20, 15, 30, 45, "+02:00") assertEquals(Date(2024, 5, 20), dt.date) assertEquals(Date(2024, 5, 20), dt.toDate()) assertEquals(DateTime(2024, 5, 20, 0, 0, 0, "Z"), Date(2024, 5, 20).toDateTime("Z")) assertEquals(DateTime(2024, 5, 20, 0, 0, 0, "+02:00"), Date(2024, 5, 20).atStartOfDay("+02:00")) ## Calendar time: `DateTime` `DateTime` represents a point in time in a specific timezone. It provides access to calendar components such as year, month, day, and hour. ### Constructing import lyng.time val now = DateTime.now() val offsetTime = DateTime.now("+02:00") val dt = Instant().toDateTime("Z") val dt2 = DateTime(2024, 1, 1, 12, 0, 0, "Z") val dt3 = DateTime.parseRFC3339("2024-01-01T12:00:00+02:00") ### DateTime members | member | description | |----------------------------------|-----------------------------------------------| | year: Int | year component | | month: Int | month component (1..12) | | day: Int | day of month (alias `dayOfMonth`) | | hour: Int | hour component (0..23) | | minute: Int | minute component (0..59) | | second: Int | second component (0..59) | | dayOfWeek: Int | day of week (1=Monday, 7=Sunday) | | timeZone: String | timezone ID string | | date: Date | calendar date component | | toInstant(): Instant | convert back to absolute Instant | | toDate(): Date | extract the calendar date in this timezone | | toUTC(): DateTime | shortcut to convert to UTC | | toTimeZone(tz): DateTime | convert to another timezone | | addMonths(n): DateTime | add/subtract months (normalizes end of month) | | addYears(n): DateTime | add/subtract years | | toRFC3339(): String | format with timezone offset | | static now(tz?): DateTime | create DateTime with current time | | static parseRFC3339(s): DateTime | parse RFC3339 string | ### Arithmetic and normalization `DateTime` handles calendar arithmetic correctly: import lyng.time val leapDay = Instant("2024-02-29T12:00:00Z").toDateTime("Z") val nextYear = leapDay.addYears(1) assertEquals(28, nextYear.day) # `Duration` class `Duration` represents absolute elapsed time between two instants. import lyng.time val t1 = Instant() delay(1.millisecond) val t2 = Instant() assert(t2 - t1 >= 1.millisecond) assert(t2 - t1 < 100.millisecond) >>> void Duration values can be created from numbers using extensions on `Int` and `Real`: - `n.millisecond`, `n.milliseconds` - `n.second`, `n.seconds` - `n.minute`, `n.minutes` - `n.hour`, `n.hours` - `n.day`, `n.days` Larger units like months or years are calendar-dependent and are intentionally not part of `Duration`. Each duration instance can be converted to numbers in these units: - `d.microseconds` - `d.milliseconds` - `d.seconds` - `d.minutes` - `d.hours` - `d.days` Example: import lyng.time assertEquals(60, 1.minute.seconds) assertEquals(10.milliseconds, 0.01.seconds) >>> void # Utility functions ## `delay(duration: Duration)` Suspends the current coroutine for at least the specified duration.