From 793717729ae46bd026eff882f7d4da819dec32e5 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Mon, 30 Sep 2024 01:53:39 -0400 Subject: Parameterize with timezones --- docs/datetime.md | 123 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 97 insertions(+), 26 deletions(-) (limited to 'docs') diff --git a/docs/datetime.md b/docs/datetime.md index 7e528def..7fbd8ff7 100644 --- a/docs/datetime.md +++ b/docs/datetime.md @@ -1,13 +1,20 @@ # DateTime Tomo has a builtin datatype for representing a specific single point in time: -`DateTime`. A DateTime object is internally represented using a UNIX epoch in -seconds and a number of nanoseconds to represent sub-second times (in C, the +`DateTime`. A DateTime object is internally represented using a UNIX timestamp +in seconds and a number of nanoseconds to represent sub-second times (in C, the equivalent of `struct timeval`). DateTime values do not represent calendar dates or clock times, they represent an exact moment in time, such as the moment when a file was last modified on the filesystem or the current moment (`DateTime.now()`). +⚠️⚠️⚠️ **WARNING** ⚠️⚠️⚠️ Dates and times are deeply counterintuitive and you should +be extremely cautious when writing code that deals with dates and times. Effort +has been made to ensure that Tomo's `DateTime` code uses standard libraries and +is as correct as possible, but counterintuitive behaviors around time zones, +daylight savings time, leap seconds, and other anomalous time situations can +still cause bugs if you're not extremely careful. + ## Time Zones Because humans are not able to easily understand UNIX timestamps, the default @@ -29,8 +36,12 @@ time. In that example, the initial time would be 3am March 1, 2023 in UTC, so one month later would be 3am April 1, 2023 in UTC, which is which is 11am March 31st in local time. Most users would be unpleasantly surprised to find out that when it's February 28th in local time, one month later is March 28th until 8pm, -at which point it becomes March 31st! For functions where this matters, there -is an extra `local_time` argument that is `yes` by default. +at which point it becomes March 31st! + +For various functions where time zones matter, there is an optional `timezone` +argument that, if set, will override the timezone when performing calculations. +If unspecified, it is assumed that the current local timezone should be used. +Time zones are specified by name, such as `America/New_York` or `EDT`. ## DateTime Methods @@ -46,24 +57,25 @@ example, one year from January 1, 2024 is January 1, 2025, which is 366 days later because 2024 is a leap year. Similarly, adding one month may add anywhere from 28 to 31 days, depending on the starting month. Days and weeks are affected by leap seconds. For this reason, `after()` takes an argument, -`local_time` which is used to determine whether time offsets should be -calculated using the current local time or UTC. +`timezone` which is used to determine in which timezone the offsets should be +calculated. **Usage:** ```markdown -datetime:after(seconds : Num = 0.0, minutes : Num = 0.0, hours : Num = 0.0, days : Int = 0, weeks : Int = 0, months : Int = 0, years : Int = 0, local_time : Bool = yes) -> DateTime +datetime:after(seconds : Num = 0.0, minutes : Num = 0.0, hours : Num = 0.0, days : Int = 0, weeks : Int = 0, months : Int = 0, years : Int = 0, timezone : Text? = !Text) -> DateTime ``` **Parameters:** -- `seconds`: An amount of seconds to offset the datetime (default: 0). -- `minutes`: An amount of minutes to offset the datetime (default: 0). -- `hours`: An amount of hours to offset the datetime (default: 0). -- `days`: An amount of days to offset the datetime (default: 0). -- `weeks`: An amount of weeks to offset the datetime (default: 0). -- `months`: An amount of months to offset the datetime (default: 0). -- `years`: An amount of years to offset the datetime (default: 0). -- `local_time`: Whether to perform the calculations in local time (default: `yes`) or, if not, in UTC time. +- `seconds` (optional): An amount of seconds to offset the datetime (default: 0). +- `minutes` (optional): An amount of minutes to offset the datetime (default: 0). +- `hours` (optional): An amount of hours to offset the datetime (default: 0). +- `days` (optional): An amount of days to offset the datetime (default: 0). +- `weeks` (optional): An amount of weeks to offset the datetime (default: 0). +- `months` (optional): An amount of months to offset the datetime (default: 0). +- `years` (optional): An amount of years to offset the datetime (default: 0). +- `timezone` (optional): If specified, perform perform the calculations in the + given timezone. If unspecified, the current local timezone will be used. **Returns:** A new `DateTime` offset by the given amount. @@ -84,12 +96,12 @@ specifier, which gives the date in `YYYY-MM-DD` form. **Usage:** ```markdown -datetime:date(local_time : Bool = yes) -> Text +datetime:date(timezone : Text? = !Text) -> Text ``` **Parameters:** -- `local_time`: Whether to use local time (default: `yes`) or UTC. +- `timezone` (optional): If specified, give the date in the given timezone (otherwise, use the current local timezone). **Returns:** The date in `YYYY-MM-DD` format. @@ -107,17 +119,18 @@ The date in `YYYY-MM-DD` format. **Description:** Using the C-style [`strftime`](https://linux.die.net/man/3/strftime) format options, return a text representation of the given date in the given format. If -`local_time` is `no`, then use UTC instead of the current locale's timezone. +`timezone` is specified, use that timezone instead of the current local +timezone. **Usage:** ```markdown -datetime:format(format: Text = "%Y-%m-%dT%H:%M:%S%z", local_time : Bool = yes) -> Text +datetime:format(format: Text = "%Y-%m-%dT%H:%M:%S%z", timezone : Text? = !Text) -> Text ``` **Parameters:** - `format`: The `strftime` format to use (default: `"%Y-%m-%dT%H:%M:%S%z"`). -- `local_time`: Whether to use local time (default: `yes`) or UTC. +- `timezone` (optional): If specified, use the given timezone (otherwise, use the current local timezone). **Returns:** Nothing. @@ -165,7 +178,7 @@ provided optional fields. **Usage:** ```markdown -datetime:get(year : &Int? = !&Int, month : &Int? = !&Int, day : &Int? = !&Int, hour : &Int? = !&Int, minute : &Int? = !&Int, second : &Int? = !&Int, nanosecond : &Int? = !&Int, weekday : &Int? = !&Int, local_time=yes) -> Void +datetime:get(year : &Int? = !&Int, month : &Int? = !&Int, day : &Int? = !&Int, hour : &Int? = !&Int, minute : &Int? = !&Int, second : &Int? = !&Int, nanosecond : &Int? = !&Int, weekday : &Int? = !&Int, timezone : Text? = !Text) -> Void ``` **Parameters:** @@ -178,7 +191,7 @@ datetime:get(year : &Int? = !&Int, month : &Int? = !&Int, day : &Int? = !&Int, h - `second`: If non-null, store the second of the minute here (0-59). - `nanosecond`: If non-null, store the nanosecond of the second here (0-1,000,000,000). - `weekday`: If non-null, store the day of the week here (sunday=1, saturday=7) -- `local_time`: Whether to use the local timezone (default: `yes`) or UTC. +- `timezone` (optional): If specified, give values in the given timezone (otherwise, use the current local timezone). **Returns:** Nothing. @@ -194,6 +207,33 @@ dt:get(month=&month) --- +### `get_local_timezone` + +**Description:** +Get the local timezone's name (e.g. `America/New_York` or `UTC`. By default, +this value is read from `/etc/localtime`, however, this can be overridden by +calling `DateTime.set_local_timezone(...)`. + +**Usage:** +```markdown +DateTime.get_local_timezone() -> Text +``` + +**Parameters:** + +None. + +**Returns:** +The name of the current local timezone. + +**Example:** +```markdown +>> DateTime.get_local_timezone() += "America/New_York" +``` + +--- + ### `hours_till` **Description:** @@ -353,13 +393,14 @@ between two `DateTime`s. For example: `5 minutes ago` or `1 day later` **Usage:** ```markdown -datetime:relative(relative_to : DateTime = DateTime.now(), local_time : Bool = yes) -> Text +datetime:relative(relative_to : DateTime = DateTime.now(), timezone : Text? = !Text) -> Text ``` **Parameters:** - `relative_to` (optional): The time against which the relative time is calculated (default: `DateTime.now()`). -- `local_time` (optional): Whether or not to perform calculations in local time (default: `yes`). +- `timezone` (optional): If specified, perform calculations in the given + timezone (otherwise, use the current local timezone). **Returns:** Return a plain English textual representation of the approximate time @@ -406,6 +447,36 @@ the_future := now():after(seconds=1) --- +### `set_local_timezone` + +**Description:** +Set the current local timezone to a given value by name (e.g. +`America/New_York` or `UTC`). The local timezone is used as the default +timezone for performing calculations and constructing `DateTime` objects from +component parts. It's also used as the default way that `DateTime` objects are +converted to text. + +**Usage:** +```markdown +DateTime.set_local_timezone(timezone : Text? = !Text) -> Void +``` + +**Parameters:** + +- `timezone` (optional): if specified, set the current local timezone to the + timezone with the given name. If null, reset the current local timezone to + the system default (the value referenced in `/etc/localtime`). + +**Returns:** +Nothing. + +**Example:** +```markdown +DateTime.set_local_timezone("America/Los_Angeles") +``` + +--- + ### `time` **Description:** @@ -413,14 +484,14 @@ Return a text representation of the time component of the given datetime. **Usage:** ```markdown -datetime:time(seconds : Bool = no, am_pm : Bool = yes, local_time : Bool = yes) -> Text +datetime:time(seconds : Bool = no, am_pm : Bool = yes, timezone : Text? = !Text) -> Text ``` **Parameters:** - `seconds`: Whether to include seconds in the time (default: `no`). - `am_pm`: Whether to use am/pm in the representation or use a 24-hour clock (default: `yes`). -- `local_time`: Whether to use local time (default: `yes`) or UTC. +- `timezone` (optional): If specified, give the time in the given timezone (otherwise, use the current local timezone). **Returns:** A text representation of the time component of the datetime. -- cgit v1.2.3