[Haskell-cafe] Working with multiple time zones

Bjorn Bringert bjorn at bringert.net
Sun Feb 17 10:09:10 EST 2008


On Feb 17, 2008 12:13 AM, Dave Hinton <beakerchu at googlemail.com> wrote:
> (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.

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


More information about the Haskell-Cafe mailing list