ArthurDent has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to use perl to format weather data from a postgres database. The trouble is that we store the timezone information in the normal TZ environment variable format (like EST5EDT for eastern US). In C, if I wanted to get the local time at a particular place, I would do a putenv call followed by a tzset call (this is on UNIX btw) and then magically when I call localtime or mktime, I get the effect I desire. I've done some searching, but I've found no way to do something similar in Perl.

I've seen some references in my travels to the $ENV variable. I assume that I can use that to set the timezone given the strings from the database. If I do that, will localtime cooperate and behave like it would in C? Is there another way to do this?

TIA
Ben

Replies are listed 'Best First'.
Re: Timezones in Perl
by Shendal (Hermit) on Jun 22, 2000 at 23:25 UTC
    Either roll your own using gmtime, or look through the locale information in the perldocs here and implement using setlocale.

    Of the two, I'd suggest rolling your own. Setting the locale seems dangerous to me.
RE: Timezones in Perl
by lhoward (Vicar) on Jun 22, 2000 at 23:35 UTC
    Date::Manip is the granddaddy of all Date/Time manipulation modules. It has a several timezone related functions (Date_ConvTZ, ConvTZ, etc..) that allows you to convert dates/times from one timezone to another without needs for setting any environmental variables.
      I suppose you could use Date::Manip, but, by the module author's own comments, "It's big and slow." If all you want is to convert time zones, I think it's easy to write your own, your performance wouldn't suffer, and you wouldn't have to worry about weather or not Date::Manip is installed.
        Of course, if you do write your own code you will be spending time to re-implement something that someone has already written. If the overhead of calling a "slow" module like Date::Manip is too much for you, then Perl is probably too slow and inefficient for you; you should use a compiled language like C. Also Date::Manip (and all other perl modules) has been used by thousands of perl programmers, so the code is well tested and proven to be reliable, stable and relatively bug-free.
Re: Timezones in Perl
by Adam (Vicar) on Jun 23, 2000 at 00:27 UTC
    The %ENV associated array contains the environment as it was passed to the current process. It is not returned when the process ends, so it does not effect other processes. When you fork a process from your Perl script it passes the %ENV hash to the new process. So, for example, if you invent an environment variable and add it to %ENV and then do a backtick shell command, that command will see your variable in the environment, whereas if you launch a separate shell outside of all this, you won't.
RE: Timezones in Perl
by ArthurDent (Acolyte) on Jun 23, 2000 at 19:07 UTC
    I figured it out. I ended up doing the following:

    my $inttime = time; my @local_tm = localtime($inttime); my @gmt_tm = gmtime($inttime); my $tz = $ENV{TZ}; print @local_tm[2],":",@local_tm[1],":",@local_tm[0]," ",$tz,"\n"; $tz = "EST5"; $ENV{TZ} = $tz; @local_tm = localtime($inttime); print @local_tm[2],":",@local_tm[1],":",@local_tm[0]," ",$tz,"\n";


    This produces the following output, that while ugly is what I was hoping for..

    11:5:40 EST5EDT 10:5:40 EST5
    Ben

      There are a couple of stylistic points that I'd like to make about your code - one more serious than the other.

      The more serious one is that you're using array slices where you want scalars. That is where you're using @local_tm[2] you should be using $local_tm[2].

      The less serious issue is that you don't need to split up the parameters to print. You can do something like this:

      print "$local_tm[2]:$local_tm[1]:$local_tm[0] $tz\n";

      or (to get the formatting a little nicer) you can use printf:

      printf '%02d:%02d:%02d %d', $local_tm[2], $local_tm[1], $local_tm[0], $tz;

      or (to really show people how well you know Perl) use printf and an array slice:

      printf '%02d:%02d:%02d %d', @local_tm[2, 1, 0], $tz;

      --
      <http://www.dave.org.uk>

      European Perl Conference - Sept 22/24 2000
      <http://www.yapc.org/Europe/>
        Thanks...

        The code I posted was basically just a quick hack as a proof of concept more than anything.. I obviously should have used $local_tm[2] rather than with the @. That was just stupidity on my part, combined with inexperience in perl. If I was doing something more valuable than just a proof of concept, I would have used printf rather than print.

        Thanks for the help though!

        Ben