Reputation: 702
I am running into issues converting the date Apr 9 2017 3:45:00:000AM
to 2017-04-09 03:45:00
Here's what i have tried.
use DateTime::Format::Strptime;
my $strp = DateTime::Format::Strptime->new(pattern => '%h %d %Y %H:%M',);
$start_date = $strp->parse_datetime('Apr 9 2017 3:45:00:000AM');
prints 2017-04-09T03:45:00
and not 2017-04-09 03:45:00
. Trying to get 24 hour clock so when i switch AM
to PM
the same time prints.
Upvotes: 0
Views: 681
Reputation: 66883
Update See end for an strptime
pattern to parse the shown input string format correctly
What is shown works,† and so the DateTime::Format::Strptime constructor returns a DateTime
object. But when an object is simply printed then one gets the stringification that is shown.
So you need to format it for printing as desired. A general way is with strftime
say $start_date->strftime("%F %T");
where both %F
and %T
are shorthands, see strftime patterns
Or combine the basic ymd
and hms
methods
say $start_date->ymd('-') . ' ' . $start_date->hms(':');
See the docs and adjust if/as needed. I didn't understand some details.
† It works only by accident in this exact example, since the pattern given to use for parsing in new
is wrong for the shown input format, and is also inconsistent with stated requirements
The shown pattern doesn't have a format specifier for the seconds, nor for the milliseconds that follow it, nor for the following AM/PM
-- all expected in the input string. So in general an input in the shown form cannot be parsed correctly with the shown pattern
The %H
matches 00-23
hour, so not 12-hour clock which is stated as expected and is implicit by the presence of AM
. (It still matches a 12-hour-time number but it won't once the missing AM/PM format specifier is added.)
The pattern in the OP works and parses the given input correctly because 03:45...
happens to be in AM, and the module uses regex to match the given pattern anywhere in the given string (by default), so %H:%M
matches 03:45
and the rest of the input string doesn't matter. If we turn on strict
in the constructor this'll fail. See documentation.
Assuming that the shown input is the correct part we'd need
my $strp = DateTime::Format::Strptime->new(
pattern => '%h %d %Y %I:%M:%S%3N%p'
);
Here %I
is for 12-hour clock (1-12), added %S
is for seconds and %3N
for milliseconds (see the page in docs for patterns, linked above), and %p
for AM/PM.
The rest then works as it stands, along with printing in a desired format given above.
Upvotes: 4
Reputation: 6626
There are two issues with your code. First, the pattern you use to parse your date is not correct: %H
is used for a 24-hour format hour. Instead, you should use a combination of %i
(12-hour) and %p
(AM
/PM
). Second, to print a DateTime
object, you should first format it first (using ->strftime
or ->ymd()
for instance).
The milliseconds in the date are, however, a bit of an issue because strptime
does not have a option to match milliseconds. I suggest to first remove them from your date, and only then parse the date with strptime
:
use DateTime::Format::Strptime;
my $date = 'Apr 9 2017 3:45:00:505PM';
# Removing milliseconds from date
$date =~ s/:(\d{3})(?=AM|PM)//;
my $milliseconds = $1;
my $strp = DateTime::Format::Strptime->new(pattern => '%h %d %Y %I:%M:%S%p',);
my $start_date = $strp->parse_datetime($date);
# Taking into account the milliseconds that were removed earlier
$start_date->add(seconds => 1) if $milliseconds > 500;
say $start_date->strftime("%F %T");
Upvotes: 1
Reputation: 6798
Following code demonstrates how desired output can be achieved without any modules
use strict;
use warnings;
use feature 'say';
my $date = 'Apr 9 2017 3:45:00:000AM';
my @fields = qw/month mday year hour min sec usec/;
my %months = ( Jan => 1, Feb => 2, Mar => 3,
Apr => 4, May => 5, Jun => 6,
Jul => 7, Aug => 8, Sep => 9,
Oct => 10, Nov => 11, Dec => 12
);
my %parts;
@parts{@fields} = split "[ :]+", $date;
$parts{hour} += 12 if $parts{usec} =~ /PM/;
$parts{month} = $months{ $parts{month} };
printf "%04d-%02d-%02d %02d:%02d:%02d\n",
@parts{qw/year month mday hour min sec/};
Perl code with assistance of module
use strict;
use warnings;
use feature 'say';
use DateTime::Format::DateParse;
my($date, $dt);
$date = 'Apr 9 2017 3:45:00:000AM';
$date =~ s/:(\d{3}[AP]M)/.$1/;
$dt = DateTime::Format::DateParse->parse_datetime( $date );
$date = $dt;
$date =~ s/T/ /;
say $date;
Upvotes: 1