Perl Time::Piece use current date if not in format

Viewed 207

Consider this code:

use Time::Piece;
  
my $format="%I:%M %p";
my $from="9 am";

my $d_from = Time::Piece->strptime($from, $format);
print ($d_from);
              

This prints:

Thu Jan  1 09:00:00 1970

Let's assume I cannot change $format or $from . The format may or may not have d/m/y values -> how do I make sure the converted object uses current date/time values for the missing components?

My use-case is this: I am writing a rules engine where a user specifies an arbitrary date/time format and I need to match rules and execute if current date/time falls in that date/time. Since the user controls $format and $from I don't know if $format will contain a day/date. It may just contain a time (example $from="9 am" means "9 am every day" if a date is not provided. When converting to a Time::Piece object I want to make sure missing fields are replaced with current date/time not start of epoch time.

1 Answers

Times and date/times are separate things, parse and treat them separately.

use strict;
use warnings;
use Time::Piece;
use v5.10;
 
my $from=shift;

# Put all your various date/time formats here.
my @DATE_TIME_FORMATS = (
    "%m/%d/%Y %I:%M %p", "%Y-%m-%d %H:%M:%S"
);

# And all your various time formats here.
my @TIME_FORMATS = (
    "%I:%M %p"
);

# One function to try parsing a set of formats, first to match wins.
sub try_strptime {
    my($from, $formats) = @_;
    
    for my $format (@$formats) {
        my $time = eval { Time::Piece->strptime($from, $format) };
        return $time if $time;
    }
    
    return;
}

if( my $dt = try_strptime($from, \@DATE_TIME_FORMATS) ) {
    say "At $dt";
}
elsif( my $time = try_strptime($from, \@TIME_FORMATS) ) {
    say $time->time . " each day";
}
else {
    say "Can't recognize '$from'";
}
$ perl test.pl '10:23 pm'
22:23:00 each day

$ perl test.pl '05/10/2020 10:23 pm'
At Sun May 10 22:23:00 2020
Related