[Haskell-cafe] Working with multiple time zones

Dave Hinton beakerchu at googlemail.com
Sat Feb 16 18:13:59 EST 2008


(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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
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.

Thanks.


More information about the Haskell-Cafe mailing list