Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Finding a remote time

by Moron (Curate)
on Jul 17, 2006 at 09:28 UTC ( [id://561717]=perlquestion: print w/replies, xml ) Need Help??

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

Looking through several pages of modules produced by looking up cpan://Time, I am still no better off with this issue:

localtime() gives me the time in the CET zone. But I am in a routine that is being given records containing a date and time field originally created in EST. Owing to DST inconstency it is not acceptable to apply the most usual difference of 5 hours, because the routine has to work all year round and that idea fails a couple of weeks of the year or so. So I need to get the current time in EST and find the difference which I can then apply to these records so that I am storing them in CET, wherever they came from in the world (that is when I eventually make the solution generic after resolving this immediate case).

Is there a way I can fool localtime() into giving me the EST time or any other idea for how to get the current EST time from a CET-based machine?

Thanks in advance for suggestions.

-M

Free your mind

Replies are listed 'Best First'.
Re: Finding a remote time
by davorg (Chancellor) on Jul 17, 2006 at 09:38 UTC
    Is there a way I can fool localtime() into giving me the EST time or any other idea for how to get the current EST time from a CET-based machine?

    DateTime.pm makes this trivial.

    $ perl -MDateTime -le 'print DateTime->now(time_zone => "EST")' 2006-07-17T04:37:59
    --
    <http://dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

Re: Finding a remote time
by gellyfish (Monsignor) on Jul 17, 2006 at 09:40 UTC

    You can set $ENV{TZ} and then use the tzset from POSIX:

    use POSIX qw(tzset); use strict; + print scalar localtime(); + $ENV{TZ} = 'EST'; + tzset(); + print scalar localtime();

    /J\

      Actually you might want to use:

      use POSIX qw( tzset ) sub localtime_in { local $ENV{TZ} = shift; tzset; localtime } $localtime_in_EST = localtime_in( "EST" );

      Otherwise you've globally change the timezone for any other calls to (gm|local)time elsewhere in your code.

      And personally I've used both some variant of twiddling $ENV{TZ} like this and DateTime.

        Localising the $ENV{TZ} isn't sufficient to prevent the effect being global, tzset() will need to be called after the value has been reverted to restore the timezone used by localtime(). For example:

        use POSIX qw(tzset); use strict; + print scalar localtime(); + sub localtime_in { local $ENV{TZ} = 'EST'; + tzset(); + localtime(); } + print scalar localtime_in(); print scalar localtime();

        Off the top of my head a way of fixing that would be something like:

        use POSIX qw(tzset); use strict; + print scalar localtime(); + sub localtime_in { my $rc; my @rc; { local $ENV{TZ} = shift; tzset(); wantarray ? @rc = localtime() : $rc = localtime(); } tzset(); return wantarray ? @rc : $rc; } + print scalar localtime_in('EST'); print scalar localtime();

        /J\

        Doesn't seem to work for me using ActivePerl v5.8.7 build 813 under Windows Server 2003. I do get the local time no matter whether I set $ENV{TZ} to EST or CET (my timezone). Tried even localtime_in( "0500" );

        Update: The DateTime solution works though. So if you need to make portable code, use DateTime;

Re: Finding a remote time
by jaa (Friar) on Jul 17, 2006 at 20:37 UTC
    As a general rule, when having to deal with datetimes and timezones, NEVER store a localtime. If you are going to have users / processing in multiple timezones, the sanest way to deal with everything is to store it ALL in UTC / GMT from the outset.

    Storing UTC makes it trivial to display correct localised date-times in Perl / various web and other front ends / languages etc using standard libraries, and without adding the overhead of your own complex date-math for all accesses to the data.

    As an aside, MySQL <= 4.1 is a PITA for saving UTC - all the time functions are localtime, and affected by the TZ of your mysql daemon.

    Use this expression for a UTC now() in MySQL:

    update mytable set right_now=DATE_ADD('1970-01-01', INTERVAL UNIX_TIMESTAMP() SECON +D)
    To get correct localtimes in Perl / etc, just make sure that you set the TZ of the process handling the request, and the localtime functions will do the hard work for you.

    Regards,

    Jeff

    A reply falls below the community's threshold of quality. You may see it by logging in.
    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Finding a remote time
by Ieronim (Friar) on Jul 17, 2006 at 09:40 UTC
    The problem you described seems to be a task for Date::Manip. This module is big and slow, but it allows to easily process dates and times in many different formats, taking the timezones into account.

         s;;Just-me-not-h-Ni-m-P-Ni-lm-I-ar-O-Ni;;tr?IerONim-?HAcker ?d;print
Re: Finding a remote time
by Moron (Curate) on Jul 17, 2006 at 13:59 UTC
    Thanks for all your replies. In the end I went for fletch's suggestion to localise $ENV{ TZ }, because I needed to compute the difference between local time and the remote time and could not permit the code to switch to remote time throughout. Another factor in choosing the most convenient solution was that it was easier to use core modules only rather than require module installation all the way down the production line (dev -> test -> QA -> uat -> prod.) for so small a piece of code.

    Update: OK to be honest I did not explicitly use 'local' because the tzset had to be repeated anyway. What I actually did was more like:

    sub RemoteTime { my $realtz = $ENV{ TZ }; my ( @return, $return ); my $wantarray = wantarray; $ENV{ TZ } = shift; tzset; if ( $wantarray ) { @return = localtime(); } else $return = localtime(); } $ENV{ TZ } = $realtz; tzset; return $wantarray ? @return : $return; }

    -M

    Free your mind

      If you need to compute stuff you really ought to use DateTime - it takes care of all the nasty details of time math for you.
      -nuffin
      zz zZ Z Z #!perl
      A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://561717]
Approved by Corion
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others studying the Monastery: (5)
As of 2024-04-23 08:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found