2010-02-12 62 views
5

我们目前正在使用第三方API,它提供了以下格式的日期时间:转换日期时间格式之间使用Perl

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这些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代码来将API中的日期时间对象转换为正确的格式和时间在我们的服务器上插入MySQL日期时间字段吗?

在此先感谢您的帮助&意见!

+3

一个很好的开始:http://datetime.perl .org /?模块 – 2010-02-12 15:53:36

回答

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

支持你想查询,存储在格林尼治标准时间加上偏移(,从格林尼治标准时间从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
+0

@gbacon - 这正是我所期待的。最后一个问题。然后,我必须显示该项目与API最初给定的时区相同的时区。你会推荐什么样的格式我将时区存储在我的MySQL表中,以便轻松地转换回来,并且还可以使用什么Perl代码将GMT和时区中存储的日期时间转换为格式,例如“2010年2月19日,星期五 - JDT 2:30 pm“? – 2010-02-12 17:10:33

+0

@gbacon - 如果有一种方法可以在MySQL中以一种方式存储时区,该方式可以让我执行一个查询,该查询将返回存储在本地日期时间的日期时间(格林尼治标准时间),只需一个SQL查询(无perl)可能会是一个更好的解决方案。 – 2010-02-12 17:20:47

+0

@Russell本地日期时间?与API或托管数据库的计算机所提供的时间相同吗? – 2010-02-12 18:25:18

0

尝试使用DateTime模块。

+0

@vivin - 您能否提供更多的细节。我只是将我们使用的代码添加到原始问题中。任何想法为什么DateTime似乎不能转换某些时区? – 2010-02-12 16:07:27

+0

我会以UTC时间存储数据。我不确定我是否理解你的问题 - 你想知道如何处理将日期插入到MySQL数据库中吗? – 2010-02-12 16:09:30

+0

我刚更新了这个问题,使其更加清晰。我的问题基本上可以提供一个更好的perl实现来将API提供的日期时间转换为正确的日期时间格式,以插入到MySQL日期时间字段中。 – 2010-02-12 16:19:00

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兼容的日期时间。

+0

我们目前使用的是DateTime,但由于某些原因,它似乎无法处理某些时区,并报告了KDT,JDT,ICST等的错误。我不知道是否有模块有更广泛的支持? – 2010-02-12 16:00:01

+0

我刚刚添加了我们当前使用原始问题的代码。任何想法为什么DateTime似乎无法处理某些时区? – 2010-02-12 16:05:48

+1

不幸的是我不知道如何让它支持这样的时区;它们不会出现在DateTime :: TimeZone模块的列表中(http://search.cpan.org/~drolsky/DateTime-TimeZone-1.10/)。您可能需要将它们转换为Olson风格的名称,如KDT =>'Asia/Seoul' – friedo 2010-02-12 16:19:36

1

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

我建议从DateTime::TimeZone开始,如果在列表中找不到要查找的内容,则可能会为时区创建新类型。你也可以找到一个符合你的语法的DateTime格式器(它们的数量很多),但是否则简单地使用正则表达式来提取日期和时间字段并将它传递给DateTime构造函数并不困难。

一旦你得到了你的字符串解析与正确设置的时间datetime对象,这是一点问题都没有将它们转换回来了到MySQL时间戳:只需使用DateTime::Format::MySQL

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

@Ether - 谢谢!由于共识似乎是我需要以UTC格式存储这些日期,您是否可以提供一些示例perl代码来说明一旦我拥有适当的DateTime对象后我该怎么做? – 2010-02-12 16:33:03

+0

您不必将它们存储在UTC中,但如果您使用日期时间进行数学计算,则会看到性能提高。但是,您需要做的是将正确的时区字符串传递给DateTime构造函数,例如, '$ my $ dt = DateTime-> new(...,timezone =>'America/Los_Angeles');' – Ether 2010-02-12 17:05:04