5

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

4 回答 4

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

输出:

2010 年 3 月 6 日星期六 09:00:00 ICST => 2010-03-06 02:00:00
2 月 19 日星期五 19:30:00 JDT 2010 => 2010-02-19 10:30:00
2010 年 2 月 19 日星期五 19:30:00 PST => 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 用户名 -D 数据库名
CONVERT_TZ(日期,'+00:00',偏移量)
2010-03-06 09:00:00
2010-02-19 19:30:00
2010-02-19 19:30:00
于 2010-02-12T16:59:31.473 回答
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 兼容的日期时间。

于 2010-02-12T15:56:54.887 回答
1

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

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

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

my $string = DateTime::Format::MySQL->format_datetime($dt);
于 2010-02-12T16:29:37.063 回答
0

尝试使用DateTime模块。

于 2010-02-12T15:55:43.873 回答