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

If I had a timestamp from 3 days ago at 4:31 pm, and one from 9 days ago at 2:40am, what kind of command would tell me the amount of days between there, not hours, minutes or anything like that, just complete days??

For example:
my $_timestamp1 = '1189669351'; my $_timestamp2 = '1189395751'; my $_timebetween = $_timestamp1 - $_timestamp2; # $_timebetween now has 273600 which if I do (273600 / (60 * 60 * 24) +it is 3.1666666666666666666666666666667

So should I just do that and erase everything to the right of the period? Or is there a module that will make it more simple, or any code?

Thank you.

Replies are listed 'Best First'.
Re: question about unix timestamps (epoch)
by Limbic~Region (Chancellor) on Sep 13, 2007 at 12:44 UTC
    Anonymous Monk,
    Have you looked at Time::Duration? I wrote a toy module for practice purposes that did something along this line but never released it as there was prior art.

    Update: Perhaps my early morning brain didn't make clear what I was thinking when I wrote this. To get just what you want is rather straight forward as others have shown. I asked the question about a module not because I thought it was necessary for your problem, but perhaps because:

    • You didn't know how easy it could be
    • You didn't know it existed
    • You might not need to come back for help if your requirements changed

    Cheers - L~R

Re: question about unix timestamps (epoch)
by shmem (Chancellor) on Sep 13, 2007 at 12:52 UTC
    Choose one of these:
    my $_timestamp1 = '1189669351'; my $_timestamp2 = '1189355751'; printf "rounded: %.0f\n",($_timestamp1 - $_timestamp2) / 86400; print "truncated: ",int( ($_timestamp1 - $_timestamp2) / 86400),"\n"; print "float: ",(($_timestamp1 - $_timestamp2) / 86400),"\n"; __END__ rounded: 4 truncated: 3 float: 3.62962962962963

    I think using a module for such a simple operation is a bit overkill, but that's just me.

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Re: question about unix timestamps (epoch)
by johngg (Canon) on Sep 13, 2007 at 12:52 UTC
    If you are only interested in complete days, that is, 3 days, 23 hours, 40 minutes is reckoned to be 3 days, not rounded up to 4, then just truncate using int.

    my $completeDays = int(($_timestamp1 - $_timestamp2) / 86400);

    I hope this is of use.

    Cheers,

    JohnGG

Re: question about unix timestamps (epoch)
by Joost (Canon) on Sep 13, 2007 at 14:44 UTC
    Looking at Time::Duration (which Limbic~Region suggested), I note that it doesn't work on dates as such, which means that it may or may not do what you want.

    For instance, like your posted code, it won't take into account leap seconds, DST or anything like that - it just figures a day is always 24 hours of 60 minutes of 60 seconds.

    If you want to take those into account, take a look at DateTime.

    As a side note: what humans think of as "X days (ago)" is something subtler and more complex than 60 * 60 * 24 seconds. For instance, yesterday evening is "a day ago" even if right now it's only 17 hours ago.

    For those kind of "days" it may be more appropriate to do the calculation only looking at the year & day-of-the-year.

Re: question about unix timestamps (epoch)
by johnlawrence (Monk) on Sep 13, 2007 at 12:49 UTC
    If you want to do it that way, you can just use int:
    #!/usr/bin/perl -w my $_timestamp1 = '1189669351'; my $_timestamp2 = '1189395751'; my $_timebetween = $_timestamp1 - $_timestamp2; print int($_timebetween/(60*60*24));

      It won't always give the right answer, because not all days are 24*60*60 seconds long. It's possible for your code to return one more day or one less day than expected.

      For example,
      it's possible for 4:30am one day to 4:00am the next day to return 1, and
      it's possible for 4:00am one day to 4:30am the next day to return 0.

        That's a good point. I was just about to ask why when I realised the obvious! I guess the solution I gave, was more "the number of 24 hour periods". Still, that should work in most cases, I guess it depends how critical it is.
Re: question about unix timestamps (epoch)
by sanPerl (Friar) on Sep 13, 2007 at 14:55 UTC
    I think what you want is absolute days between two dates (the way any human would calculate). You can use following code. This will exactly give you 3 days. I have converted localtime to 12:00 am of the day and i am taking difference. It works :-)
    use strict; use Time::Local; my $_timestamp1 = '1189669351'; my $_timestamp2 = '1189395751'; my ($sec1,$min1,$hour1,$mday1,$mon1,$year1,$wday1,$yday1,$isdst1) = lo +caltime($_timestamp1); my ($sec2,$min2,$hour2,$mday2,$mon2,$year2,$wday2,$yday2,$isdst2) = lo +caltime($_timestamp2); my $no_of_days = ((timelocal(0,0,0,$mday1,$mon1,$year1,$wday1,$yday1,$ +isdst1) - timelocal(0,0,0,$mday2,$mon2,$year2,$wday2,$yday2,$isdst2)) +/86400); print "$no_of_days\n";
Re: question about unix timestamps (epoch)
by menolly (Hermit) on Sep 13, 2007 at 22:50 UTC
    Date::Calc is another module that can be useful for this and similar tasks.