aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-09-29 23:09:37 -0400
committerBruce Hill <bruce@bruce-hill.com>2024-09-29 23:09:37 -0400
commitd7145198095d9f316ecffc97499ae2791384da20 (patch)
tree71d5ff4742de1230a58f40cc70b74270f2c0aaa2
parentd0c015c74a7b1fe479f3c753edd9d35e6c922e62 (diff)
Fix some timezone issues
-rw-r--r--docs/datetime.md18
-rw-r--r--environment.c4
-rw-r--r--stdlib/datetime.c14
3 files changed, 21 insertions, 15 deletions
diff --git a/docs/datetime.md b/docs/datetime.md
index e62a8a2b..1cbc324e 100644
--- a/docs/datetime.md
+++ b/docs/datetime.md
@@ -16,7 +16,7 @@ preferred representation of the DateTime in the current time zone:
```tomo
>> DateTime.now()
-= Sun Sep 29 18:20:12 2024
+= Sun Sep 29 18:20:12 2024 EDT
```
For various methods, it is assumed by default that users wish to perform
@@ -71,7 +71,7 @@ A new `DateTime` offset by the given amount.
**Example:**
```markdown
>> DateTime(2024, 9, 29, hour=19):after(days=1, minutes=30)
-= Mon Sep 30 19:30:00 2024
+= Mon Sep 30 19:30:00 2024 EDT
```
---
@@ -111,7 +111,7 @@ options, return a text representation of the given date in the given format. If
**Usage:**
```markdown
-datetime:format(format: Text = "%c", local_time : Bool = yes) -> Text
+datetime:format(format: Text = "%c %Z", local_time : Bool = yes) -> Text
```
**Parameters:**
@@ -278,11 +278,11 @@ integer, an error will be raised.
**Example:**
```markdown
>> DateTime.new(2024, 9, 29)
-= Mon Sep 30 00:00:00 2024
+= Mon Sep 30 00:00:00 2024 EDT
# March 1642, 2020:
>> DateTime(2020, 4, 1643)
-= Sat Sep 28 00:00:00 2024
+= Sat Sep 28 00:00:00 2024 EDT
```
---
@@ -308,7 +308,7 @@ Returns a `DateTime` object representing the current date and time.
**Example:**
```markdown
>> DateTime.now()
-= Sun Sep 29 20:22:48 2024
+= Sun Sep 29 20:22:48 2024 EDT
```
---
@@ -321,14 +321,14 @@ or a null value if the value could not be successfully parsed.
**Usage:**
```markdown
-DateTime.parse(text: Text, format: Text = "%c") -> DateTime?
+DateTime.parse(text: Text, format: Text = "%Y-%m-%dT%H:%M:%S. %f%z") -> DateTime?
```
**Parameters:**
- `text`: The text to parse.
- `format`: The date format of the text being parsed (see:
- [strptime](https://linux.die.net/man/3/strptime) for more info on this format) (default: `"%c"`).
+ [strptime](https://linux.die.net/man/3/strptime) for more info on this format) (default: `"%c %Z"`).
**Returns:**
If the text was successfully parsed according to the given format, return a
@@ -337,7 +337,7 @@ If the text was successfully parsed according to the given format, return a
**Example:**
```markdown
>> DateTime.parse("2024-09-29", "%Y-%m-%d")!
-= Sun Sep 29 00:00:00 2024
+= Sun Sep 29 00:00:00 2024 EDT
>> DateTime.parse("???", "%Y-%m-%d")
= !DateTime
diff --git a/environment.c b/environment.c
index b9cbaa47..69710b41 100644
--- a/environment.c
+++ b/environment.c
@@ -267,13 +267,13 @@ env_t *new_compilation_unit(CORD libname)
{"after", "DateTime$after", "func(dt:DateTime,seconds=0.0,minutes=0.0,hours=0.0,days=0,weeks=0,months=0,years=0,local_time=yes)->DateTime"},
{"date", "DateTime$date", "func(dt:DateTime,local_time=yes)->Text"},
- {"format", "DateTime$format", "func(dt:DateTime,format=\"%c\",local_time=yes)->Text"},
+ {"format", "DateTime$format", "func(dt:DateTime,format=\"%Y-%m-%dT%H:%M:%S%z\",local_time=yes)->Text"},
{"from_unix_timestamp", "DateTime$from_unix_timestamp", "func(timestamp:Int64)->DateTime"},
{"get", "DateTime$get", "func(dt:DateTime,year=!&Int,month=!&Int,day=!&Int,hour=!&Int,minute=!&Int,second=!&Int,nanosecond=!&Int,weekday=!&Int, local_time=yes)"},
{"hours_till", "DateTime$hours_till", "func(now:DateTime,then:DateTime)->Num"},
{"minutes_till", "DateTime$minutes_till", "func(now:DateTime,then:DateTime)->Num"},
{"new", "DateTime$new", "func(year:Int,month:Int,day:Int,hour=0,minute=0,second=0.0)->DateTime"},
- {"parse", "DateTime$parse", "func(text:Text, format=\"%c\")->DateTime?"},
+ {"parse", "DateTime$parse", "func(text:Text, format=\"%Y-%m-%dT%H:%M:%S%z\")->DateTime?"},
{"relative", "DateTime$relative", "func(dt:DateTime,relative_to=DateTime.now(),local_time=yes)->Text"},
{"seconds_till", "DateTime$seconds_till", "func(now:DateTime,then:DateTime)->Num"},
{"time", "DateTime$time", "func(dt:DateTime,seconds=no,am_pm=yes,local_time=yes)->Text"},
diff --git a/stdlib/datetime.c b/stdlib/datetime.c
index a3bb42c1..bc1d88e7 100644
--- a/stdlib/datetime.c
+++ b/stdlib/datetime.c
@@ -21,7 +21,7 @@ public Text_t DateTime$as_text(const DateTime_t *dt, bool colorize, const TypeIn
struct tm info;
struct tm *final_info = localtime_r(&dt->tv_sec, &info);
static char buf[256];
- size_t len = strftime(buf, sizeof(buf), "%c", final_info);
+ size_t len = strftime(buf, sizeof(buf), "%c %Z", final_info);
Text_t text = Text$format("%.*s", (int)len, buf);
if (colorize)
text = Text$concat(Text("\x1b[36m"), text, Text("\x1b[m"));
@@ -141,12 +141,18 @@ public Text_t DateTime$time(DateTime_t dt, bool seconds, bool am_pm, bool local_
public OptionalDateTime_t DateTime$parse(Text_t text, Text_t format)
{
struct tm info = {.tm_isdst=-1};
- char *invalid = strptime(Text$as_c_string(text), Text$as_c_string(format), &info);
+ const char *str = Text$as_c_string(text);
+ const char *fmt = Text$as_c_string(format);
+ if (strstr(fmt, "%Z"))
+ fail("The %%Z specifier is not supported for time parsing!");
+
+ char *invalid = strptime(str, fmt, &info);
if (!invalid || invalid[0] != '\0')
return NULL_DATETIME;
+ long offset = info.tm_gmtoff; // Need to cache this because mktime() mutates it to local timezone >:(
time_t t = mktime(&info);
- return (DateTime_t){.tv_sec=t};
+ return (DateTime_t){.tv_sec=t + offset - info.tm_gmtoff};
}
static inline Text_t num_format(long n, const char *unit)
@@ -195,7 +201,7 @@ public Text_t DateTime$relative(DateTime_t dt, DateTime_t relative_to, bool loca
CONSTFUNC public Int64_t DateTime$unix_timestamp(DateTime_t dt)
{
- return (Int64_t)(dt.tv_sec);
+ return (Int64_t)dt.tv_sec;
}
CONSTFUNC public DateTime_t DateTime$from_unix_timestamp(Int64_t timestamp)