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

Hi Monks!
I did a search in the Monastery for similar threads, and only found 1, but not very helpful. The task I want to perform is, given a specified date, select the one that is closest to it and also, be able to say if the "closest" date is in the future or in the past, relative to the specified one. My input is (after my pre-processing) an array of dates, from which I need to pull the closest one to the one that I will specify externally. Are there modules for this available?

Replies are listed 'Best First'.
Re: choosing closest date to a given date
by marto (Cardinal) on Sep 14, 2018 at 12:42 UTC

    For each date in your array calculate the delta between it and the target date, select the one with the lowest delta? Date::Calc/Date::Manip.

Re: choosing closest date to a given date
by haukex (Archbishop) on Sep 14, 2018 at 19:09 UTC

    Personally, I like DateTime (usually together with DateTime::Format::Strptime for parsing).

    use warnings; use strict; use DateTime; use DateTime::Format::Strptime; my @time_strs = qw/ 2018-09-14T14:35:56Z 2018-09-13T09:32:12Z 2018-09-12T20:12:16Z 2018-08-07T07:12:45Z 2018-08-01T23:55:59Z 2018-07-24T15:39:01Z 2018-01-04T18:19:20Z 2017-11-03T10:26:49Z 2017-07-17T17:22:04Z/; my @target_strs = qw/ 2018-09-13T23:55:00Z 2018-09-14T00:55:00Z 2018-04-14T09:33:12Z 2018-04-15T09:33:12Z/; for my $target_str (@target_strs) { my $strp = DateTime::Format::Strptime->new( on_error=>'croak', pattern => '%Y-%m-%dT%H:%M:%SZ', time_zone=>'UTC' ); my $target_dt = $strp->parse_datetime($target_str); my @dts; for my $t (@time_strs) { my $dt = $strp->parse_datetime($t); my $diff_s = $dt->subtract_datetime_absolute($target_dt) ->in_units('seconds'); push @dts, { dt=>$dt, diff_s=>$diff_s, absdiff_s=>abs($diff_s) }; } @dts = sort { $a->{absdiff_s} <=> $b->{absdiff_s} } @dts; my $closest = $dts[0]; print "Closest is ", $closest->{dt}->strftime('%Y-%m-%dT%H:%M:%S %Z'), ", which is ", $closest->{diff_s}>0 ? 'after ' : 'before ', $target_dt->strftime('%Y-%m-%dT%H:%M:%S %Z'), "\n"; } __END__ Closest is 2018-09-13T09:32:12 UTC, which is before 2018-09-13T23:55:0 +0 UTC Closest is 2018-09-14T14:35:56 UTC, which is after 2018-09-14T00:55:0 +0 UTC Closest is 2018-01-04T18:19:20 UTC, which is before 2018-04-14T09:33:1 +2 UTC Closest is 2018-07-24T15:39:01 UTC, which is after 2018-04-15T09:33:1 +2 UTC
Re: choosing closest date to a given date
by Laurent_R (Canon) on Sep 14, 2018 at 19:24 UTC
    If you have only one specified date, or do that only once in a while, then the easiest is to traverse your array of dates and find the smallest time difference.

    If, on the other hand, you need to do that with large loads of specified dates, then it might be worth to sort your date array once and then implement a binary search algorithm.

Re: choosing closest date to a given date
by hippo (Archbishop) on Sep 14, 2018 at 13:10 UTC
    Are there modules for this available?

    Loads. I'd probably go with Time::Seconds since it's a core module.

Re: choosing closest date to a given date
by bliako (Abbot) on Sep 16, 2018 at 00:36 UTC

    working with seconds-since-the-epoch-unix-style may be the fastest and most straight-forward way. As a bonus, future and past are distinguished by the sign of the result of the subtraction of the two dates' epochs.

    But you will soon discover that you want to compare dates in different time-zones too. And therefore a module for high-level date construction/parsing/manipulation like DateTime (and its sub-tree) might be more useful to you to use from the start.

    If you are only interested in Date rather than Date+Time then Date::Simple has <=> overloaded, which means something like this: if( $dt1 > $dt2 ){ } works fine.

    I have used both modules with great satisfaction.