Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Determining Daylight Savings Time

by Starky (Chaplain)
on May 29, 2002 at 21:20 UTC ( [id://170223]=perlquestion: print w/replies, xml ) Need Help??

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

Is there a way to determine whether a given date in an arbitrary time zone occurs during daylight savings time (e.g., when you have something like the number of epoch seconds given by a client's time() call such as 1022704935, or perhaps just a date string such as '2002-05-29 08:00:00', and the client is in MST7MDT) other than a convoluted procedure involving localtime()[8]?

I have searched the CPAN, but to no avail. And using localtime has provided me with nothing but frustration, since (so far as I can tell) the only way to determine whether it is daylight savings time in a particular time zone is:

  1. Convert the date to epoch seconds
  2. Set $ENV{TZ} to the timezone in question.
  3. Add or subtract the number of seconds from the epoch seconds depending on the offset from the local timezone setting. Determining the offset involves knowing whether it is daylight savings time or not, so we have a bit of a chicken-and-egg problem here several times a year ...
  4. Get $isdst = localtime($epoch_seconds)[8]
  5. Reset $ENV{TZ} to its original value so it doesn't muck up any other date calculations elsewhere in the code

The reason for dealing with the offset is that localtime() likes to adjust the return value according to the offset between the machine's time zone and that given by $ENV{TZ}:

#!/usr/bin/perl use strict; my $time = time(); print "Localtime is [".localtime($time)."[ when \$ENV{TZ} is [$ENV{TZ} +] based on time [$time]\n"; $ENV{TZ} = 'GMT'; print "Localtime is now [".localtime($time)."] when \$ENV{TZ} is [$ENV +{TZ}[ based on time [$time]\n";
yields
Localtime is [Wed May 29 14:42:15 2002] when $ENV{TZ} is [] based on t +ime [1022704935] Localtime is now [Wed May 29 20:42:15 2002] when $ENV{TZ} is [GMT] bas +ed on time [1022704935]
Even Date::Manip likes to implicitly convert epoch seconds. For example,
#!/usr/bin/perl use strict; use Date::Manip; print &UnixDate(&ParseDate("epoch ".time()),"%Y-%m-%d %H:%M:%S")."\n";
gives
[starky@freak bin]$ unset TZ [starky@freak bin]$ ./dm-test.pl 2002-05-29 15:11:01 [starky@freak bin]$ export TZ=GMT [starky@freak bin]$ ./dm-test.pl 2002-05-29 21:11:15

It just seems to be an overly convoluted process. I'm convinced there's an easier way but cannot seem to find it. I feel like I'm just being daft here or there's something about time zones I'm simply not clued in to ...

Edit by tye to change PRE tags to CODE tags

Replies are listed 'Best First'.
Re: Determining Daylight Savings Time
by Juerd (Abbot) on May 29, 2002 at 21:30 UTC

    5. Reset $ENV{TZ} to its original value so it doesn't muck up any other date calculations elsewhere in the code

    You could of course localize %ENV:

    { local $\ = "\n"; print scalar localtime; { local %ENV; $ENV{TZ} = 'GMT'; print scalar localtime; } print scalar localtime; }
    yields:
    Wed May 29 23:29:08 2002 Wed May 29 21:29:08 2002 Wed May 29 23:29:08 2002

    Update/PS: -- for frontpaging your own node. Don't do that.

    - Yes, I reinvent wheels.
    - Spam: Visit eurotraQ.
    

      You don't have to localize all of %ENV:
      local $ENV{TZ} = 'GMT';
         MeowChow                                   
                     s aamecha.s a..a\u$&owag.print

        You don't have to localize all of %ENV: local $ENV{TZ} = 'GMT';

        Please test before posting. Localizing a single %ENV value will not work as expected.

        { local $\ = "\n"; print scalar localtime; { local $ENV{TZ} = 'GMT'; print scalar localtime; } print scalar localtime, ", which is wrong."; }
        yields:
        Thu May 30 23:19:56 2002 Thu May 30 21:19:56 2002 Thu May 30 21:19:56 2002, which is wrong.
        Update: environment: Debian GNU/Linux sid x86, Perl 5.6.1

        - Yes, I reinvent wheels.
        - Spam: Visit eurotraQ.
        

Re: Determining Daylight Savings Time
by Abigail-II (Bishop) on May 30, 2002 at 12:37 UTC
    No, that is fundamentally impossible.

    Suppose I give you the date '27 October 2002, 2:30', and the timezone is CET. Is that in daylight savings time or not? The answer is that *both* are possible. There will be a 27 October 2002, 2:30 in DST, followed one hour later by a 27 October 2002, 2:30 not in DST.

    Of course it's possible that given a date (and time), and the timezone to calculate which date/times have to be DST, which ones cannot be DST, which ones can be both (typically just one hour/year), and which date/time combinations are impossible (typically one hour/year as well). After all, that's what your computer does too when displaying time ;-) But the rules differ from timezone to timezone.

    Note that in your particular example, with TZ = MST7MDT, it's easy, as then the timezone name itself indicates daylight savings time is active.

    I don't understand your steps to determine DST though. With step 1, you convert the date to epoch seconds - but you already need to know the timezone and whether it's DST or not for that. And why are you in step 3 fiddling with the epoch?

    Finally, did you study Time::Local and see how that tackles the problem?

    Abigail

      Late reply, but:

      This is absolutely impossible without knowing local rules. Because there can be different rules within a single timezone. Example: while Arizona in its entirety belong to the Mountain time zone, most (but not all) of it does NOT observe Daylight Savings Time. Other states in this same timezone do. There are a number of other similar situations in the world.

      Your best bet is to query some service for example geonames. Then you can have accurate data.

Re: Determining Daylight Savings Time
by maverick (Curate) on May 29, 2002 at 21:31 UTC
    The first question that springs to mind is why do you need to know if the time zone you're in is daylight savings or not?

    If the goal is to have two different systems in different timezones have a normalized time, why not use gmtime() instead of localtime()? it gives you the same value regardless of the local...

    /\/\averick
    OmG! They killed tilly! You *bleep*!!

      Thanks for your reply!

      The reason is that I'm doing timezone conversion. The code is supposed to be high-availability ... it is very bad if times get snookered even a couple times a year.

      I'm using Date::Manip to perform the conversion. Date::Manip understands MST and MDT, but it does not understand something like MST7MDT. For example,

      #!/usr/bin/perl use strict; use Date::Manip; my $date = &ParseDate("2002-05-29 08:00:00"); print "The unconverted date is [".&UnixDate($date,"%Y-%m-%d %H:%M:%S") +."]\n"; my $from = 'MDT'; my $to = 'GMT'; my $converted = &Date_ConvTZ($date,$from,$to); print "The conversion from [$from] resulted in [".&UnixDate($converted +,"%Y-%m-%d %H:%M:%S")."]\n"; $from = 'MST7MDT'; $converted = &Date_ConvTZ($date,$from,$to); print "The conversion from [$from] resulted in [".&UnixDate($converted +,"%Y-%m-%d %H:%M:%S")."]\n";
      gives
      The unconverted date is [2002-05-29 08:00:00] The conversion from [MDT] resulted in [2002-05-29 14:00:00] The conversion from [MST7MDT] resulted in [2002-05-29 08:00:00]

      So I need to know whether a given date is in Mountain Daylight Time or Mountain Standard Time.

      Edit by tye to change PRE tags to CODE tags

        So essentially the problem is that Date::Manip doesn't understand MST7MDT and gives you GMT? Maybe you could look at the internals of Date::Manip and add that timezone? Perhaps a different CPAN module would do the trick...Date::Handler looks promising..

        HTH

        /\/\averick
        OmG! They killed tilly! You *bleep*!!

        I'm fairly certain that Time::ParseDate correctly handles the AAAXBBB timezone format.

        Update: Whoops, I'm fairly certain I'm wrong.

           MeowChow                                   
                       s aamecha.s a..a\u$&owag.print
Re: Determining Daylight Savings Time
by Starky (Chaplain) on May 29, 2002 at 23:47 UTC
    The reputation of my node now stands at -1.

    Not that I particularly worry about XP, but I would be appreciative if someone could puhleeze clue me in to my why it seems to be receiving a negative response? Did I ask a stupid question? Was the question offensive? Not enough detail? Too much detail? Purely random voting?

    I'm a bit confused at this point. I'd like to ask questions in such a way as to positively contribute to the community, so any feedback would be appreciated.

    Update: Just saw Juerd's "--" comment. Didn't know that was a no-no. Thanks, Juerd :-)

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (7)
As of 2024-04-25 08:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found