Преобразование между форматами даты и времени с использованием Perl - PullRequest
5 голосов
/ 12 февраля 2010

В настоящее время мы используем сторонний 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 для преобразования объектов datetime из API в надлежащий формат и время на нашем сервере для вставки в поле datetime MySQL?

Заранее спасибо за помощь и советы!

Ответы [ 4 ]

6 голосов
/ 12 февраля 2010

Храните время внутри по Гринвичу. Делайте все манипуляции в 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
3 голосов
/ 12 февраля 2010

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

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

Я не уверен, что даты, указанные в вашем ОП, являются стандартным форматом, но если нет, то из них было бы довольно просто построить формат 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-совместимую дату и время.

1 голос
/ 12 февраля 2010

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

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

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

my $string = DateTime::Format::MySQL->format_datetime($dt);
0 голосов
/ 12 февраля 2010

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

...