1
Feb   2 2016 12:00AM
Feb 15 2015 05:00PM 

Would like to convert the above data to 'YYYY-MM-DD TT:TT:TT' format, ideally:

2016-02-02 00:00:00

Here's what I've tried using a substitution to convert it. The reason I have two different ones is because when I BCP out my data into a text file the dates with single digit uses a space instead of a 0 in front of it:

s/Feb  (\d{1}) (\d{4}) (\d{2})(\:\d{2})AM/2-$1-2 $3$4/g;

s/Feb (\d{2}) (\d{4}) (\d{2})(\:\d{2})AM/2-$1-2 $3$4/g;

Also I am not sure how I would go about converting the time to military time and also would there be a more efficient way to do all 12 months rather then have 12 lines of substitution for all of them, in this case there would be 24.

fugu
  • 6,417
  • 5
  • 40
  • 75
Gary
  • 129
  • 10

2 Answers2

4

Some people prefer Time::Piece because it comes bundled with Perl, but it's so easy to get things wrong with that modules. I strongly recommend using a module that doesn't confuse the experts, such as DateTime.

use strict;
use warnings qw( all );
use feature qw( say );

use DateTime::Format::Strptime qw( );

my $format = DateTime::Format::Strptime->new(
   pattern    => '%b %d %Y %I:%M%p',
   #time_zone => 'local',
   on_error   => 'croak',
);

for ('Feb 2 2016 12:00AM', 'Feb 15 2015 05:00PM') {
   say $format->parse_datetime($_)->strftime('%Y-%m-%d %H:%M:%S');
}

Output:

2016-02-02 00:00:00
2015-02-15 17:00:00
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • Preemptive answer to "What's wrong with Time::Piece?": 1) It's not portable (it relies on your locale settings so you can get different results running the same operations on different systems), e.g. http://stackoverflow.com/q/36630667 (uses Time::Local, which has the same problem) 2) `Time::Piece->strptime` coerces everything to UTC, even if you pass a timezone with `%z`; you have to use the undocumented `localtime->strptime` instead. 3) `strptime` silently "fixes" invalid dates, e.g. 2016-02-31 -> 2016-03-02 – ThisSuitIsBlackNot Jul 21 '16 at 19:18
  • 4) Time::Seconds::ONE_YEAR is wrong (based on a proposal for leap years that has never actually been adopted). And so on. – ThisSuitIsBlackNot Jul 21 '16 at 19:18
  • 2
    @ThisSuitBlackNot, You should ask-and-answer "Why do some people discourage the use of Time::Piece?" (*Time::Piece, the XML::Simple of the date-time world!®*) – ikegami Jul 21 '16 at 19:31
  • Good idea. Do you have anything to add to the list? – ThisSuitIsBlackNot Jul 21 '16 at 19:33
  • 2
    My number one reason for hating it is because it's too easy to use incorrectly. For example, `localtime(time + ONE_DAY)` and `localtime(time) + ONE_DAY` appear interchangeable, but only the latter is correct. – ikegami Jul 21 '16 at 19:34
  • 1
    @ThisSuitIsBlockNot, Correction: Neither is correct! `TZ=America/New_York perl -MTime::Piece -MTime::Seconds=ONE_DAY -E'$_=localtime(1457773200); say; $_ += ONE_DAY; say;'` – ikegami Jul 21 '16 at 19:43
4

The Time::Piece module is convenient for this sort of thing

The strptime class method takes a date-time string and a format specification that it uses to parse the string to create a new object. Meanwhile the strftime method will return a date-time string according to another format specification

use strict;
use warnings 'all';

use Time::Piece ();

while ( <DATA> ) {
    chomp;
    my $new_dt = Time::Piece->strptime($_, '%b %d %Y %H:%M%p')->strftime('%Y-%m-%d %H:%M:%S');
    printf "%s --> %s\n", $_, $new_dt;
}

__DATA__
Feb 2 2016 12:00AM
Feb 15 2015 05:00PM

output

Feb 2 2016 12:00AM --> 2016-02-02 00:00:00
Feb 15 2015 05:00PM --> 2015-02-15 17:00:00
Borodin
  • 126,100
  • 9
  • 70
  • 144