[commit: packages/time] master: Make getTimeZone cross-platform consistent by always considering the TZ environment variable. (9926c4a)
git at git.haskell.org
git at git.haskell.org
Fri Jan 23 23:01:21 UTC 2015
Repository : ssh://git@git.haskell.org/time
On branch : master
Link : http://git.haskell.org/packages/time.git/commitdiff/9926c4aae23dc11afb018175a15e505da4e73e73
>---------------------------------------------------------------
commit 9926c4aae23dc11afb018175a15e505da4e73e73
Author: oconnorr <oconnorr at google.com>
Date: Mon Jun 10 15:22:54 2013 -0700
Make getTimeZone cross-platform consistent by always considering the TZ environment variable.
Ignore-this: 98f02c84c56cc5f77aa96e3f9d9e90fc
The current behaviour of getTimeZone is system dependent. On Linux, using glibc we get the following result:
$ ghc -package time-1.4 -e 'System.Posix.Env.putEnv "TZ=EST5EDT" >> Data.Time.getCurrentTimeZone >>= print >> System.Posix.Env.putEnv "TZ=PST8PDT" >> Data.Time.getCurrentTimeZone >>= print'
EDT
EDT
Under MacOS X we get a different result
$ ghc -package time-1.4 -e 'System.Posix.Env.putEnv "TZ=EST5EDT" >> Data.Time.getCurrentTimeZone >>= print >> System.Posix.Env.putEnv "TZ=PST8PDT" >> Data.Time.getCurrentTimeZone >>= print'
EDT
PDT
The underlying problem is that POSIX does not fully specify the behaviour of localtime_r, upon which getTimeZone relies. POSIX.1-2008 says:
Unlike localtime(), the localtime_r() function is not required to set tzname.
"not required" means that localtime_r may or may not set tzname. MacOS X's behaviour sets tzname on every call to localtime_r.
On the other hand, Linux, using glibc, the behaviour of localtime_r is outstandingly complicated. Upon the first call to localtime_r (or more techincially upon the first call to tzset_internal) it will set tzname based upon the value in the TZ environment variable, but upon subsequent calls, localtime_r will *not* set the tzname.
This leads to the bizzare behaviour under Linux whereby the value used by getTimeZone (and getCurrentTimeZone) will always use the value of the TZ environment variable during the first call, and it is impossible to change it again. The only workaround available to a Haskell programer is to call tzset, which is can only be found in another package.
This patch calls tzset() before each call to localtime_r() which forces tzname to be set from the TZ enviroment call. The result is that on all platforms one gets the sane result of
$ ghc -package time-1.4.1 -e 'System.Posix.Env.putEnv "TZ=EST5EDT" >> Data.Time.getCurrentTimeZone >>= print >> System.Posix.Env.putEnv "TZ=PST8PDT" >> Data.Time.getCurrentTimeZone >>= print'
EDT
PDT
darcs-hash:20130610222254-a4c94-e18c93b079fcee2becc635ed32a2ce3c34f9276e
>---------------------------------------------------------------
9926c4aae23dc11afb018175a15e505da4e73e73
cbits/HsTime.c | 1 +
time.cabal | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/cbits/HsTime.c b/cbits/HsTime.c
index dacb1d4..e8a1155 100644
--- a/cbits/HsTime.c
+++ b/cbits/HsTime.c
@@ -5,6 +5,7 @@ long int get_current_timezone_seconds (time_t t,int* pdst,char const* * pname)
{
#if HAVE_LOCALTIME_R
struct tm tmd;
+ tzset();
struct tm* ptm = localtime_r(&t,&tmd);
#else
struct tm* ptm = localtime(&t);
diff --git a/time.cabal b/time.cabal
index 873a06a..5e38d2a 100644
--- a/time.cabal
+++ b/time.cabal
@@ -1,5 +1,5 @@
name: time
-version: 1.4.0.2
+version: 1.4.1
stability: stable
license: BSD3
license-file: LICENSE
More information about the ghc-commits
mailing list