http://www.perlmonks.org?node_id=1181949

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

I am forced to use the epoch Jan 1, 2000 12:00:00. I need to convert from DateTime format to seconds, then back from seconds to DateTime format. How can I do this the easiest way?

  • Comment on How to use a different epoch with DateTime

Replies are listed 'Best First'.
Re: How to use a different epoch with DateTime
by Cristoforo (Curate) on Feb 14, 2017 at 03:25 UTC
    Here is a solution using Time::Piece.
    C:\Old_Data\perlp>corelist Time::Piece Time::Piece was first released with perl v5.9.5
    #!/usr/bin/perl use strict; use warnings; use Time::Piece; my $dt = 'Jan 1, 2000 12:00:00'; my $fmt = '%b %d, %Y %H:%M:%S'; my $epoch = Time::Piece->strptime($dt, $fmt); $epoch += 86400*5; #print localtime($epoch)->strftime($fmt); print $epoch->strftime($fmt);
    This prints Jan 06, 2000 12:00:00

    Update: I wasn't sure if your question specifically wanted a DateTime solution or just a way to convert from a timestamp to epoch and back. Sorry if my post doesn't meet your expectations.

    I'm not well acquainted with the DateTime module, but I'm sure there is a simple solution there as well.

    Update2: Changed the print line to the desired form. Arrg

      Thanks for the great response. DateTime solution not necessary. This looks straight forward. I will give it a try and let you know if it works for me. Thanks
Re: How to use a different epoch with DateTime
by thomas895 (Deacon) on Feb 14, 2017 at 02:02 UTC

    You could create another DateTime with your epoch, and then use the difference between another time and your epoch instance in some way.

    -Thomas
    "Excuse me for butting in, but I'm interrupt-driven..."
Re: How to use a different epoch with DateTime
by anita2R (Scribe) on Feb 14, 2017 at 21:37 UTC

    Does the system you work on have its epoch set to zero for 01 January 2000, or does it use the standard Linux epoch of 01 January 1970?

    (I am ignoring the issue of whether your year 2000 epoch starts at midnight or at noon!)

    Try this to see what it's set at:

    #!/usr/bin/perl # use Time::Local; # use strict; use warnings; # note months are 0 to 11 - hence the '-1' # timegm is seconds, minutes, hours, day, month -1, year my $two_k_epoch = timegm( 0, 0, 0, 1, 0, 2000 ); # midnight 01 January + 2000 - change to noon if required my $linux_epoch = timegm( 0, 0, 0, 1, 0, 1970 ); # midnight 01 January + 1970 print "2K epoch: $two_k_epoch\tLinux epoch: $linux_epoch\n";

    If the 2K epoch is zero, then you shouldn't have to do anything, as all calculations will be using that epoch. As long as the calculated seconds are not transferred to another system that is using the Linux epoch there shouldn't be any problems, but it's not something I can test.

    If however your system is using standard Linux epoch ($linux_epoch is zero) the you will have to subtract the year 2000 value from all calculated seconds and add it back again before converting seconds back to eye-readable values.

    You will still need to know whether you are working in UTC or local time.

    When you used 'DateTime' in your question title, did you specifically mean the perl DateTime module, or just any date and time module. From what I have just read, DateTime uses an epoch based on year 1 (long before the Gregorian calendar was invented),

     In this calendar, the first day of the calendar (the epoch), is the first day of year 1

    As an aside, I like Date::Calc as I do a fair bit of adding/subtracting days or hours from start dates/times

      Yes I was referring to the Perl DateTime module. But I'm not stuck on using that. My problem is this. 1. I must use the epoch 2000 Jan 1, 12:00:00 (UTC) That's 12noon. 2. From that epoch I will be given both beginning and end time boundaries in the future. 3. I will need to add/sub seconds from either of those boundaries. 4. Then convert back to readable form in UTC.

        DateTime is probably not the best module to use, particularly as you are going forward and don't need dates before the start of the Gregorian calendar. The man page for DateTime notes that it does not account for leap seconds, so your results may be out.

        The default time zone for new DateTime objects, except where stated otherwise, is the "floating" time zone. This concept comes from the iCal standard. A floating datetime is one which is not anchored to any particular time zone. In addition, floating datetimes do not include leap seconds, since we cannot apply them without knowing the datetime's time zone. The results of date math and comparison between a floating datetime and one with a real time zone are not really valid, because one includes leap seconds and the other does not. Similarly, the results of datetime math between two floating datetimes and two datetimes with time zones are not really comparable.

        As suggested by thomas895 create your new epoch seconds for the new dates given, calculate the epoch seconds for 01 January 2000, noon, and subtract it from the epoch seconds for new dates given.

        The number of seconds difference between future dates will be the same whatever the base epoch date is.

