diff --git a/sys/man/2/tmdate b/sys/man/2/tmdate index 98c70eb8b..2b59649e6 100644 --- a/sys/man/2/tmdate +++ b/sys/man/2/tmdate @@ -114,6 +114,9 @@ and the unpadded and padded complete value, respectively. .TP .B Z, ZZ, ZZZ The timezone in [+-]HHMM and [+-]HH:MM, and named form, respectively. +If the named timezone matches the name of the local zone, then the +local timezone will be used. +Otherwise, we will attempt to use the named zones listed in RFC5322. .TP .B a, A Lower and uppercase 'am' and 'pm' specifiers, respectively. @@ -267,6 +270,10 @@ print("%τ", &t); /* Mon Nov 3 13:11:11 PST 2019 */ .SH BUGS .PP +Checking the timezone name against the local timezone is a +dirty hack. The same date string may parse differently for +people in different timezones. +.PP There is no way to format specifier for subsecond precision. .PP The timezone information that we ship is out of date. diff --git a/sys/src/libc/port/date.c b/sys/src/libc/port/date.c index 189bcb438..44ae15696 100644 --- a/sys/src/libc/port/date.c +++ b/sys/src/libc/port/date.c @@ -615,7 +615,7 @@ tmparse(Tm *tm, char *fmt, char *str, Tzone *tz, char **ep) int depth, n, w, c0, zs, z0, z1, md, ampm, zoned, sloppy, tzo, ok; vlong abs; char *s, *p, *q; - Tzone *zparsed; + Tzone *zparsed, *local; Tzabbrev *a; Tzoffpair *m; @@ -774,6 +774,32 @@ tmparse(Tm *tm, char *fmt, char *str, Tzone *tz, char **ep) switch(w){ case -1: case 3: + /* + * Ugly Hack: + * Ctime is defined as printing a 3-character timezone + * name. The timezone name is ambiguous. For example, + * EST refers to both Australian and American eastern + * time. On top of that, we don't want to make the + * tzabbrev table exhaustive. So, we put in this hack: + * + * Before we consult the well known table of timezones, + * we check if the local time matches the timezone name. + * + * If you want unambiguous timezone parsing, use numeric + * timezone offsets (Z, ZZ formats). + */ + if((local = tzload("local")) != nil){ + if(cistrncmp(s, local->stname, strlen(local->stname)) == 0){ + s += strlen(local->stname); + zparsed = local; + goto Zoneparsed; + } + if(cistrncmp(s, local->dlname, strlen(local->dlname)) == 0){ + s += strlen(local->dlname); + zparsed = local; + goto Zoneparsed; + } + } for(a = tzabbrev; a->abbr; a++){ n = strlen(a->abbr); if(cistrncmp(s, a->abbr, n) == 0 && !isalpha(s[n]))