Time zone bug
Brian Inglis
Brian.Inglis@SystematicSw.ab.ca
Mon May 1 17:25:00 GMT 2017
On 2017-05-01 09:25, cyg Simple wrote:
> On 4/30/2017 7:19 PM, Steven Penny wrote:
>> On Sun, 30 Apr 2017 17:37:00, Ken Brown wrote:
>>> As a result of a failing emacs test, I came across the following:
>>>
>>> $ TZ='NZST-12NZDT,M9.5.0,M4.1.0/3' date -d@0 +'%Y-%m-%d %H:%M:%S %z (%Z)'
>>> 1970-01-01 12:00:00 +1200 (NZST)
>>>
>>> The same command on Linux yields "1970-01-01 13:00:00 +1300 (NZDT)",
>>> which is
>>> correct according to Paul Eggert
>>> (https://lists.gnu.org/archive/html/emacs-devel/2017-04/msg00881.html).
This may be a problem in:
winsup/cygwin/localtime.cc
not properly handling POSIX time zone specs in the S hemisphere, with DST
which starts in autumn/fall and ends in spring, at the start of the time_t
epoch, where the first DST transition happens with negative time_t.
Neither localtime nor mktime on Cygwin properly handle these rules where
both localtime and mktime on Linux do - STC and sdiff attached.
On Linux, even if you comment out the localtime call, mktime sets the
offset correctly; on Cygwin even using localtime and mktime fails to set
the offset at 1970-01-01 correctly.
Cygwin awk strftime also shows the same issue where Linux is also correct.
>> I concur, here is non-esoteric example Linux:
>> $ TZ=Pacific/Auckland date +%Z
>> NZST
>> $ TZ=NZST date +%Z
>> NZST
>> $ TZ=NZDT date +%Z
>> NZDT
>> Cygwin:
>> $ TZ=Pacific/Auckland date +%Z
>> NZST
>> $ TZ=NZST date +%Z
>> GMT
>> $ TZ=NZDT date +%Z
>> GMT
This is just a slight difference in handling POSIX time zone specs
with no explicit offset specified - the basic format is std offset.
If you provide only a std abbr with no offset, Cygwin defaults to
GMT, where Linux uses the abbr and sets the offset to zero. Both
behave identically if you specify a +-offset:
$ TZ=XXX date +"%F %a %R%z(%Z)"; TZ=XXX0 date +"%F %a %R%z(%Z)"
2017-05-01 Mon 17:13+0000(GMT)
2017-05-01 Mon 17:13+0000(XXX)
$ ssh ... 'TZ=XXX date +"%F %a %R%z(%Z)"; TZ=XXX0 date +"%F %a %R%z(%Z)"'
2017-05-01 Mon 17:13+0000(XXX)
2017-05-01 Mon 17:13+0000(XXX)
depends whether you prefer to see the same answer or the smart answer ;^>
--
Take care. Thanks, Brian Inglis, Calgary, Alberta, Canada
-------------- next part --------------
NZST-12NZDT,M9.5.0,M4.1.0/3 NZST-12NZDT,M9.5.0,M4.1.0/3
1970-01-01 001 4 00:00+0000s(GMT) gm 1970-01-01 001 4 00:00+0000s(GMT) gm
1970-01-01 001 4 13:00+1300d(NZDT) local | 1970-01-01 001 4 12:00+1200s(NZST) local
1970-01-01 001 4 13:00+1300d(NZDT) mk | 1970-01-01 001 4 12:00+1200s(NZST) mk
1970-01-01 001 Thu 13:00+1300 (NZDT) | 1970-01-01 001 Thu 12:00+1200 (NZST)
1970-04-04 094 6 13:00+0000s(GMT) gm 1970-04-04 094 6 13:00+0000s(GMT) gm
1970-04-05 095 0 02:00+1300d(NZDT) local | 1970-04-05 095 0 01:00+1200s(NZST) local
1970-04-05 095 0 02:00+1300d(NZDT) mk | 1970-04-05 095 0 01:00+1200s(NZST) mk
1970-04-05 095 Sun 02:00+1300 (NZDT) | 1970-04-05 095 Sun 01:00+1200 (NZST)
1970-04-04 094 6 14:00+0000s(GMT) gm 1970-04-04 094 6 14:00+0000s(GMT) gm
1970-04-05 095 0 02:00+1200s(NZST) local 1970-04-05 095 0 02:00+1200s(NZST) local
1970-04-05 095 0 02:00+1200s(NZST) mk 1970-04-05 095 0 02:00+1200s(NZST) mk
1970-04-05 095 Sun 02:00+1200 (NZST) 1970-04-05 095 Sun 02:00+1200 (NZST)
1970-09-26 269 6 13:00+0000s(GMT) gm 1970-09-26 269 6 13:00+0000s(GMT) gm
1970-09-27 270 0 01:00+1200s(NZST) local 1970-09-27 270 0 01:00+1200s(NZST) local
1970-09-27 270 0 01:00+1200s(NZST) mk 1970-09-27 270 0 01:00+1200s(NZST) mk
1970-09-27 270 Sun 01:00+1200 (NZST) 1970-09-27 270 Sun 01:00+1200 (NZST)
1970-09-26 269 6 14:00+0000s(GMT) gm 1970-09-26 269 6 14:00+0000s(GMT) gm
1970-09-27 270 0 03:00+1300d(NZDT) local 1970-09-27 270 0 03:00+1300d(NZDT) local
1970-09-27 270 0 03:00+1300d(NZDT) mk 1970-09-27 270 0 03:00+1300d(NZDT) mk
1970-09-27 270 Sun 03:00+1300 (NZDT) 1970-09-27 270 Sun 03:00+1300 (NZDT)
1971-01-01 001 5 00:00+0000s(GMT) gm 1971-01-01 001 5 00:00+0000s(GMT) gm
1971-01-01 001 5 13:00+1300d(NZDT) local 1971-01-01 001 5 13:00+1300d(NZDT) local
1971-01-01 001 5 13:00+1300d(NZDT) mk 1971-01-01 001 5 13:00+1300d(NZDT) mk
1971-01-01 001 Fri 13:00+1300 (NZDT) 1971-01-01 001 Fri 13:00+1300 (NZDT)
1971-04-03 093 6 13:00+0000s(GMT) gm 1971-04-03 093 6 13:00+0000s(GMT) gm
1971-04-04 094 0 02:00+1300d(NZDT) local 1971-04-04 094 0 02:00+1300d(NZDT) local
1971-04-04 094 0 02:00+1300d(NZDT) mk 1971-04-04 094 0 02:00+1300d(NZDT) mk
1971-04-04 094 Sun 02:00+1300 (NZDT) 1971-04-04 094 Sun 02:00+1300 (NZDT)
1971-04-03 093 6 14:00+0000s(GMT) gm 1971-04-03 093 6 14:00+0000s(GMT) gm
1971-04-04 094 0 02:00+1200s(NZST) local 1971-04-04 094 0 02:00+1200s(NZST) local
1971-04-04 094 0 02:00+1200s(NZST) mk 1971-04-04 094 0 02:00+1200s(NZST) mk
1971-04-04 094 Sun 02:00+1200 (NZST) 1971-04-04 094 Sun 02:00+1200 (NZST)
0 0
-------------- next part --------------
/* newlib/libc/time/strftime.c %z format STC */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define TZ "TZ=NZST-12NZDT,M9.5.0,M4.1.0/3"
#define DFMT "%04d-%02d-%02d %03d %-3d %02d:%02d%+03ld00%s(%s)\t%s\n" //:%02d
#define TFMT "%F %j %a %R%z (%Z)"
#define EPOCH 1970
#define YADD 1900
#define MADD 1
#define DADD 1
#define YR_MTH 12
#define MTH_DAY 30
#define DAY_HR 24
#define HR_MIN 60
#define MIN_S 60
#define HR_S (HR_MIN*MIN_S)
/* extra is total days over 30 in preceding months - net total 5/year */
#define S(extra,yr,mth,day,hr) \
((((((yr) - EPOCH)*YR_MTH + ((mth) - 1))*MTH_DAY + (extra) + (day) - 1)\
*DAY_HR + (hr))*HR_S)
int
dump( struct tm* tp, char *label) {
return printf( DFMT, tp->tm_year + YADD, tp->tm_mon + MADD, tp->tm_mday,
tp->tm_yday + DADD, tp->tm_wday,
tp->tm_hour, tp->tm_min, // tp->tm_sec,
# ifdef __TM_GMTOFF
tp->__TM_GMTOFF/HR_S,
# elif __USE_BSD
tp->tm_gmtoff/HR_S,
# else
tp->__tm_gmtoff/HR_S,
# endif
tp->tm_isdst < 0 ? "?" : tp->tm_isdst ? "d" : "s",
# ifdef __TM_ZONE
tp->__TM_ZONE,
# elif __USE_BSD
tp->tm_zone,
# else
tp->__tm_zone,
# endif
label
);
}
int
test( time_t tt ) {
char ss[BUFSIZ] = "";
struct tm * tp;
size_t st;
int rc;
if (EOF == (rc = puts( "" ))) return 5;
if (!(tp = gmtime( &tt ))) return 1;
if ((rc = dump( tp, "gm" )) <= 0) return -rc;
if (!(tp = localtime( &tt ))) return 2;
if ((rc = dump( tp, "local" )) <= 0) return -rc;
if (-1 == (tt = mktime( tp ))) return 3;
if ((rc = dump( tp, "mk" )) <= 0) return -rc;
if ((st = strftime( ss, sizeof ss, TFMT, tp)) <= 0) return 4;
if (EOF == (rc = puts( ss ))) return 5;
return 0;
}
int
main( void ) {
int rc;
if ((rc = putenv( TZ ))) return rc;
if (EOF == (rc = puts( getenv( "TZ" )))) return 6;
/* extra year m day hour */
if ((rc = test( S( 0, 1970, 1, 1, 0)))) return rc;
if ((rc = test( S( 0, 1970, 4, 4, 13)))) return rc;
if ((rc = test( S( 0, 1970, 4, 4, 14)))) return rc;
if ((rc = test( S( 3, 1970, 9, 26, 13)))) return rc;
if ((rc = test( S( 3, 1970, 9, 26, 14)))) return rc;
if ((rc = test( S( 5, 1971, 1, 1, 0)))) return rc;
if ((rc = test( S( 5, 1971, 4, 3, 13)))) return rc;
if ((rc = test( S( 5, 1971, 4, 3, 14)))) return rc;
return rc;
}
-------------- next part --------------
--
Problem reports: http://cygwin.com/problems.html
FAQ: http://cygwin.com/faq/
Documentation: http://cygwin.com/docs.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
More information about the Cygwin
mailing list