Re: How to use a different epoch with DateTime
by ikegami (Patriarch) on Feb 14, 2017 at 18:09 UTC

    Jan 1, 2000 12:00:00, as in noon??? What time zone?

      Any time zone will do. Which one do you recommend?
Re: How to use a different epoch with DateTime
by haukex (Archbishop) on Feb 16, 2017 at 11:29 UTC

    Hi thimes,

    It depends a bit on what kind of math you want to do and whether you want leap seconds (pointed out by anita2R, thanks) to be considered. Personally, unless high performance must be considered, I like to throw all of my math at the DateTime module. The following shows the different ways you can do the math:

    #!/usr/bin/env perl use warnings; use strict; use DateTime; my $dt_customepoch = DateTime->new( year=>2000, month=>1, day=>1, hour=>12, minute=>0, second=>0, time_zone=>'UTC' ); print "dt_customepoch: ", $dt_customepoch->strftime('%b %e %Y, %T %Z'), "\n"; my $s_customepoch = $dt_customepoch->epoch; print " s_customepoch: $s_customepoch\n"; ### Obtaining DateTime object from a value expressed in # seconds since the custom epoch (let's call it "sce") my $sce_one = 128072700; # Thu Jan 22 19:45:00 2004 print " sce_one: $sce_one\n"; my $dt_one = DateTime->from_epoch( # Note the addition here epoch => $s_customepoch + $sce_one, # from_epoch defaults to UTC, but we'll be explicit time_zone=>'UTC' ); print " dt_one: ", $dt_one->strftime('%b %e %Y, %T %Z'), " (epoch=", $dt_one->epoch, ")\n"; #### Doing math in the "seconds since custom epoch" domain # Add 3 years, 21 days*, -4 hours, 11 minutes # * adjusted +1 for 2004 being leap year my $s_offset = 60*60*24*365*3 + 60*60*24*(21+1) - 60*60*4 + 60*11; print " s_offset: $s_offset\n"; my $sce_two = $sce_one + $s_offset; print " sce_two: $sce_two\n"; my $dt_two = DateTime->from_epoch( time_zone=>'UTC', epoch => $s_customepoch + $sce_two ); print " dt_two: ", $dt_two->strftime('%b %e %Y, %T %Z'), " (epoch=", $dt_two->epoch, ")\n"; ### Doing the same math in the DateTime domain my $dt_three = $dt_one->clone->add( # Note how no adjustment for the leap year is needed years=>3, days=>21, hours=>-4, minutes=>11); print " dt_three: ", $dt_three->strftime('%b %e %Y, %T %Z'), " (epoch=", $dt_three->epoch, ")\n"; #### Obtaining "seconds from custom epoch" # using regular subtraction vs. DateTime math my $sce_threea = $dt_three->epoch - $s_customepoch; print "sce_threea: $sce_threea\n"; my $sce_threeb = $dt_three ->subtract_datetime_absolute($dt_customepoch) ->in_units('seconds'); # Leap second (Dec 31, 2005 23:59:60 UTC) is considered! print "sce_threeb: $sce_threeb\n"; __END__ dt_customepoch: Jan 1 2000, 12:00:00 UTC s_customepoch: 946728000 sce_one: 128072700 dt_one: Jan 22 2004, 19:45:00 UTC (epoch=1074800700) s_offset: 96495060 sce_two: 224567760 dt_two: Feb 12 2007, 15:56:00 UTC (epoch=1171295760) dt_three: Feb 12 2007, 15:56:00 UTC (epoch=1171295760) sce_threea: 224567760 sce_threeb: 224567761

    Hope this helps,
    -- Hauke D