Как получить DateTime :: Format :: Strptime для анализа даты / времени високосных секунд? - PullRequest
3 голосов
/ 24 марта 2020

Я пытаюсь использовать DateTime::Format::Strptime для анализа некоторых дат / времени, и я не могу заставить его анализировать дату / время для високосных секунд (например, 2012-06-30T23: 59: 60UT C). В документации говорится, что он поддерживает до 60 секунд для високосных секунд. Что я делаю не так?

Вот мой код:

use DateTime;
use DateTime::TimeZone;
use DateTime::Format::Strptime;

my $utc = DateTime::TimeZone->new(name => 'Etc/UTC');

my $ymdhms_parser = DateTime::Format::Strptime->new(pattern => '%F %T',
                                                    locale => 'en_US',
                                                    time_zone => $utc,
                                                    strict => 1,
                                                    on_error => 'croak');

my $date = '2012-06-30 23:59:60';
print "date: $date\n";
my $dt = $ymdhms_parser->parse_datetime($date);
print "dt: $dt\n";
print "tz: ",$dt->time_zone,"\n";

Вывод, который я получаю:

date: 2012-06-30 23:59:60
Parsed values did not produce a valid date at /path/to/test.pl line 14.

Версии:

DateTime 1.52
DateTime::LeapSecond 1.52
DateTime::Format::Strptime 1.77

1 Ответ

2 голосов
/ 25 марта 2020

Следующее работает как задумано:

my $dt = DateTime->new(
   year      => 2012,
   month     =>    6,
   day       =>   30,
   hour      =>   23,
   minute    =>   59,
   second    =>   60,
   time_zone => $utc,
);

Однако вызов parse_datetime эффективно делает следующее:

my $dt = DateTime->new(
   year      => 2012,
   month     =>    6,
   day       =>   30,
   hour      =>   23,
   minute    =>   59,
   second    =>   60,
   time_zone => 'floating',
);

$dt->set_time_zone($utc);

Выше приведено DateTime->new к метанию исключение, которое приводит к получению сообщения об ошибке.

Но я не могу ошибиться DateTime :: Format :: Strptime.

Часовой пояс, найденный в анализируемой строке (например, если используется %z), передается в ->new, а часовой пояс, передаваемый в конструктор, передается в ->set_time zone. Это позволяет выполнять преобразование часового пояса, когда часовой пояс указан в обоих местах.

Например, допустим, что входное значение равно 2020-03-25T00:00:00-05:00 (обратите внимание на смещение). И скажем, вы передали time_zone => 'UTC' и соответствующий шаблон в конструктор. Результирующий объект DateTime будет для 5 утра UT C вместо полуночи UT C -05: 00. Это хорошо.


Интересно, что можно создавать объекты DateTime с использованием плавающего часового пояса с 60 в течение секунд.

$ perl -MDateTime -e'
   CORE::say
      DateTime
         ->new(
            year      => 2012,
            month     =>    6,
            day       =>   30,
            hour      =>   23,
            minute    =>   59,
            second    =>   60,
            time_zone => "UTC",
         )
            ->set_time_zone("floating");
'
2012-06-30T23:59:60

Но DateTime противоречиво разрешает it.

$ perl -MDateTime -e'
   CORE::say
      DateTime
         ->new(
            year      => 2012,
            month     =>    6,
            day       =>   30,
            hour      =>   23,
            minute    =>   59,
            second    =>   60,
            time_zone => "floating",
         );
'
Invalid second value (60)
 at -e line 1.

Подано сообщение об ошибке.


В качестве обходного пути включите часовой пояс в анализируемые данные.

my $ymdhms_parser = DateTime::Format::Strptime->new(
   pattern  => '%F %T%z',
   locale   => 'en_US',
   strict   => 1,
   on_error => 'croak',
);

my $dt = $ymdhms_parser->parse_datetime($date.'Z');
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...