in reply to Date Time problem.

I think there have been some great replies, but I think some further clarification would help. I can see that there are some mis-understandings.

There are three time functions included within Perl itself:
1. localtime()
2. gmtime()
3. time() - makes an epoch second value for "now", can be used by either gmtime() or localtime()

The module Time::Local contains the inverse of those functions:
1. timelocal()
2. timegm()
3. (there is no "inverse" of time() per sea)

The operating system keeps track of "time" based upon a continually incrementing integer number of seconds since a specific start date/time. This is called the "epoch time" (returned time() value of zero). For Unix and Windows this is 00:00:00 Jan 1, 1970. I seem to remember that some versions of Apple's OS'es use a different value for this "epoch date/time". The point being is that this "epoch time" value is not transportable in a general sense between platforms. Converting an "epoch time" to a text string is a good way to ensure portability.

The time() function produces the current value of this continuously incrementing number of "epoch seconds" since the start of the "epoch" and corresponds to "now". This number never decreases and is independent of daylight savings time. When we "set our clocks back one hour", this "seconds since epoch" number just keeps growing. Just because we set our clocks back one hour, that doesn't change the fact that more seconds are continuing to accrue since the "epoch time".

The general way to do "time math" is to convert to epoch seconds, do math in seconds and then convert back to a string. The DateTime module does it that way too and it can apply some fancy "correction values for leap seconds, etc.

Some simple example code...

#!usr/bin/perl -w use strict; my $one_day_secs = 24*60*60; my $today = time(); my $today_string = localtime($today); my $yesterday_string = localtime($today-$one_day_secs); print "today as epoch time: $today\n"; print "today: $today_string\n"; print "yesterday: $yesterday_string\n"; print time __END__ output: today as epoch time: 1252088732 today: Fri Sep 4 11:25:32 2009 yesterday: Thu Sep 3 11:25:32 2009
localtime($time) is just a user presentation of the $time, "seconds since epoch" integer value.

I recommend and use UTC, Zulu, GMT time in log files (that basically is all the same thing).

Update: the OP's idea of adding zero is a GREAT idea. The idea is that default alpha sort will produce correct answers. A simple substitution to add a zero if only a single digit appears to suffice.

#!/usr/bin/perl -w use strict; my $a = "1"; $a =~ s/^(\d)$/0$1/; print $a;

Replies are listed 'Best First'.
Re^2: Date Time problem.
by ikegami (Patriarch) on Sep 05, 2009 at 02:39 UTC

    The general way to do "time math" is to convert to epoch seconds, do math in seconds and then convert back to a string.

    Except it doesn't work. Not all days have 24*60*60 seconds.

    the OP's idea of adding zero is a GREAT idea.

    And POSIX's strftime is the way to do it if you're already dealing with localtime or gmtime (It handles the y+1900 and the m+1 for you.)

    use POSIX qw( strftime ); print( strftime('%Y%m%d', localtime), "\n");
      Dealing with "leap seconds" is a complex thing.
      For leap seconds for awhile see:
      http://en.wikipedia.org/wiki/Leap_second

      For most logging and reporting activities, leap seconds are of no consequence. One "day" is 86,400 seconds (24*60*60) seconds. There may or may not be a "leap second" in a given year. The Op's question was for one day ago.

      No problem with strftime. It "works" albeit slower than other ways.

        As previously mentioned, I don't think leap seconds matter with time. In any case, I'm talking of the days with 23*60*60 seconds and the days with 25*60*60 seconds.

        Previously written example:

        # Set your timezone to America/New_York before running. # In this time zone, DST ends on Nov 2, 2008 at 2:00 AM. # "Sets" the current time to 5 seconds past midnight on Oct 28, 2008. use Time::Local qw( timelocal ); my $time = timelocal(5,0,0,28,10-1,2008); use POSIX; print( strftime( "%m-%d\n", localtime( (24*60*60) * $_ + $time ) ) ) for 1..30;

        Output

        10-29 10-30 10-31 11-01 11-02 \ 11-02 seen twice 11-02 / 11-03 11-04 11-05 11-06 11-07 11-08 11-09 11-10 11-11 11-12 11-13 11-14 11-15 11-16 11-17 11-18 11-19 11-20 11-21 11-22 11-23 11-24 11-25 11-26 > 11-27 never seen

        You don't need any inefficient code to do it right, so you might as well do it right. Sewi showed a way that will probably always work. The following will always work:

        use Time::Local qw( timegm ); use POSIX qw( strftime ); my $date = timegm(localtime); $date += 24*60*60; print(strftime("%Y%m%d\n", gmtime($date)));

        GMT always has 24*60*60 seconds per day. Note the result is still local time.