Преобразуйте между форматами даты и времени Используя Perl

Мы в настоящее время используем третью сторону API, который обеспечивает дату и время в следующем формате:

Sat Mar 06 09:00:00 ICST 2010
Fri Feb 19 19:30:00 JDT 2010
Fri Feb 19 19:30:00 PST 2010

Однако мы хотим хранить эти объекты даты и времени в MySQL в стандартном поле даты и времени, которое требует следующего формата:

YYYY-MM-DD HH:MM:SS

Прямо сейчас мы используем следующий код, который сообщает об ошибках для определенных часовых поясов, таких как KDT, JDT и ICST:

use Date::Manip;
use DateTime;
use DateTime::Format::DateManip;

my $date = ParseDate($time);
$date = DateTime::Format::DateManip->parse_datetime($date);
eval{ $time = $date->strftime("%Y-%m-%d %H:%M:%S"); };

Можно ли рекомендовать лучшей реализации кода Perl выше преобразовать объекты даты и времени от API до соответствующего формата и время на нашем сервере, который будет вставлен в поле даты и времени MySQL?

Заранее спасибо за Вашу справку и совет!

5
задан Russell C. 12 February 2010 в 16:17
поделиться

4 ответа

Сохранять время внутри по Гринвичу. Все манипуляции делайте в GMT. Затем в последний момент, когда вы собираетесь отобразить результаты для пользователя, , затем конвертируются в местное время пользователя.

Я рекомендую использовать Date :: Parse , но вам придется увеличить смещение его часового пояса, потому что сейчас, например, нет Индокитайского летнего времени и Японского летнего времени.

#! /usr/bin/perl

use warnings;
use strict;

use Date::Format;
use Date::Parse;

# add timezone offsets
$Time::Zone::Zone{icst} = +7*3600;
$Time::Zone::Zone{jdt}  = +9*3600;

while (<DATA>) {
  chomp;
  warn("$0: failed conversion for $_\n"), next
    unless defined(my $time_t = str2time $_);

  my @t = gmtime($time_t);
  print $_, " => ", strftime("%Y-%m-%d %H:%M:%S", @t), "\n";
}

__DATA__
Sat Mar 06 09:00:00 ICST 2010
Fri Feb 19 19:30:00 JDT 2010
Fri Feb 19 19:30:00 PST 2010

Вывод:

Sat Mar 06 09:00:00 ICST 2010 => 2010-03-06 02:00:00
Fri Feb 19 19:30:00 JDT 2010 => 2010-02-19 10:30:00
Fri Feb 19 19:30:00 PST 2010 => 2010-02-20 03:30:00

Для поддержки желаемого запроса сохраните время в GMT плюс смещение ( то есть , от GMT до местного времени из API). Обратите внимание, что в приведенном ниже коде предполагается, что если str2time может анализировать заданное время, то strptime тоже может. Измените цикл на

my @dates;
while (<DATA>) {
  chomp;
  warn("$0: failed conversion for $_\n"), next
    unless defined(my $time_t = str2time $_);

  my $zone = (strptime $_)[-1];
  my @t = gmtime($time_t);
  push @dates => [ strftime("%Y-%m-%d %H:%M:%S", @t)
                 , sprintf("%+03d:%02d",
                           int($zone / 3600),
                           int($zone % 3600) / 60)
                 , $_
                 ];
}

С собранным временем визуализируйте его как SQL:

print "DROP TABLE IF EXISTS dates;\n",
      "CREATE TABLE dates (date DATETIME, offset CHAR(6));\n",
      "INSERT INTO dates (date,offset) VALUES\n",
        join(",\n\n" =>
          map("  -- $_->[2]\n" .
              "  ('$_->[0]','$_->[1]')", @dates)),
        ";\n",
      "SELECT CONVERT_TZ(date,'+00:00',offset) FROM dates;\n"

Результатом будет

DROP TABLE IF EXISTS dates;
CREATE TABLE dates (date DATETIME, offset CHAR(6));
INSERT INTO dates (date,offset) VALUES
  -- Sat Mar 06 09:00:00 ICST 2010
  ('2010-03-06 02:00:00','+07:00'),

  -- Fri Feb 19 19:30:00 JDT 2010
  ('2010-02-19 10:30:00','+09:00'),

  -- Fri Feb 19 19:30:00 PST 2010
  ('2010-02-20 03:30:00','-08:00');
SELECT CONVERT_TZ(date,'+00:00',offset) FROM dates;

, и мы можем передать его по конвейеру mysql :

$ ./prog.pl | mysql -u username -D dbname
CONVERT_TZ(date,'+00:00',offset)
2010-03-06 09:00:00
2010-02-19 19:30:00
2010-02-19 19:30:00
6
ответ дан 13 December 2019 в 22:07
поделиться

Вероятно, вам придется явно указать конструктору DateTime, с каким(и) часовым(и) поясом(ами) вы имеете дело, поскольку трех- и четырехбуквенные коды не уникальны и не стандартизованы.

Я бы предложил начать с DateTime::TimeZone, и, возможно, создать новые типы для ваших часовых поясов, если вы не сможете найти то, что ищете в списке. Вы также можете найти форматтер DateTime, который соответствует вашему синтаксису (их существует огромное количество), но в остальном несложно просто использовать regex для извлечения полей даты и времени и передать их в конструктор DateTime.

После того, как вы разобрали свои строки на объекты DateTime с правильно установленным временем, не составит труда преобразовать их обратно в временные метки MySQL: просто используйте DateTime::Format::MySQL:

my $string = DateTime::Format::MySQL->format_datetime($dt);
1
ответ дан 13 December 2019 в 22:07
поделиться

Попробуйте использовать модуль DateTime .

0
ответ дан 13 December 2019 в 22:07
поделиться

При хранении дат, вы всегда должны хранить их в UTC. Таким образом, вы сможете получить их из базы данных и преобразовать в соответствующий часовой пояс, если это необходимо для отображения пользователю.

Для правильной работы с датами в Perl я от души рекомендую набор DateTime, в котором есть парсеры и форматеры для всевозможных форматов ввода и вывода.

Я не уверен, являются ли даты, перечисленные в вашем OP, стандартным форматом, но если нет, то будет довольно просто создать из них формат DateTime:

my $str = 'Sat Mar 06 09:00:00 ICST 2010';
my ( $month, $day, $hour, $min, $sec, $tz, $year ) = ( $str =~ m{\w{3}\s(\w{3})\s(\d{2})\s(\d{2}):(\d{2}):(\d{2})\s(\w+)\s(\d{4})} );

my $dt = DateTime->new( year => $year, month => $month, day => $day, 
                        hour => $hour, minute => $min, second => $sec, 
                        time_zone => $tz );

Затем вы можете использовать DateTime::Format::MySQL для преобразования даты в совместимое с MySQL время.

3
ответ дан 13 December 2019 в 22:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: