使用Perl在日期时间格式之间转换

时间:2010-02-12 15:49:48

标签: mysql perl datetime date-conversion

我们目前正在使用以下列格式提供日期时间的第三方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日期时间字段?

提前感谢您的帮助&咨询!

4 个答案:

答案 0 :(得分:6)

将时间存储在GMT内部。在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

答案 1 :(得分:3)

存储日期时,应始终以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兼容的日期时间。

答案 2 :(得分:1)

您可能必须明确告诉DateTime构造函数您正在处理哪个时区,因为三字母和四字母代码不是唯一的而且没有标准化。

我建议从DateTime::TimeZone开始,如果在列表中找不到您要查找的内容,可能会为您的时区构建新类型。您还可以找到符合您的语法的DateTime格式化程序(其中有大量的格式化程序),但除此之外,使用正则表达式提取日期和时间字段并将其传递给DateTime构造函数并不困难。

一旦你将字符串解析为DateTime对象并正确设置了时间,将它们转换回MySQL时间戳就没有问题:只需使用DateTime::Format::MySQL

my $string = DateTime::Format::MySQL->format_datetime($dt);

答案 3 :(得分:0)

尝试使用DateTime模块。