From 5c572de9fe2a64210a035967e800c6199aff98fa Mon Sep 17 00:00:00 2001 From: Kevin Gibbons Date: Thu, 30 Jan 2025 15:36:52 -0800 Subject: [PATCH 01/12] Avoid nonstandard use of names for types in wit-0.3.0-draft Co-authored-by: Philip Chimento --- README.md | 18 +++++----- wit-0.3.0-draft/monotonic-clock.wit | 12 +++---- .../{wall-clock.wit => system-clock.wit} | 35 ++++++++++++------- wit-0.3.0-draft/timezone.wit | 12 +++---- wit-0.3.0-draft/world.wit | 2 +- 5 files changed, 45 insertions(+), 34 deletions(-) rename wit-0.3.0-draft/{wall-clock.wit => system-clock.wit} (57%) diff --git a/README.md b/README.md index cd01d69..2beab9c 100644 --- a/README.md +++ b/README.md @@ -71,20 +71,20 @@ default-monotonic-clock: monotonic-clock ``` ```rust - let start: Instant = monotonic_clock::now(clock); + let start: Mark = monotonic_clock::now(clock); // some stuff - let stop: Instant = monotonic_clock::now(clock); + let stop: Mark = monotonic_clock::now(clock); - let elapsed: Instant = stop - start; + let elapsed: Duration = stop - start; ``` #### Telling the current human time: ```rust - let the_current_time = wall_clock::now(); + let the_current_time = system_clock::now(); println!("it has been {} seconds and {} nanoseconds since the Unix epoch!", the_current_time.seconds, the_current_time.nanoseconds); ``` @@ -92,9 +92,9 @@ default-monotonic-clock: monotonic-clock #### Retrieving the timezone: ```rust - let datetime: Datetime = wall_clock::now(); + let instant: Instant = system_clock::now(); - let timezone_display: TimezoneDisplay = timezone::display(datetime); + let timezone_display: TimezoneDisplay = timezone::display(instant); println!("the timezone is {}", timezone_display.name); ``` @@ -105,14 +105,14 @@ default-monotonic-clock: monotonic-clock In POSIX, `clock_gettime` uses a single `timespec` type to represent timestamps from all clocks, with two fields: seconds and nanoseconds. However, in applications -that just need to measure elapsed time, and don't need to care about wall clock +that just need to measure elapsed time, and don't need to care about absolute time, working with seconds and nanoseconds as separate fields adds extra code size and complexity. For these use cases, a single 64-bit nanoseconds value, which can measure up to about 584 years, is sufficient and simpler. -For wall clock time, it's still useful to have both seconds and nanoseconds, both +For system time, it's still useful to have both seconds and nanoseconds, both to be able to represent dates in the far future, and to reflect the fact that -code working with wall clock time will often want to treat seconds and fractions +code working with system time will often want to treat seconds and fractions of seconds differently. And so, this API uses different data types for different types of clocks. diff --git a/wit-0.3.0-draft/monotonic-clock.wit b/wit-0.3.0-draft/monotonic-clock.wit index d60a1ec..37524f6 100644 --- a/wit-0.3.0-draft/monotonic-clock.wit +++ b/wit-0.3.0-draft/monotonic-clock.wit @@ -9,11 +9,11 @@ package wasi:clocks@0.3.0-rc-2025-08-15; /// successive reads of the clock will produce non-decreasing values. @since(version = 0.3.0-rc-2025-08-15) interface monotonic-clock { - /// An instant in time, in nanoseconds. An instant is relative to an + /// A mark on a monotonic clock is a number of nanoseconds since an /// unspecified initial value, and can only be compared to instances from /// the same monotonic-clock. @since(version = 0.3.0-rc-2025-08-15) - type instant = u64; + type mark = u64; /// A duration of time, in nanoseconds. @since(version = 0.3.0-rc-2025-08-15) @@ -24,20 +24,20 @@ interface monotonic-clock { /// The clock is monotonic, therefore calling this function repeatedly will /// produce a sequence of non-decreasing values. @since(version = 0.3.0-rc-2025-08-15) - now: func() -> instant; + now: func() -> mark; /// Query the resolution of the clock. Returns the duration of time /// corresponding to a clock tick. @since(version = 0.3.0-rc-2025-08-15) get-resolution: func() -> duration; - /// Wait until the specified instant has occurred. + /// Wait until the specified mark has occurred. @since(version = 0.3.0-rc-2025-08-15) wait-until: async func( - when: instant, + when: mark, ); - /// Wait for the specified duration to elapse. + /// Wait for the specified duration. @since(version = 0.3.0-rc-2025-08-15) wait-for: async func( how-long: duration, diff --git a/wit-0.3.0-draft/wall-clock.wit b/wit-0.3.0-draft/system-clock.wit similarity index 57% rename from wit-0.3.0-draft/wall-clock.wit rename to wit-0.3.0-draft/system-clock.wit index 2e3b2d4..db66ca4 100644 --- a/wit-0.3.0-draft/wall-clock.wit +++ b/wit-0.3.0-draft/system-clock.wit @@ -1,27 +1,38 @@ package wasi:clocks@0.3.0-rc-2025-08-15; -/// WASI Wall Clock is a clock API intended to let users query the current -/// time. The name "wall" makes an analogy to a "clock on the wall", which -/// is not necessarily monotonic as it may be reset. +/// WASI System Clock is a clock API intended to let users query the current +/// time. The clock is not necessarily monotonic as it may be reset. /// /// It is intended to be portable at least between Unix-family platforms and /// Windows. /// -/// A wall clock is a clock which measures the date and time according to -/// some external reference. -/// /// External references may be reset, so this clock is not necessarily /// monotonic, making it unsuitable for measuring elapsed time. /// /// It is intended for reporting the current date and time for humans. @since(version = 0.3.0-rc-2025-08-15) -interface wall-clock { - /// A time and date in seconds plus nanoseconds. +interface system-clock { + /// An "instant", or "exact time", is a point in time without regard to any + /// time zone: just the time since a particular external reference point, + /// often called an "epoch". + /// Note that even if the seconds field is negative, incrementing + /// nanoseconds always represents moving forwards in time. + /// For example, `{ -1 seconds, 999999999 nanoseconds }` represents the + /// instant one nanosecond before the epoch. + /// For more on various different ways to represent time, see + /// https://tc39.es/proposal-temporal/docs/timezone.html @since(version = 0.3.0-rc-2025-08-15) - record datetime { - seconds: u64, + record instant { + seconds: s64, nanoseconds: u32, } + /// A duration of time, in seconds plus nanoseconds. + @since(version = 0.3.0-rc-2025-08-15) + type duration = { + seconds: u64, + nanoseconds: u32, + }; + /// Read the current value of the clock. /// /// This clock is not monotonic, therefore calling this function repeatedly @@ -36,11 +47,11 @@ interface wall-clock { /// [POSIX's Seconds Since the Epoch]: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16 /// [Unix Time]: https://en.wikipedia.org/wiki/Unix_time @since(version = 0.3.0-rc-2025-08-15) - now: func() -> datetime; + now: func() -> instant; /// Query the resolution of the clock. /// /// The nanoseconds field of the output is always less than 1000000000. @since(version = 0.3.0-rc-2025-08-15) - get-resolution: func() -> datetime; + get-resolution: func() -> duration; } diff --git a/wit-0.3.0-draft/timezone.wit b/wit-0.3.0-draft/timezone.wit index 2ee16ab..c118223 100644 --- a/wit-0.3.0-draft/timezone.wit +++ b/wit-0.3.0-draft/timezone.wit @@ -3,23 +3,23 @@ package wasi:clocks@0.3.0-rc-2025-08-15; @unstable(feature = clocks-timezone) interface timezone { @unstable(feature = clocks-timezone) - use wall-clock.{datetime}; + use system-clock.{instant}; - /// Return information needed to display the given `datetime`. This includes + /// Return information needed to display the given `instant`. This includes /// the UTC offset, the time zone name, and a flag indicating whether /// daylight saving time is active. /// - /// If the timezone cannot be determined for the given `datetime`, return a + /// If the timezone cannot be determined for the given `instant`, return a /// `timezone-display` for `UTC` with a `utc-offset` of 0 and no daylight /// saving time. @unstable(feature = clocks-timezone) - display: func(when: datetime) -> timezone-display; + display: func(when: instant) -> timezone-display; /// The same as `display`, but only return the UTC offset. @unstable(feature = clocks-timezone) - utc-offset: func(when: datetime) -> s32; + utc-offset: func(when: instant) -> s32; - /// Information useful for displaying the timezone of a specific `datetime`. + /// Information useful for displaying the timezone of a specific `instant`. /// /// This information may vary within a single `timezone` to reflect daylight /// saving time adjustments. diff --git a/wit-0.3.0-draft/world.wit b/wit-0.3.0-draft/world.wit index 94068c7..be2f879 100644 --- a/wit-0.3.0-draft/world.wit +++ b/wit-0.3.0-draft/world.wit @@ -5,7 +5,7 @@ world imports { @since(version = 0.3.0-rc-2025-08-15) import monotonic-clock; @since(version = 0.3.0-rc-2025-08-15) - import wall-clock; + import system-clock; @unstable(feature = clocks-timezone) import timezone; } From 59ac07ecce67a7a3bf416b21a4581b163afa4606 Mon Sep 17 00:00:00 2001 From: Kevin Gibbons Date: Fri, 29 Aug 2025 20:36:33 -0700 Subject: [PATCH 02/12] Apply suggestions from code review Co-authored-by: Philip Chimento --- wit-0.3.0-draft/system-clock.wit | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wit-0.3.0-draft/system-clock.wit b/wit-0.3.0-draft/system-clock.wit index db66ca4..daebc7e 100644 --- a/wit-0.3.0-draft/system-clock.wit +++ b/wit-0.3.0-draft/system-clock.wit @@ -28,10 +28,10 @@ interface system-clock { /// A duration of time, in seconds plus nanoseconds. @since(version = 0.3.0-rc-2025-08-15) - type duration = { + record duration { seconds: u64, nanoseconds: u32, - }; + } /// Read the current value of the clock. /// From b340dbe665821ae6f8977d96d56ef68476ce0a00 Mon Sep 17 00:00:00 2001 From: Kevin Gibbons Date: Fri, 29 Aug 2025 21:03:24 -0700 Subject: [PATCH 03/12] add new types.wit package to hold `duration` --- wit-0.3.0-draft/monotonic-clock.wit | 6 ++---- wit-0.3.0-draft/types.wit | 8 ++++++++ 2 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 wit-0.3.0-draft/types.wit diff --git a/wit-0.3.0-draft/monotonic-clock.wit b/wit-0.3.0-draft/monotonic-clock.wit index 37524f6..bb8e1ef 100644 --- a/wit-0.3.0-draft/monotonic-clock.wit +++ b/wit-0.3.0-draft/monotonic-clock.wit @@ -9,16 +9,14 @@ package wasi:clocks@0.3.0-rc-2025-08-15; /// successive reads of the clock will produce non-decreasing values. @since(version = 0.3.0-rc-2025-08-15) interface monotonic-clock { + use types.{duration}; + /// A mark on a monotonic clock is a number of nanoseconds since an /// unspecified initial value, and can only be compared to instances from /// the same monotonic-clock. @since(version = 0.3.0-rc-2025-08-15) type mark = u64; - /// A duration of time, in nanoseconds. - @since(version = 0.3.0-rc-2025-08-15) - type duration = u64; - /// Read the current value of the clock. /// /// The clock is monotonic, therefore calling this function repeatedly will diff --git a/wit-0.3.0-draft/types.wit b/wit-0.3.0-draft/types.wit new file mode 100644 index 0000000..4736b89 --- /dev/null +++ b/wit-0.3.0-draft/types.wit @@ -0,0 +1,8 @@ +package wasi:clocks@0.3.0-rc-2025-08-15; +/// This interface common types used throughout wasi:clocks. +@since(version = 0.3.0-rc-2025-08-15) +interface types { + /// A duration of time, in nanoseconds. + @since(version = 0.3.0-rc-2025-08-15) + type duration = u64; +} From dd44eb077415a6f022e22112b69b0be81b813766 Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Fri, 29 Aug 2025 17:49:28 -0700 Subject: [PATCH 04/12] Change docs to refer to "currently configured time zone" The "timezone of an instant" is a misnomer because the `instant` type doesn't carry timezone information. The host has a currently configured time zone (or has no such concept, in which case the only sensible thing to do is use UTC). --- wit-0.3.0-draft/timezone.wit | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/wit-0.3.0-draft/timezone.wit b/wit-0.3.0-draft/timezone.wit index c118223..c71ad08 100644 --- a/wit-0.3.0-draft/timezone.wit +++ b/wit-0.3.0-draft/timezone.wit @@ -5,11 +5,11 @@ interface timezone { @unstable(feature = clocks-timezone) use system-clock.{instant}; - /// Return information needed to display the given `instant`. This includes - /// the UTC offset, the time zone name, and a flag indicating whether - /// daylight saving time is active. + /// Return information needed to display the given `instant` in the + /// currently configured time zone. This includes the UTC offset, the time + /// zone name, and a flag indicating whether daylight saving time is active. /// - /// If the timezone cannot be determined for the given `instant`, return a + /// If the currently configured timezone cannot be determined, return a /// `timezone-display` for `UTC` with a `utc-offset` of 0 and no daylight /// saving time. @unstable(feature = clocks-timezone) @@ -19,7 +19,8 @@ interface timezone { @unstable(feature = clocks-timezone) utc-offset: func(when: instant) -> s32; - /// Information useful for displaying the timezone of a specific `instant`. + /// Information useful for displaying a specific `instant` in the currently + /// configured time zone. /// /// This information may vary within a single `timezone` to reflect daylight /// saving time adjustments. From cb6a02ffda8f2bb2c2246e1ae3d44b76a592f2b4 Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Tue, 9 Jul 2024 17:28:48 -0700 Subject: [PATCH 05/12] Remove "in-daylight-saving-time" flag This flag is problematic because when a time zone is "in DST" is not well defined. Most time zones in the world don't use DST at all. Of the ones that do, most go to DST during the summer for half the year, but not all. For example, the function in Moment.js that provides this functionality comes with a giant caveat: https://momentjs.com/docs/#/query/is-daylight-saving-time/ --- wit-0.3.0-draft/timezone.wit | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/wit-0.3.0-draft/timezone.wit b/wit-0.3.0-draft/timezone.wit index c71ad08..50dbebe 100644 --- a/wit-0.3.0-draft/timezone.wit +++ b/wit-0.3.0-draft/timezone.wit @@ -6,12 +6,11 @@ interface timezone { use system-clock.{instant}; /// Return information needed to display the given `instant` in the - /// currently configured time zone. This includes the UTC offset, the time - /// zone name, and a flag indicating whether daylight saving time is active. + /// currently configured time zone. This includes the UTC offset and the + /// time zone name. /// /// If the currently configured timezone cannot be determined, return a - /// `timezone-display` for `UTC` with a `utc-offset` of 0 and no daylight - /// saving time. + /// `timezone-display` for `UTC` with a `utc-offset` of 0. @unstable(feature = clocks-timezone) display: func(when: instant) -> timezone-display; @@ -21,9 +20,6 @@ interface timezone { /// Information useful for displaying a specific `instant` in the currently /// configured time zone. - /// - /// This information may vary within a single `timezone` to reflect daylight - /// saving time adjustments. @unstable(feature = clocks-timezone) record timezone-display { /// The number of seconds difference between UTC time and the local @@ -46,11 +42,5 @@ interface timezone { /// In time zones that do not have an applicable name, a formatted /// representation of the UTC offset may be returned, such as `-04:00`. name: string, - - /// Whether daylight saving time is active. - /// - /// In implementations that do not expose an actual time zone, this - /// should return false. - in-daylight-saving-time: bool, } } From 60f04043e7eb0b5bcf533de49f8a2bb8127000e8 Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Tue, 9 Jul 2024 17:28:51 -0700 Subject: [PATCH 06/12] Rename "timezone-display::name" to "id" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Other possibilities: "tzid", "iana-id", "identifier", "iana-identifier". Returning a user-displayable name as part of timezone-display would require more information: the user's preferred language, and the preferred style for the name: - abbreviated or not - year-round or specific to the Instant E.g., the time zone with the IANA id "America/Los_Angeles" might be displayed as "Pacific Time", "Pacific Standard Time", "Pacific Daylight Time", "PT", "PST", "PDT", "Nordamerikanische Westküstenzeit"... The Rust iana_time_zone crate uses IANA time zone IDs, so if this interface needs to be able to implement iana_time_zone, timezone-display should have an IANA ID and not a user-displayable name. --- README.md | 2 +- wit-0.3.0-draft/timezone.wit | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 2beab9c..7f851ad 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ default-monotonic-clock: monotonic-clock let timezone_display: TimezoneDisplay = timezone::display(instant); - println!("the timezone is {}", timezone_display.name); + println!("the timezone is {}", timezone_display.id); ``` ### Detailed design discussion diff --git a/wit-0.3.0-draft/timezone.wit b/wit-0.3.0-draft/timezone.wit index 50dbebe..7b8de1b 100644 --- a/wit-0.3.0-draft/timezone.wit +++ b/wit-0.3.0-draft/timezone.wit @@ -32,15 +32,18 @@ interface timezone { /// should return 0. utc-offset: s32, - /// The abbreviated name of the timezone to display to a user. The name - /// `UTC` indicates Coordinated Universal Time. Otherwise, this should - /// reference local standards for the name of the time zone. + /// The IANA identifier of the timezone. The id `UTC` indicates + /// Coordinated Universal Time. Otherwise, this should be an identifier + /// from the IANA Time Zone Database. + /// + /// For displaying to a user, the identifier should be converted into a + /// localized name by means of an internationalization API. /// /// In implementations that do not expose an actual time zone, this /// should be the string `UTC`. /// /// In time zones that do not have an applicable name, a formatted /// representation of the UTC offset may be returned, such as `-04:00`. - name: string, + id: string, } } From f8e73b87c84328462fd2eed8d28f24146d709061 Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Tue, 9 Jul 2024 17:28:55 -0700 Subject: [PATCH 07/12] Measure UTC offset in nanoseconds There are time zones that used sub-minute or even sub-second UTC offsets for instants in the past. E.g., when built using Vanguard format, the UTC offset in the TZDB for "Asia/Ho_Chi_Minh" before July 1906 is 7:06:30.133333333. --- wit-0.3.0-draft/timezone.wit | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/wit-0.3.0-draft/timezone.wit b/wit-0.3.0-draft/timezone.wit index 7b8de1b..0c47923 100644 --- a/wit-0.3.0-draft/timezone.wit +++ b/wit-0.3.0-draft/timezone.wit @@ -16,21 +16,21 @@ interface timezone { /// The same as `display`, but only return the UTC offset. @unstable(feature = clocks-timezone) - utc-offset: func(when: instant) -> s32; + utc-offset: func(when: instant) -> s64; /// Information useful for displaying a specific `instant` in the currently /// configured time zone. @unstable(feature = clocks-timezone) record timezone-display { - /// The number of seconds difference between UTC time and the local + /// The number of nanoseconds difference between UTC time and the local /// time of the timezone. /// - /// The returned value will always be less than 86400 which is the - /// number of seconds in a day (24*60*60). + /// The returned value will always be less than 86,400,000,000,000 which + /// is the number of nanoseconds in a day (24*60*60*1e9). /// /// In implementations that do not expose an actual time zone, this /// should return 0. - utc-offset: s32, + utc-offset: s64, /// The IANA identifier of the timezone. The id `UTC` indicates /// Coordinated Universal Time. Otherwise, this should be an identifier From 367ec464b5d7fecacb3d60b9ac09987833d846f9 Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Thu, 11 Jul 2024 11:42:09 -0700 Subject: [PATCH 08/12] Refactor timezone-display into separate methods If the timezone-display ID is an IANA ID, and we are going with the approach of not making the localized ("PST" vs "PDT" vs "PT") name part of this component, then the current time zone doesn't depend on the current time. After removing the isDST flag, timezone-display contains two pieces of data, the ID and the UTC offset. The UTC offset is already available via a function that takes an Instant as input. The ID could just be available via its own function that doesn't take any input. In that case there would be no need for timezone-display. --- README.md | 7 ++--- wit-0.3.0-draft/timezone.wit | 58 ++++++++++++++---------------------- 2 files changed, 25 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 7f851ad..a99080f 100644 --- a/README.md +++ b/README.md @@ -93,10 +93,9 @@ default-monotonic-clock: monotonic-clock ```rust let instant: Instant = system_clock::now(); - - let timezone_display: TimezoneDisplay = timezone::display(instant); - - println!("the timezone is {}", timezone_display.id); + let id = timezone::id(); + let offset_h = timezone::utc_offset(instant) as f64 / 3600e9; + println!("the timezone is {} at UTC{:+}", id, offset_h); ``` ### Detailed design discussion diff --git a/wit-0.3.0-draft/timezone.wit b/wit-0.3.0-draft/timezone.wit index 0c47923..937268a 100644 --- a/wit-0.3.0-draft/timezone.wit +++ b/wit-0.3.0-draft/timezone.wit @@ -5,45 +5,31 @@ interface timezone { @unstable(feature = clocks-timezone) use system-clock.{instant}; - /// Return information needed to display the given `instant` in the - /// currently configured time zone. This includes the UTC offset and the - /// time zone name. + /// Return the IANA identifier of the currently configured timezone. The id + /// `UTC` indicates Coordinated Universal Time. Otherwise, this should be an + /// identifier from the IANA Time Zone Database. /// - /// If the currently configured timezone cannot be determined, return a - /// `timezone-display` for `UTC` with a `utc-offset` of 0. + /// For displaying to a user, the identifier should be converted into a + /// localized name by means of an internationalization API. + /// + /// In implementations that do not expose an actual time zone, this + /// should be the string `UTC`. + /// + /// In time zones that do not have an applicable name, a formatted + /// representation of the UTC offset may be returned, such as `-04:00`. @unstable(feature = clocks-timezone) - display: func(when: instant) -> timezone-display; + id: func() -> string; - /// The same as `display`, but only return the UTC offset. + /// The number of nanoseconds difference between UTC time and the local + /// time of the currently configured timezone at the exact time of + /// `instant`. + /// + /// The magnitude of the returned value will always be less than + /// 86,400,000,000,000 which is the number of nanoseconds in a day + /// (24*60*60*1e9). + /// + /// In implementations that do not expose an actual time zone, this + /// should return 0. @unstable(feature = clocks-timezone) utc-offset: func(when: instant) -> s64; - - /// Information useful for displaying a specific `instant` in the currently - /// configured time zone. - @unstable(feature = clocks-timezone) - record timezone-display { - /// The number of nanoseconds difference between UTC time and the local - /// time of the timezone. - /// - /// The returned value will always be less than 86,400,000,000,000 which - /// is the number of nanoseconds in a day (24*60*60*1e9). - /// - /// In implementations that do not expose an actual time zone, this - /// should return 0. - utc-offset: s64, - - /// The IANA identifier of the timezone. The id `UTC` indicates - /// Coordinated Universal Time. Otherwise, this should be an identifier - /// from the IANA Time Zone Database. - /// - /// For displaying to a user, the identifier should be converted into a - /// localized name by means of an internationalization API. - /// - /// In implementations that do not expose an actual time zone, this - /// should be the string `UTC`. - /// - /// In time zones that do not have an applicable name, a formatted - /// representation of the UTC offset may be returned, such as `-04:00`. - id: string, - } } From 0c3e04253c969e7a9feb32eeaa287bed191676c1 Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Fri, 29 Aug 2025 18:04:40 -0700 Subject: [PATCH 09/12] Move Unix Time docs to instant type Instead of only specifying the epoch of the instant returned from now(), specify the epoch of the instant type. It then follows that now() returns an instant with that epoch. --- wit-0.3.0-draft/system-clock.wit | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/wit-0.3.0-draft/system-clock.wit b/wit-0.3.0-draft/system-clock.wit index daebc7e..339508e 100644 --- a/wit-0.3.0-draft/system-clock.wit +++ b/wit-0.3.0-draft/system-clock.wit @@ -14,12 +14,19 @@ interface system-clock { /// An "instant", or "exact time", is a point in time without regard to any /// time zone: just the time since a particular external reference point, /// often called an "epoch". + /// + /// Here, the epoch is 1970-01-01T00:00:00Z, also known as + /// [POSIX's Seconds Since the Epoch], also known as [Unix Time]. + /// /// Note that even if the seconds field is negative, incrementing /// nanoseconds always represents moving forwards in time. /// For example, `{ -1 seconds, 999999999 nanoseconds }` represents the /// instant one nanosecond before the epoch. /// For more on various different ways to represent time, see /// https://tc39.es/proposal-temporal/docs/timezone.html + /// + /// [POSIX's Seconds Since the Epoch]: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16 + /// [Unix Time]: https://en.wikipedia.org/wiki/Unix_time @since(version = 0.3.0-rc-2025-08-15) record instant { seconds: s64, @@ -38,14 +45,7 @@ interface system-clock { /// This clock is not monotonic, therefore calling this function repeatedly /// will not necessarily produce a sequence of non-decreasing values. /// - /// The returned timestamps represent the number of seconds since - /// 1970-01-01T00:00:00Z, also known as [POSIX's Seconds Since the Epoch], - /// also known as [Unix Time]. - /// /// The nanoseconds field of the output is always less than 1000000000. - /// - /// [POSIX's Seconds Since the Epoch]: https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_16 - /// [Unix Time]: https://en.wikipedia.org/wiki/Unix_time @since(version = 0.3.0-rc-2025-08-15) now: func() -> instant; From 1d63a763505c8f60107203db1f03c712e09db902 Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Mon, 1 Sep 2025 15:30:54 -0700 Subject: [PATCH 10/12] Make time zone methods return optional types We wish to be able to represent "is completely unaware of time zones" or "failure to discover a time zone" in the API, distinct from a host that always uses UTC. --- wit-0.3.0-draft/timezone.wit | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/wit-0.3.0-draft/timezone.wit b/wit-0.3.0-draft/timezone.wit index 937268a..cc98283 100644 --- a/wit-0.3.0-draft/timezone.wit +++ b/wit-0.3.0-draft/timezone.wit @@ -5,31 +5,31 @@ interface timezone { @unstable(feature = clocks-timezone) use system-clock.{instant}; - /// Return the IANA identifier of the currently configured timezone. The id - /// `UTC` indicates Coordinated Universal Time. Otherwise, this should be an - /// identifier from the IANA Time Zone Database. + /// Return the IANA identifier of the currently configured timezone. This + /// should be an identifier from the IANA Time Zone Database. /// /// For displaying to a user, the identifier should be converted into a /// localized name by means of an internationalization API. /// - /// In implementations that do not expose an actual time zone, this - /// should be the string `UTC`. - /// - /// In time zones that do not have an applicable name, a formatted - /// representation of the UTC offset may be returned, such as `-04:00`. + /// If the implementation does not expose an actual timezone, or is unable + /// to provide mappings from times to deltas between the configured timezone + /// and UTC, or determining the current timezone fails, or the timezone does + /// not have an IANA identifier, this returns nothing. @unstable(feature = clocks-timezone) - id: func() -> string; + iana-id: func() -> option; /// The number of nanoseconds difference between UTC time and the local - /// time of the currently configured timezone at the exact time of + /// time of the currently configured timezone, at the exact time of /// `instant`. /// /// The magnitude of the returned value will always be less than /// 86,400,000,000,000 which is the number of nanoseconds in a day /// (24*60*60*1e9). /// - /// In implementations that do not expose an actual time zone, this - /// should return 0. + /// If the implementation does not expose an actual timezone, or is unable + /// to provide mappings from times to deltas between the configured timezone + /// and UTC, or determining the current timezone fails, this returns + /// nothing. @unstable(feature = clocks-timezone) - utc-offset: func(when: instant) -> s64; + utc-offset: func(when: instant) -> option; } From 42bfd8c74647363b0690d55b1ddac1039c07b921 Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Mon, 1 Sep 2025 15:37:38 -0700 Subject: [PATCH 11/12] Add timezone::to-debug-string method --- wit-0.3.0-draft/timezone.wit | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/wit-0.3.0-draft/timezone.wit b/wit-0.3.0-draft/timezone.wit index cc98283..67ab2fe 100644 --- a/wit-0.3.0-draft/timezone.wit +++ b/wit-0.3.0-draft/timezone.wit @@ -32,4 +32,15 @@ interface timezone { /// nothing. @unstable(feature = clocks-timezone) utc-offset: func(when: instant) -> option; + + /// Returns a string that is suitable to assist humans in debugging whether + /// any timezone is available, and if so, which. This may be the same string + /// as `iana-id`, or a formatted representation of the UTC offset such as + /// `-04:00`, or something else. + /// + /// WARNING: The returned string should not be consumed mechanically! It may + /// change across platforms, hosts, or other implementation details. Parsing + /// this string is a major platform-compatibility hazard. + @unstable(feature = clocks-timezone) + to-debug-string: func() -> string; } From e183e898473c5780b8759cd17146563136de77dd Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Mon, 1 Sep 2025 15:48:44 -0700 Subject: [PATCH 12/12] Remove system-clock::duration Use types::duration for the return type of get-resolution instead. It supports durations up to 584 years which is more than sufficient for any clock resolution. (A more capable duration type would be needed if we were doing any arithmetic between instants.) --- wit-0.3.0-draft/system-clock.wit | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/wit-0.3.0-draft/system-clock.wit b/wit-0.3.0-draft/system-clock.wit index 339508e..e402a41 100644 --- a/wit-0.3.0-draft/system-clock.wit +++ b/wit-0.3.0-draft/system-clock.wit @@ -11,6 +11,8 @@ package wasi:clocks@0.3.0-rc-2025-08-15; /// It is intended for reporting the current date and time for humans. @since(version = 0.3.0-rc-2025-08-15) interface system-clock { + use types.{duration}; + /// An "instant", or "exact time", is a point in time without regard to any /// time zone: just the time since a particular external reference point, /// often called an "epoch". @@ -33,13 +35,6 @@ interface system-clock { nanoseconds: u32, } - /// A duration of time, in seconds plus nanoseconds. - @since(version = 0.3.0-rc-2025-08-15) - record duration { - seconds: u64, - nanoseconds: u32, - } - /// Read the current value of the clock. /// /// This clock is not monotonic, therefore calling this function repeatedly @@ -49,9 +44,8 @@ interface system-clock { @since(version = 0.3.0-rc-2025-08-15) now: func() -> instant; - /// Query the resolution of the clock. - /// - /// The nanoseconds field of the output is always less than 1000000000. + /// Query the resolution of the clock. Returns the smallest duration of time + /// that the implementation permits distinguishing. @since(version = 0.3.0-rc-2025-08-15) get-resolution: func() -> duration; }