Hi Paul, > On 05/01/2017 09:40 AM, Bruno Haible wrote: > > + /* If the environment variable TZ has been set by Cygwin, neutralize it. > > + The Microsoft CRT interprets TZ differently than Cygwin and produces > > + incorrect results if TZ has the syntax used by Cygwin. */ > > + const char *tz = getenv ("TZ"); > > + if (tz != NULL && strchr (tz, '/') != NULL) > > + _putenv ("TZ="); > > I'm puzzled why setting TZ="" is desirable here. Does this cause the > Microsoft CRT to use UTC?
No. An empty or absent TZ environment variable, for the Microsoft CRT, means the time zone that the user has set in the Windows Control Panel. Only for Cygwin, an empty or absent TZ environment variable means GMT. I find this a poor choice, because - When the user changes the time zone through the Windows Control Panel (or even automatically, when he's travelling), he has to either terminate the Cygwin terminal window or change the TZ variable in there. - Cygwin programs run in Windows; it's not adequate to have a default the choices made in the Control Panel. (Gnulib's 'localename' module, for instance, makes sure to use the settings from the Control Panel on Windows or Mac OS.) > Is TZ="" a good thing because switching to UTC > is better than the undefined behavior one would get with TZ set to a > value not documented by Microsoft? No, setting TZ="" is a good thing because some developers use Cygwin as a development environment for native Windows programs, and it is expected that such a program produces identical results when run from a Cygwin terminal window than from a cmd.exe window. > Also, the test "strchr (tz, '/') != NULL" allows many Cygwin-compatible > TZ settings that Microsoft does not document support for, e.g., > TZ="PST8PDT,M3.2.0,M11.1.0" for Los Angeles. Admittedly most Cygwin > users in L.A. probably just use TZ="America/Los_Angeles" so fixing this > is not that important. Still, if the intent is to limit the TZ value to > what Microsoft documents, I suppose you could nuke the TZ value if it > does not match the C-locale ERE > "^[A-Za-z]{3}[-+]?[01]?[0-9](:[0-5][0-9](:[0-5][0-9])?)?([A-Za-z]{3})?$", > or maybe put in a FIXME comment to that effect. The full set of TZ values understood by MSVC CRT is not documented. (Maybe there are more valid strings than those that fit your regexp?) The full set of TZ values understood by Cygwin is not documented either. But what matters most to me are those that Cygwin sets without the user being aware of. (*) So the borderline between both sets is guesswork. I guessed that "contains a slash" vs. "does not contain a slash" is a reasonable distinction. Plus, it's easy to implement in less than 1 line of code. (*) This happens by /etc/profile.d/tzset.sh, which uses the 'tzset' program to determine the value. The 'tzset' program is implemented in Cygwin's winsup/utils/tzset.c winsup/utils/tzmap.h and all the resulting values contain a slash, except for CST6CDT EST5EDT MST7MDT PST8PDT which follow the syntax understood by Microsoft's CRT [1]. [1] https://msdn.microsoft.com/en-us/library/90s5c885.aspx How about this revised comment? diff --git a/lib/tzset.c b/lib/tzset.c index ce854b9..90f633a 100644 --- a/lib/tzset.c +++ b/lib/tzset.c @@ -41,9 +41,18 @@ tzset (void) #endif #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ - /* If the environment variable TZ has been set by Cygwin, neutralize it. - The Microsoft CRT interprets TZ differently than Cygwin and produces - incorrect results if TZ has the syntax used by Cygwin. */ + /* Rectify the value of the environment variable TZ. + There are two possible kinds of such values: + - Traditional US time zone names, e.g. "PST8PDT", + - tzdata time zone names, based on geography. They contain one + or more slashes. + The Microsoft CRT understands only the first kind, see + <https://msdn.microsoft.com/en-us/library/90s5c885.aspx>. + It produces incorrect results if the value of TZ is of the second kind. + But in a Cygwin environment, /etc/profile.d/tzset.sh sets TZ to + a value of the second kind for most geographies. If this is the case, + neutralize it. For the Microsoft CRT, an absent of empty TZ means + the time zone that the user has set in the Windows Control Panel. */ const char *tz = getenv ("TZ"); if (tz != NULL && strchr (tz, '/') != NULL) _putenv ("TZ=");