Я написал этот вопрос, но не опубликовал его до разработки решения. Вот то, что я придумал для двусмысленности - я надеюсь, что это помогает кому-то еще. Особая благодарность @ikegami за предоставление примеров использования Strptime и strftime для создания окончательного вывода в формате UT C. Это весь сценарий, начиная с формата отметки времени, например «11/03/19 01: 00: 00A». В этом примере записи данных обрезаются до отметки времени, удаляя следующие данные.
#!/usr/bin/perl
# Parse local time stamped data files save in UTC Time
use strict;
use warnings;
use File::Basename;
use Time::Piece;
use Time::Local;
use feature qw( say );
use DateTime::Format::Strptime qw( );
STDOUT->autoflush(1);
my $format = DateTime::Format::Strptime->new(
pattern => '%m/%d/%y %I:%M:%S%p %Z',
locale => 'en',
zone_map => { CST => '-0600', CDT => '-0500' }, # Handle non-standard time zone names.
time_zone => 'America/Chicago', # Optional. Convert result to this tz.
strict => 1,
on_error => 'croak',
);
# Input file from command line.
open (INFILE, $ARGV[0])
or die "Error cannot open $ARGV[0]: $!";
print "Opening $ARGV[0] for input ";
my $base = fileparse($ARGV[0],'\..*');
my $outfname = $base.'.csv';
if ( defined $ARGV[1] ) { # If a 2nd paramater is given, use it for the output file
open (OUT, '>'.$ARGV[1]);
} else {
open (OUT, '>'.$outfname); # Else name the output file with .csv
print "opening $outfname for output\n";
}
my $prev_outtemp = 0;
my $lastparsedtime = 0;
my $ForceStdTime = 0;
while (<INFILE>) {
chomp;
my $workline = $_;
$workline=~ s/^\s+|\s+$//g; # trim leading/trailing space
my @pline = split(/ /,$workline); #split input line into elements @pline[0] @pline[1] etc
$pline[1] =~ s/A/AM/; # change A and M to AM/PM
$pline[1] =~ s/P/PM/;
my $timestampstr = $pline[0]." ".$pline[1];
# 12/31/09 08:40:00AM
my $parsedtime = Time::Piece->strptime($timestampstr, '%m/%d/%y %I:%M:%S%p');
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($parsedtime);
my $tltime = timelocal( $sec, $min, $hour, $mday, $mon, $year );
$year += 1900;
$mon += 1;
my ($dst) = (localtime($tltime))[8]; # fetch daylight savings time flag
if ( $parsedtime < $lastparsedtime ) { # Time discontinuity
$ForceStdTime = 1; # force standard time during 1 hour in spring
}
$lastparsedtime = $parsedtime;
my $dtlocaltag = "";
if ($dst and not $ForceStdTime) {
$dtlocaltag = "\"$pline[0] $pline[1] CDT\"";
}
else {
$dtlocaltag = "\"$pline[0] $pline[1] CST\"";
}
print "$dtlocaltag ";
if (not $dst) {
$ForceStdTime = 0; # reset force flag once localtime sees standard time
}
my $dt = $format->parse_datetime($dtlocaltag);
my $epoch = $dt->epoch;
my $local_dt_str = $dt->strftime("%Y-%m-%dT%H:%M:%S%z");
$dt->set_time_zone('UTC');
my $utc_dt_str = $dt->strftime("%Y-%m-%dT%H:%M:%SZ");
print " $local_dt_str $utc_dt_str\n";
print OUT "\"$utc_dt_str\"";
# --- snip --- processing of rest of data in text input line....
print OUT "\n";
} # end of while loop
close (INFILE);
close(OUT);
Файл входных данных выглядит следующим образом:
11/03/19 12:50:00A
11/03/19 01:00:00A
11/03/19 01:10:00A
11/03/19 01:20:00A
11/03/19 01:30:00A
11/03/19 01:40:00A
11/03/19 01:50:00A
11/03/19 01:00:00A
11/03/19 01:10:00A
11/03/19 01:20:00A
11/03/19 01:30:00A
11/03/19 01:40:00A
11/03/19 01:50:00A
11/03/19 02:00:00A
11/03/19 02:10:01A
03/08/20 12:50:00A
03/08/20 01:00:00A
03/08/20 01:10:00A
03/08/20 01:20:00A
03/08/20 01:30:00A
03/08/20 01:40:00A
03/08/20 01:50:00A
03/08/20 03:00:00A
03/08/20 03:10:00A
Файл выходных данных выглядит следующим образом:
"2019-11-03T05:50:00Z"
"2019-11-03T06:00:00Z"
"2019-11-03T06:10:00Z"
"2019-11-03T06:20:00Z"
"2019-11-03T06:30:00Z"
"2019-11-03T06:40:00Z"
"2019-11-03T06:50:00Z"
"2019-11-03T07:00:00Z"
"2019-11-03T07:10:00Z"
"2019-11-03T07:20:00Z"
"2019-11-03T07:30:00Z"
"2019-11-03T07:40:00Z"
"2019-11-03T07:50:00Z"
"2019-11-03T08:00:00Z"
"2019-11-03T08:10:01Z"
"2020-03-08T06:50:00Z"
"2020-03-08T07:00:00Z"
"2020-03-08T07:10:00Z"
"2020-03-08T07:20:00Z"
"2020-03-08T07:30:00Z"
"2020-03-08T07:40:00Z"
"2020-03-08T07:50:00Z"
"2020-03-08T08:00:00Z"
"2020-03-08T08:10:00Z"