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

say i've got a variable, the result of a call to time() from a couple weeks ago, and i want to get the difference between it and the current time, with weeks, days, hours, mins seperate...is there a good way to do this already? i can't just do "60 seconds in 60 minutes in 24 hours..." what with daylight savings time, leap years, etc etc.

this is what i need to do, and i want to make sure theres no better way to do it than to figure all the math myself. (numbers, they scare me like spiders)

$then = "1112241312"; $now = time(); $timespan = $now - $then; ($weeks,$days,$hours,$minutes,$seconds) = doSomethingHere($timespan);

Replies are listed 'Best First'.
Re: figuring difference in times?
by planetscape (Chancellor) on Aug 20, 2005 at 05:10 UTC
Re: figuring difference in times?
by Zaxo (Archbishop) on Aug 20, 2005 at 05:23 UTC

    I think planetscape's answer is sufficient for most purposes. The really reliable answer is to always keep time in UTC. With no time zones and daylight politicking, timekeeping is remarkably simple.

    After Compline,
    Zaxo

Re: figuring difference in times?
by BigLug (Chaplain) on Aug 20, 2005 at 11:12 UTC
    I'm one of the DateTime developers, so it may surprise you that in this case I'd wonder if you need the entire swiss army knife that is DateTime, or if all you need is a butter knife...

    DateTime can do many things beside simple duration formatting. It can manipulate dates and time and convert them between timezones to most points in history. You can even convert your dates to the Julian calendar or even Tolkien's shire calendar. But if you don't need all that don't bother with DateTime (but think about it carefully, will you be writing some other code in the future to work with these dates? If so, then use DateTime)

    The Butter Knife
    The following is the non-DateTime way to do it. The math is fairly simple and I've put it into constants so you can follow it easily.

    Start with finding out how many of the largest period (weeks) are in the duration, then subtract that from the duration and move to the next level of precision. In the end you'll be left with seconds.

    sub doSomethingHere { my $duration = shift; my $MINUTE = 60; my $HOUR = 60 * $MINUTE; my $DAY = 24 * $HOUR; my $WEEK = 7 * $DAY; my $weeks = int($duration / $WEEK); $duration -= $weeks * $WEEK; my $days = int($duration / $DAY); $duration -= $days * $DAY; my $hours = int($duration / $HOUR); $duration -= $hours * $HOUR; my $minutes = int($duration / $MINUTE); my $seconds = $duration - $minutes * $MINUTE; return ($weeks, $days, $hours, $minutes, $seconds); }
    (Disclaimer: The above code is not golf. There are more compact ways to do it without declaring the constants, but this is to illustrate the procedure)
Re: figuring difference in times?
by davidrw (Prior) on Aug 20, 2005 at 13:53 UTC
    a partial Date::Calc solution (see the pod about normalization):
    use Date::Calc qw /Localtime Delta_YMDHMS/; my @then = (Localtime(1112241312))[0..5]; my @now = (Localtime(time))[0..5]; print join ":", Delta_YMDHMS( @now, @then ); # S,M,H,D,M,Y
    To get the number of weeks difference, either do:
    use Date::Calc qw/Delta_Days/; print Delta_Days( @now[0..2], @then[0..2] ) / 7;
    Or use the Weeks_in_Year and Week_of_Year methods.
Re: figuring difference in times?
by rjbs (Pilgrim) on Aug 20, 2005 at 20:09 UTC
    I'd just use Time-Duration. You give it a number of seconds (like the difference between two time() results) and it can tell you that it was "four years, six months, and two hours ago" for example. DateTime is neat, but using it just for this strikes me as nuts.
    rjbs
Re: figuring difference in times?
by ambrus (Abbot) on Jun 10, 2011 at 21:59 UTC

    Let's use the Date::Manip module.

    use Date::Manip; ($weeks,$days,$hours,$minutes,$seconds) = Delta_Format($timespan . "s", 0, qw"%wh %dv %hv %mv %sd");

    Or, using technology from the future (compared to your question)

    use Date::Manip 6.13; my $deltao = Date::Manip::Delta->new($timespan . "s"); ($weeks,$days,$hours,$minutes,$seconds) = $deltao->printf(qw"%www %ddd %hhh %mmm %sss");