
On Feb 17, 2008 12:13 AM, Dave Hinton
(This is a toy program to demonstrate only the part of my real program that I'm having trouble with.)
Suppose I'm writing a program to print the current time in various time zones. The time zones are to be given symbolically on the command line in the form "Europe/London" or "America/New_York". The idea is that either the operating system or the runtime library keeps track of what time zones different places are in, and when they are on summer time, so that my code doesn't have to worry about it.
Haskell has a TimeZone type in Data.Time.LocalTime, but it only represents constant offsets from UTC — doesn't encode rules for when the clocks change. And there doesn't seem to be any way of looking up the time zone for a locality.
Data.Time.LocalTime has the getTimeZone function, which returns the time zone for a given UTC time on the local machine — this takes care of summer time, but by itself only works for the local machine's locality.
If I was writing this program in C, I'd get round this by setting the TZ environment variable to the locality I was interested in before doing time conversions.
$ cat cnow.c #include
#include #include #include void outTime (time_t utc, char *tzName) { char env[100] = "TZ="; strcat (env, tzName); putenv (env); printf ("%s\t%s", tzName, asctime (localtime (&utc))); } int main (int argc, char **argv) { int i; time_t utc = time (NULL); for (i = 1; i < argc; ++i) outTime (utc, argv[i]); return 0; } $ gcc cnow.c -o cnow $ ./cnow Europe/Paris Europe/Moscow Europe/London Europe/Paris Sat Feb 16 23:57:22 2008 Europe/Moscow Sun Feb 17 01:57:22 2008 Europe/London Sat Feb 16 22:57:22 2008 So far, so good. Here's the equivalent in Haskell:
$ cat hsnow.hs import Data.Time import Data.Time.LocalTime import System.Environment import System.Posix.Env outTime utc env = do putEnv ("TZ=" ++ env) tz <- getTimeZone utc putStrLn (env ++ "\t" ++ show (utcToLocalTime tz utc)) main = do utc <- getCurrentTime mapM_ (outTime utc) =<< getArgs $ ghc --make hsnow.hs -o hsnow [1 of 1] Compiling Main ( hsnow.hs, hsnow.o ) Linking hsnow ... $ ./hsnow Europe/Paris Europe/Moscow Europe/London Europe/Paris 2008-02-16 23:59:11.776151 Europe/Moscow 2008-02-16 23:59:11.776151 Europe/London 2008-02-16 23:59:11.776151 $ ./hsnow Europe/Moscow Europe/London Europe/Paris Europe/Moscow 2008-02-17 01:59:28.617711 Europe/London 2008-02-17 01:59:28.617711 Europe/Paris 2008-02-17 01:59:28.617711
Not good. GHC's runtime library seems to be taking the value of TZ the first time it is called as gospel, and ignoring subsequent changes to TZ.
So:
1. Is this a bug in GHC's Data.Time.LocalTime.getTimeZone? 2. If GHC's implementation is working as designed, how do I translate the C program above into Haskell?
I'm running on Debian stable, with GHC 6.6.
Interesting, it works for me: $ ghc --make hsnow.hs -o hsnow [1 of 1] Compiling Main ( hsnow.hs, hsnow.o ) Linking hsnow ... $ ./hsnow Europe/Paris Europe/Moscow Europe/London Europe/Paris 2008-02-17 16:07:43.009057 Europe/Moscow 2008-02-17 18:07:43.009057 Europe/London 2008-02-17 15:07:43.009057 $ ghc --version The Glorious Glasgow Haskell Compilation System, version 6.8.2 $ uname -srv Darwin 8.11.1 Darwin Kernel Version 8.11.1: Wed Oct 10 18:23:28 PDT 2007; root:xnu-792.25.20~1/RELEASE_I386 -- /Björn