2010-02-12 68 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