Конвертируйте Между форматами даты и времени С помощью Perl
-
20-09-2019 - |
Вопрос
В настоящее время мы используем сторонний API, который предоставляет datetime в следующем формате:
Sat Mar 06 09:00:00 ICST 2010
Fri Feb 19 19:30:00 JDT 2010
Fri Feb 19 19:30:00 PST 2010
Однако мы хотим сохранить эти объекты datetime в MySQL в стандартном поле datetime, для которого требуется следующий формат:
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?
Заранее спасибо за вашу помощь и совет!
Решение
Храните время внутри компании в формате GMT.Выполняйте все манипуляции в GMT.Затем, в последний момент, как раз в тот момент, когда вы собираетесь отобразить результаты пользователю, тогда перевести в местное время пользователя.
Я рекомендую использовать Дата::Разбор, но вам придется увеличить смещения часовых поясов, потому что в настоящее время, например, в Индокитае нет летнего времени, а в Японии - дневного.
#! /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
Другие советы
При хранении дат вы всегда должны сохранять их в формате UTC.Таким образом, вы можете извлекать их из базы данных и преобразовывать в соответствующий часовой пояс по мере необходимости для отображения пользователю.
Для правильной обработки datetimes в Perl я от всей души рекомендую Дата - время suite, в котором есть анализаторы и форматеры для всех видов различных форматов ввода и вывода.
Я не уверен, что даты, перечисленные в вашем 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 );
Затем вы могли бы использовать Дата-время::Формат::MySQL чтобы преобразовать дату в MySQL-совместимое datetime.
Вероятно, вам придется явно указать конструктору DateTime, с какими часовыми поясами вы имеете дело, поскольку трех- и четырехбуквенные коды не уникальны и не стандартизированы.
Я бы предложил начать с Дата и время::Часовой пояс, и, возможно, создание новых типов для ваших часовых поясов, если вы не можете найти то, что ищете, в списке.Вы также можете найти средство форматирования DateTime, соответствующее вашему синтаксису (их существует огромное количество), но в остальном нетрудно просто использовать регулярное выражение для извлечения полей даты и времени и передачи их конструктору DateTime.
Как только вы обработаете свои строки в объекты DateTime с правильно установленным временем, совсем не составит труда преобразовать их обратно в метки времени MySQL:просто используй Дата-время::Формат::MySQL:
my $string = DateTime::Format::MySQL->format_datetime($dt);
Попробуйте использовать Дата - время модуль.