proposed change to 'zic' to support "outlandish" offsets
Currently zic allows only GMT offsets in the range -24:00 to 24:00. And yet the recent query about Mt. Athos led me to think that in some cases it can be useful to allow GMT offsets outside the range, to approximate the Julian calendar. And at any rate zic should be able to generate whatever offset can be stored in the standard tz file format, if only for testing purposes. So here is a proposed patch to the zic code and documentation to support this. I'll follow up with a message illustrating how this might be used to support Julian dates and civil times on Mt. Athos. =================================================================== RCS file: RCS/zic.8,v retrieving revision 2007.4 retrieving revision 2007.4.0.1 diff -pu -r2007.4 -r2007.4.0.1 --- zic.8 2007/03/20 12:48:10 2007.4 +++ zic.8 2007/04/23 22:27:49 2007.4.0.1 @@ -239,14 +239,35 @@ wall clock time is assumed. .B SAVE Gives the amount of time to be added to local standard time when the rule is in effect. -This field has the same format as the +This field's format is similar to that of the .B AT -field -(although, of course, the -.B w +field, except that the +.BR s , +.BR u , and -.B s -suffixes are not used). +.B w +suffixes are not used. +.IP +Also, for completeness, the +.B SAVE +field can be preceded by an +optional day count of the form +.IB N d +where +.I N +is a nonnegative integer number of days. +Both the day count and the time can be preceded by an optional sign; +if the second sign is omitted it is assumed to be the same as the first. +A day consists of 24 hours. +For example, +.B \-2d+23:45 +means minus 2 days, plus 23 hours and 45 minutes, and is equivalent +to +.B \-1d0:15 +which means minus 1 day, minus another 15 minutes. +The day count is not needed for any real-world example using the +Gregorian calendar, but it may be useful for testing, or for +half-baked approximations to other calendars. .TP .B LETTER/S Gives the @@ -287,15 +308,16 @@ zone. .B GMTOFF The amount of time to add to UTC to get standard time in this zone. This field has the same format as the -.B AT -and .B SAVE fields of rule lines; begin the field with a minus sign if time must be subtracted from UTC. .TP .B RULES/SAVE The name of the rule(s) that apply in the time zone or, -alternately, an amount of time to add to local standard time. +alternately, an amount of time to add to local standard time, +using the same format as the +.B SAVE +fields of rule lines. If this field is .B \- then standard time always applies in the time zone. =================================================================== RCS file: RCS/zic.c,v retrieving revision 2007.5 retrieving revision 2007.5.0.1 diff -pu -r2007.5 -r2007.5.0.1 --- zic.c 2007/03/26 17:53:22 2007.5 +++ zic.c 2007/04/23 22:27:49 2007.5.0.1 @@ -914,8 +914,12 @@ _("%s: panic: Invalid l_value %d\n"), /* ** Convert a string of one of the forms -** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss +** h hh:mm hh:mm:ss ** into a number of seconds. +** The string can be preceded by an optional Nd, where N is a day count. +** Both the day count and the time can be preceded by an optional sign. +** For example, "-1d+23:45" means minus 1 day, plus 23 hours and 45 minutes. +** If the second sign is omitted it is assumed to be the same as the first. ** A null string maps to zero. ** Call error with errstring and return zero on errors. */ @@ -927,15 +931,27 @@ const char * const errstring; const int signable; { int hh, mm, ss, sign; + int abshourmax, gotday; + char * endptr; + long dd, dd1; if (string == NULL || *string == '\0') return 0; - if (!signable) - sign = 1; - else if (*string == '-') { - sign = -1; - ++string; - } else sign = 1; + sign = 1; + dd = 0; + gotday = FALSE; + if (signable) { + dd1 = strtol(string, &endptr, 10); + if (string != endptr && *endptr == 'd') { + if (*string == '-') + sign = -1; + string = endptr + 1; + dd = dd1; + gotday = TRUE; + if (noise) + warning(_("day offsets not handled by pre-2007 versions of zic")); + } + } if (sscanf(string, scheck(string, "%d"), &hh) == 1) mm = ss = 0; else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2) @@ -945,18 +961,28 @@ const int signable; error(errstring); return 0; } - if ((hh < 0 || hh >= HOURSPERDAY || + if (! (LONG_MIN / SECSPERDAY <= dd && dd <= LONG_MAX / SECSPERDAY)) { + error(_("time overflow")); + return 0; + } + abshourmax = HOURSPERDAY - (gotday || mm || ss); + if (hh < -abshourmax || hh > abshourmax || mm < 0 || mm >= MINSPERHOUR || - ss < 0 || ss > SECSPERMIN) && - !(hh == HOURSPERDAY && mm == 0 && ss == 0)) { + ss < 0 || ss > SECSPERMIN) { error(errstring); return 0; } + if (signable) + switch (*string) { + case '-': sign = -1; hh = -hh; break; + case '+': sign = 1; break; + } if (noise && hh == HOURSPERDAY) warning(_("24:00 not handled by pre-1998 versions of zic")); - return eitol(sign) * - (eitol(hh * MINSPERHOUR + mm) * - eitol(SECSPERMIN) + eitol(ss)); + return oadd(eitol(dd) * SECSPERDAY, + eitol(sign) * + (eitol(hh * MINSPERHOUR + mm) * + eitol(SECSPERMIN) + eitol(ss))); } static void
I don't know about Mt. Athos in particular; the general case of trying to support Julian dates is complicated by needing to change the day-of-month associated with a time_t value without changing the day-of-week associated with the value. The advent of the 64-bit time_t extends the range of time_t values to include historical periods when the Julian calendar was in effect. It may or may not be worthwhile to try to change the handling of Julian-era time_t values; doing so would seem to require changes to both zic and to localtime. --ado -----Original Message----- From: Paul Eggert [mailto:eggert@cs.ucla.edu] Sent: Monday, April 23, 2007 6:37 PM To: tz@lecserver.nci.nih.gov Cc: mgpeter@pcc-services.com; evdokimos@gmail.com Subject: proposed change to 'zic' to support "outlandish" offsets Currently zic allows only GMT offsets in the range -24:00 to 24:00. And yet the recent query about Mt. Athos led me to think that in some cases it can be useful to allow GMT offsets outside the range, to approximate the Julian calendar. And at any rate zic should be able to generate whatever offset can be stored in the standard tz file format, if only for testing purposes.
Hello, I've been following this discussion with interest, and we have discussed it a bit on the ICU mailing list (which is an application library which does time zone and calendar calculations, among other things). What would be ideal is not to change the system clock to be 'back', but to have the default calendar used by all formatters/ parsers to be a Julian one. ( i.e. as opposed to Gregorian, Japanese, etc. ) . One major benefit of this is that otherwise communication in and out (such as email dates..) will be all wrong. Time zone calculations could be simply done according to the Gregorian calendar ( to not affect either ICU or TZ infrastructure ) with the gregorian dates for changeover, whether the intended changeovers are in J or G time. (similar to how Israel time is handled, for example.) In other words, Athos time's zone rules could be in the TZ database according to the Gregorian dates of DST changes. Or would it follow Greece's DST rules? I think that having an outlandish offset would complicate things more than simply recalculating day of week, day of month, etc. based on a different calendar system, as if it were the Hebrew or Islamic or Hindi calendar. Regards, Steven http://icu-project.org On 01 Mej 2007, at 06:37, Olson, Arthur David ((NIH/NCI)) [E] wrote:
I don't know about Mt. Athos in particular; the general case of trying to support Julian dates is complicated by needing to change the day-of-month associated with a time_t value without changing the day-of-week associated with the value.
The advent of the 64-bit time_t extends the range of time_t values to include historical periods when the Julian calendar was in effect. It may or may not be worthwhile to try to change the handling of Julian-era time_t values; doing so would seem to require changes to both zic and to localtime.
--ado
-----Original Message----- From: Paul Eggert [mailto:eggert@cs.ucla.edu] Sent: Monday, April 23, 2007 6:37 PM To: tz@lecserver.nci.nih.gov Cc: mgpeter@pcc-services.com; evdokimos@gmail.com Subject: proposed change to 'zic' to support "outlandish" offsets
Currently zic allows only GMT offsets in the range -24:00 to 24:00. And yet the recent query about Mt. Athos led me to think that in some cases it can be useful to allow GMT offsets outside the range, to approximate the Julian calendar. And at any rate zic should be able to generate whatever offset can be stored in the standard tz file format, if only for testing purposes.
"Olson, Arthur David \(NIH/NCI\) [E]" <olsona@dc37a.nci.nih.gov> writes:
I don't know about Mt. Athos in particular; the general case of trying to support Julian dates is complicated by needing to change the day-of-month associated with a time_t value without changing the day-of-week associated with the value.
Yes, absolutely, and the change I proposed does not really support the Julian calendar; it's just a hack. A similar hack already "works" on some systems, e.g., on Solaris 8: $ date -u +'%Y-%m-%d %H:%M UTC'; TZ=Athos-310 date +'%Y-%m-%d %H:%M Athos' 2007-05-01 23:46 UTC 2007-05-14 21:46 Athos so the question is whether the tz code should support similar hacks. (Note that the day-of-week will be wrong in the above example.)
The advent of the 64-bit time_t extends the range of time_t values to include historical periods when the Julian calendar was in effect. It may or may not be worthwhile to try to change the handling of Julian-era time_t values; doing so would seem to require changes to both zic and to localtime.
Yes, and I was reluctant to futz with localtime, to be honest, since this would require a change to the tz compiled format. I think the primary justification for the proposed change is to generate "outlandish" compiled tz files, for use in testing. If it's not the intent to support outlandish values in compiled format, that fact should probably be documented, and files containing such values should be rejected by localtime.
One possibility is to eliminate checks on hours greater than 24 in zic.c (with warnings thrown in when they occur). This minimizes changes that folks writing alternate parsers would need to make; if we're really lucky, those folks aren't checking the range of hours now and so won't need to make any changes. Full-blown Julian work in the future would require more substantial changes. --ado ------- zic.c ------- *** /tmp/geta18403 Thu May 3 10:59:07 2007 --- /tmp/getb18403 Thu May 3 10:59:07 2007 *************** *** 3,9 **** ** 2006-07-17 by Arthur David Olson. */ ! static char elsieid[] = "@(#)zic.c 8.12"; #include "private.h" #include "locale.h" --- 3,9 ---- ** 2006-07-17 by Arthur David Olson. */ ! static char elsieid[] = "@(#)zic.c 8.13"; #include "private.h" #include "locale.h" *************** *** 945,959 **** error(errstring); return 0; } ! if ((hh < 0 || hh >= HOURSPERDAY || mm < 0 || mm >= MINSPERHOUR || ! ss < 0 || ss > SECSPERMIN) && ! !(hh == HOURSPERDAY && mm == 0 && ss == 0)) { error(errstring); return 0; } ! if (noise && hh == HOURSPERDAY) warning(_("24:00 not handled by pre-1998 versions of zic")); return eitol(sign) * (eitol(hh * MINSPERHOUR + mm) * eitol(SECSPERMIN) + eitol(ss)); --- 945,961 ---- error(errstring); return 0; } ! if (hh < 0 || mm < 0 || mm >= MINSPERHOUR || ! ss < 0 || ss > SECSPERMIN) { error(errstring); return 0; } ! if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0) warning(_("24:00 not handled by pre-1998 versions of zic")); + if (noise && (hh > HOURSPERDAY || + (hh == HOURSPERDAY && (mm != 0 || ss != 0)))) + warning(_("values over 24 hours not handled by pre-2007 versions of zic")); return eitol(sign) * (eitol(hh * MINSPERHOUR + mm) * eitol(SECSPERMIN) + eitol(ss));
"Olson, Arthur David \(NIH/NCI\) [E]" <olsona@dc37a.nci.nih.gov> writes:
One possibility is to eliminate checks on hours greater than 24 in zic.c (with warnings thrown in when they occur). This minimizes changes that folks writing alternate parsers would need to make; if we're really lucky, those folks aren't checking the range of hours now and so won't need to make any changes.
Yes, thanks, that should work. I read through that change and found some portability issues: * The compiled file can represent UTC offsets from -2**31 to 2**31-1 seconds, which is -596523:14:08 to 596523:14:07 in hh:mm:ss notation, but the 596523 exceeds the integer limit on a host with 16-bit int. * zic should guard against overflow when multiplying the hour count by 60*60, and also when adding (mm*60+ss) to (hh*60*60). * On hosts with 64-bit 'long', zic silently truncates UTC offsets that don't fit into 32 bits, when generating the output file. Here is a proposed patch. --- zic.c 2007/05/03 17:40:41 2007.5.1.1 +++ zic.c 2007/05/03 22:31:40 2007.5.0.3 @@ -926,7 +926,8 @@ const char * string; const char * const errstring; const int signable; { - int hh, mm, ss, sign; + long hh; + int mm, ss, sign; if (string == NULL || *string == '\0') return 0; @@ -936,11 +937,11 @@ const int signable; sign = -1; ++string; } else sign = 1; - if (sscanf(string, scheck(string, "%d"), &hh) == 1) + if (sscanf(string, scheck(string, "%ld"), &hh) == 1) mm = ss = 0; - else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2) + else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2) ss = 0; - else if (sscanf(string, scheck(string, "%d:%d:%d"), + else if (sscanf(string, scheck(string, "%ld:%d:%d"), &hh, &mm, &ss) != 3) { error(errstring); return 0; @@ -951,14 +952,17 @@ const int signable; error(errstring); return 0; } + if (LONG_MAX / SECSPERHOUR < hh) { + error(_("time overflow")); + return 0; + } if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0) warning(_("24:00 not handled by pre-1998 versions of zic")); if (noise && (hh > HOURSPERDAY || (hh == HOURSPERDAY && (mm != 0 || ss != 0)))) warning(_("values over 24 hours not handled by pre-2007 versions of zic")); - return eitol(sign) * - (eitol(hh * MINSPERHOUR + mm) * - eitol(SECSPERMIN) + eitol(ss)); + return oadd(eitol(sign) * hh * eitol(SECSPERHOUR), + eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss))); } static void @@ -2273,6 +2277,10 @@ const int ttisgmt; error(_("too many local time types")); exit(EXIT_FAILURE); } + if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) { + error(_("UTC offset out of range")); + exit(EXIT_FAILURE); + } gmtoffs[i] = gmtoff; isdsts[i] = isdst; ttisstds[i] = ttisstd;
Does this DB exists as XML? Can is exist as XML? Sic vis pacem para bellum. Bill Bonnett "The things that will destroy America are prosperity-at-any-price, peace-at-any-price, safety first instead of duty, the love of soft living, and the get-rich-quick theory of life." -- President Theodore Roosevelt Because of spam, this email address is non-existent. Please use the email you contacted me with to continue communication. -----Original Message----- From: Paul Eggert [mailto:eggert@CS.UCLA.EDU] Sent: Friday, May 04, 2007 1:34 AM To: tz@lecserver.nci.nih.gov Subject: Re: proposed change to 'zic' to support "outlandish" offsets "Olson, Arthur David \(NIH/NCI\) [E]" <olsona@dc37a.nci.nih.gov> writes:
One possibility is to eliminate checks on hours greater than 24 in zic.c (with warnings thrown in when they occur). This minimizes changes that folks writing alternate parsers would need to make; if we're really lucky, those folks aren't checking the range of hours now and so won't need to make any changes.
Yes, thanks, that should work. I read through that change and found some portability issues: * The compiled file can represent UTC offsets from -2**31 to 2**31-1 seconds, which is -596523:14:08 to 596523:14:07 in hh:mm:ss notation, but the 596523 exceeds the integer limit on a host with 16-bit int. * zic should guard against overflow when multiplying the hour count by 60*60, and also when adding (mm*60+ss) to (hh*60*60). * On hosts with 64-bit 'long', zic silently truncates UTC offsets that don't fit into 32 bits, when generating the output file. Here is a proposed patch. --- zic.c 2007/05/03 17:40:41 2007.5.1.1 +++ zic.c 2007/05/03 22:31:40 2007.5.0.3 @@ -926,7 +926,8 @@ const char * string; const char * const errstring; const int signable; { - int hh, mm, ss, sign; + long hh; + int mm, ss, sign; if (string == NULL || *string == '\0') return 0; @@ -936,11 +937,11 @@ const int signable; sign = -1; ++string; } else sign = 1; - if (sscanf(string, scheck(string, "%d"), &hh) == 1) + if (sscanf(string, scheck(string, "%ld"), &hh) == 1) mm = ss = 0; - else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2) + else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2) ss = 0; - else if (sscanf(string, scheck(string, "%d:%d:%d"), + else if (sscanf(string, scheck(string, "%ld:%d:%d"), &hh, &mm, &ss) != 3) { error(errstring); return 0; @@ -951,14 +952,17 @@ const int signable; error(errstring); return 0; } + if (LONG_MAX / SECSPERHOUR < hh) { + error(_("time overflow")); + return 0; + } if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0) warning(_("24:00 not handled by pre-1998 versions of zic")); if (noise && (hh > HOURSPERDAY || (hh == HOURSPERDAY && (mm != 0 || ss != 0)))) warning(_("values over 24 hours not handled by pre-2007 versions of zic")); - return eitol(sign) * - (eitol(hh * MINSPERHOUR + mm) * - eitol(SECSPERMIN) + eitol(ss)); + return oadd(eitol(sign) * hh * eitol(SECSPERHOUR), + eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss))); } static void @@ -2273,6 +2277,10 @@ const int ttisgmt; error(_("too many local time types")); exit(EXIT_FAILURE); } + if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) { + error(_("UTC offset out of range")); + exit(EXIT_FAILURE); + } gmtoffs[i] = gmtoff; isdsts[i] = isdst; ttisstds[i] = ttisstd;
I created an XML version here: http://www.salvographics.com/TzDatabase.aspx The intent was to create a windows server version because its support for timezones and DST is inadequate. However, I never followed through. The parser/XML converter is written in C# -- I'll send it to anyone who is interested. -----Original Message----- From: TZ [mailto:tz@abdicate.net] Sent: Friday, May 04, 2007 4:29 AM To: tz@lecserver.nci.nih.gov Subject: RE: proposed change to 'zic' to support "outlandish" offsets Does this DB exists as XML? Can is exist as XML? Sic vis pacem para bellum. Bill Bonnett "The things that will destroy America are prosperity-at-any-price, peace-at-any-price, safety first instead of duty, the love of soft living, and the get-rich-quick theory of life." -- President Theodore Roosevelt
At 07:12 AM 5/4/2007 -0400, you wrote:
I created an XML version here:
http://www.salvographics.com/TzDatabase.aspx
The intent was to create a windows server version because its support for timezones and DST is inadequate. However, I never followed through.
The parser/XML converter is written in C# -- I'll send it to anyone who is interested.
Charles Salvo, That is very interesting. Please reply with a copy of your parser. Thanks a lot. Regards, ------------------------------------- John Halloran john@halloran.com http://www.halloran.com/ Halloran Software P. O. Box 75713 Los Angeles, CA 90075 U.S.A. 818/901-1221
Does this TimeZone data have any GIS / geographic correlation? Thank you! Christina Lawrence
participants (7)
-
Charles Salvo -
Christina Lawrence -
John Halloran -
Olson, Arthur David (NIH/NCI) [E] -
Paul Eggert -
Steven R. Loomis -
TZ