取得日期和時間
進入處理日期和時間的模組之前,讓我們快速回顧Perl 內建的日期和時間處理工具。
取得當地目前的日期和時間的主要函式是local time。當以純量內容(scalar context)的方式來處理時,localt ime 會以字串的型式傳回目前的時間和日期:print scalar localtime, "n";
這會以下列的格式印出字串:day month date time year,並產生下面的輸出:Mon Feb 2 13:23:00 1998
localt ime 函式可以選擇性的接受UNIX 的時間參數。時間的值是一個從1970 年1月1 日至今以秒計算的整數值。
你如果熟悉C 的time 函式,你就會知道localtime也高明不到哪裡去,一樣非常煩人。
如果你不提供一個時間值(time value)給localt ime 函式,它會呼叫Per l 的time 函式。
你也可以以串列內容(list context)的方式使用localtime 函式,它會產生下面的值:
($sec, $min, $hour, $mday, $mon, $year,, $wday, $yday, $isdst) = localtime;
localtime 的值 |
|
時間元素 |
說明 |
$sec |
秒 |
$min |
分 |
$hour |
小時 |
$mon |
月 |
$year |
目前的年減去1900 ,不是僅將19xx 年的19去掉,因此不會有Y2K的困擾 |
$wday |
每週的日期(如Sunday 是0 ) |
$yday |
每年的日期(如Jan1 是0 ) |
$isdst |
如果日光節約時間使用則是正值,其它為0 。 |
我想說明的是,$year 在2000 年後仍然有效。到了公元2000 年,$year 將會是100而不是0。
使用Net::Time
我們第一個使用的日期和時間模組是Net::Time,它用來從遠端系統取得日期和時間。這個模組比較特殊的地方是,Net::Time是時間協定RFC868和日期協定RFC867 的介面。inet_time函式應用這個時間協定並且傳回一個Unix的時間值,而inet_daytime函式應用日期協定並傳回人們瞭解的時間值。
這兩個函式有同樣的介面:參數分別是遠端機器的名稱,所使用的網路協定(TCP或UDP),和逾時值(timeout value)。
若沒有任何參數,我們會試著連接區域的主機,使用UDP協定並且以120秒當時間限制。雖然看起來十分簡單,但這些函式只有在這些機器使用這個協定下才會成功執行。完全看你的工作站或是機器的設定。
範例time.pl:使用Time協定
use Net::Time qw(inet_time);
use strict;
my $host = shift || 'localhost';
my $host_time = inet_time($host, 'tcp', 10);
if($host_time) { print "Time on $host is $host_timen"; }
else { print "inet_time failed: $!"; }
在主機上(名稱為somehos t)執行此範例會產生下面的輸出:Time on somehost is 886452598
範例daytime.pl:使用Daytime 協定
use Net::Time qw(inet_daytime);
use strict;
my $host = shift || 'localhost';
my $host_time = inet_daytime($host, 'tcp', 10);
if($host_time) { print "Time on $host is $host_timen"; }
else { print "inet_daytime failed: $!"; }
在同樣的主機上執行,會產生下面的輸出:Time on somehost is Mon Feb 2 13:52:19 1998
日期和時間的表示法
暫停一下,回想你曾經見過的日期表示法。舉例來說,1998年7月21日可以被表示成7/21/98,21/7/98,21-July-1998,21.7.1998 和21-JUL-1998 等等。幸虧有一個國際的日期表示標準稱為ISO8601。它的表示法是:YYYY-MM-DD YYYY 是表示年份,MM 表示月份,DD 是表示日期。
國際標準的時間表示法是:hh:mm:ss
hh 是表示幾點(0-23),mm 是表示分鐘,ss 是表示秒鐘。如果時間未加修飾,則表示當地時間;在後面加上Z 則表示zero mer idian,這個時間是U niversal 時間(UTC )。
我們已經看過Unix的時間,而Perl時間是表示成從1970-1-1 至今經過的秒數。所以現在的UTC 時間是寫成886457054,或是Mon Feb 2 22:04:14 1998。
Date::Format
Date::Format 可以將日期轉換成字串。它提供的方法相對於C函式庫的strftime和ctime。
Date::Format 提供的函式是time2str〔其參數為格式樣版(format template)和(Unix時間)和strftime(其參數為格式樣版和一連串的時間值(例如由localtime所傳回的陣列)〕。
這兩個函式都使用同樣的格式指定方式
日期格式的指定方式 |
|
格式指定元 |
說明 |
%% |
插入百分號 |
%a |
縮寫的星期幾, 如Mon |
%A |
完整的星期幾, 如Monday |
%b |
縮寫的月份,如Jan |
%B |
完整的月份,如January |
%c |
ctime 的日期和時間的表示方式, 如02/03/98 02:43:11 |
%d |
每個月第幾天,使用兩位數表示(01-31),如03 |
%e |
每個月第幾天,使用整數表示(1 - 31),如3 |
%D |
mm/dd/yy 格式, 如02/03/98 |
%h |
縮寫的月份,如Jan |
%H |
使用24小時的時間格式(00 - 23) |
%I |
使用12小時的時間格式(01 - 12) |
%j |
每年的日期,使用三位數表示(001 - 366 ) |
%k |
用24 小時的時間格式(0 -23 ) |
%l |
使用12小時的時間格式(01 - 12) |
%m |
月,使用整數表示(1 - 12) |
%M |
分鐘,使用兩位數表示( 00-59 ) |
%n |
換行字元 |
%o |
每月的第幾天, 如1st,2nd |
%p |
am或pm |
%r |
時間格式:02:51:50am |
%R |
時間格式:02:51 |
%s |
從1970-1-1起算經過多少秒(UTC),如8866499802 |
%S |
使用兩位數表示的秒(00 - 59) |
%t |
tab字元 |
%T |
時間格式: 02:56:42 |
%U |
每年第幾個禮拜(01-51),星期天是每個禮拜第一天 |
%w |
星期幾用十進位表示(0-6 ) |
%W |
每年第幾個禮拜(01-51),星期一是每個禮拜第一天 |
%x |
日期表示02/03/98 |
%X |
時間表示02:56:42 |
%y |
不表示世紀的年(00-99 ) |
%Y |
表示世紀的年,如1998 |
Z |
%ASCII時區的縮寫,如PST、EST |
%z |
時區,使用-/+0000 的格式 |
Date::Format 也包含函式ctime 和asctime,功能與使用格式指定字串“%a %b %e %T %Yn”來呼叫time2str及strftime函式相同。Date::Format也可以格式化成數個不同的語言,請看模組文件內附的完整說明。
Time::Zone
我們已經介紹過時間和日期的表示法,為了完整性,我們將討論時區。時區一般是以三個字元表示,如GMT、PST 、或EST。這種表示法並非是標準,全世界各地可能有不同的表示法。
有一個國際時區的標準表示法:單一字元碼(one-character code)(請看世界時區圖http://aa.usno.navy.mil/AA/faq/docs/world_tzones.html)。至於正式的Internet 時區標準,請參看ftp://elsie.nci.nib.gov/pub/。我回頭介紹每個人真正使用的時區表示方式。
Time::Zone 模組所提供的服務是關於時區的處理。它可以解析TZ 環境變數,決定本地或某一特定時區與GMT的秒偏差(off set in seconds)。給定與GMT 的秒偏差,它也可以產生時區的表示方式。
tz2zone函式解析TZ環境變數(或是一個選擇性的時區引數),並產生適合顯示的輸出。
下面範例中,程式以不同的格式當作參數呼叫tz2zone,所以你可以看它對各種格式所做出的反應。
範例tz2zone: 時區顯示方式的示範
use Time::Zone;
use strict;
print tz2zone('MST'), "n"; # just use MST
print tz2zone('MST7MDT'), "n"; # give it a full
# zone-offset-daylight zone string
print tz2zone('MST7MDT', undef, 1), "n"; # lie and make it think
# it's daylight savings time
這會產生下面的輸出(在標準時間的機器上執行):
MST
MST
MDT
要找出GMT和MST( Mountain Standard Time)的秒偏差, 我們可以使用tz_offset函式(若要取得與目前時區的秒偏差,可以使用tz_local_of fset)。
範例tzoffset.pl:示範如何顯示時區之間的秒偏差
use Time::Zone;
use strict;
my $time_zone = 'MST';
my $offset = tz_offset($time_zone);
print "$time_zone is ", $offset/3600, " hours from GMTn";
輸出如下:
MST is –7 hour from GMT
tz_name函式根據偏差來決定時區的名稱。所以給定一個和GMT 的偏差值(以秒作單位),tz_time會做出時區的表示。
範例:tzlist.pl:時區顯示程式
use Time::Zone;
use strict;
my ($tz);
for (-12 .. 12) {
$tz = tz_name($_ * 3600); # convert hours to seconds
print "$tz: $_ n"; # but print hours, since that's
} # easier to understand
Date::Parse
Date::Parse模組的功能和Date::Format 相反,也就是給一個日期敘述的字串,它會傳回一個用秒表示的日期值,或是一個日期元素的陣列。
範例dateparse.pl:Date::Parse的使用範例
use Date::Parse;
use strict;
my $date_expr = "Feb 3 1998 03:06:32";
print str2time($date_expr), "n"; # prints seconds since the epoch
print join(" ", strptime($date_expr), "n"); # prints list of date elements
它會產生下面的輸出:
886500392
32 06 03 03 02 98
如同Date::Format,Date::Parse可以處理不同語言的日期。
Date::DateCalc
Date::DateC alc 可用來解析及計算與ISO/R 2015-1971 和DIN 1355 標準相容的日期。例如,你可以增加日期使用calc_new_dat e 的函式或是利用check_date 函式檢查一個日期是否合法。範例4-7 使用calc_new_date 函式將日期增加30 天。
範例datecalc.pl: Date::DateCalc 範例
use Date::DateCalc qw(calc_new_date date_to_string);
use strict;
my ($year, $month, $day) = (1998, 2, 14); # start with Valentine's
Day($year, $month, $day) = calc_new_date($year, $month, $day, 30);
print date_to_string($year, $month, $day), "n";
這產生下面的輸出:
Monday, 16 March 1998
你也可以使用dates_dif ference 去找出耶誕節和萬聖節之間隔了多少天。
範例datediff.pl:使用dates_difference 函式
use Date::DateCalc qw(dates_difference);
use strict;
my ($y1, $m1, $d1) = (1998, 10, 31); # specify dates in their
my ($y2, $m2, $d2) = (1998, 12, 25); # normal chronological order
print "There are ",
dates_difference($y1, $m1, $d1, $y2, $m2, $d2)," days between Christmas and Halloweenn";
Date::Manip
最後一個模組是Date::Manip,它是另一個方便的日期解析器和計算器。Date::Manip比Date::DateCalca更進一步,它讓你處理日期表示法(date expression),像是“today”和“+3 business days”甚至“3rd Sunday in June 1998”【譯註】。Date::Manip 甚至可以讓你將假期和一些特殊的日期儲存在一個檔案中,在表示法中直接使用這些設定的日期。
使用Date::Manip之前必須做些準備工作:確定它可以從TZ環境變數推論出時區。如果你不能或不願意設定這個變數,你可以自行告訴Date::Manip時區是使用$Date::Manip::TZ 變數。然而當你如此做時,若沒有這個變數,Date::Manip 可能無法順利執行。
ParseDate 函式接受很多不同形式的日期串列,並且以下面的格式傳回日期串列:YYYYMMDDHH:MM:SS
下面的例子顯示一些ParseDate可以處理的日期格式:
use Date::Manip;
use strict;
my $dt;
$dt = ParseDate('today');
$dt = ParseDate('tomorrow');
$dt = ParseDate('third Sunday in June 1998');
$dt = ParseDate('June 21 1998');
$dt = ParseDate('last Thursday');
$dt = ParseDate('in 2 months');
如果傳給par sedate 的參數是它無法處理的格式,它會傳回undef:$dt = ParseDate("When Hell freezes over"); # dt will be undef
除了處理日期之外,Date::Manip提供一個UnixDate函式將日期格式化。和 Date::Format函式類似,UnixDate 讀取一個日期字串(如同ParseDate 傳回的)和特殊格式的指定字,並且傳回一個相對於每一個格式的陣列。
範例today.pl:使用ParseDate 函式
use Date::Manip;
use strict;
print UnixDate(ParseDate('today'), "%c"), "n";
這會產生下面的結果:
Tue Feb 3 04:21:16 1998
UnixDate 額外的日期指定格式 |
|
格式指定字 |
敘述 |
%E |
每月的日期(例如1st, 2nd , 3rd) |
%f |
月,用整數表示(例如1 - 12) |
%F |
%A %B %e , %Y (例如Tuesday, February 3 ,1 9 98 ) |
%g |
%a , %d %b %Y %H :%M:%S :%z( 例如Tue, 03 Feb 1998 0 4:27:33 MST ) |
%i |
小時, 使用1-12 的格式, 例如4 |
%l |
如果在六個月內則日期使用%b %e %H:%M 的格式,否則使用%b %e %y。 |
%P |
%Y%m%d%H %:%M:%S (例如1998 0 20 30 4:27:33) |
%q |
%Y%m%d%H%M%S (例如1998 02 0 30 4 27 33 ) |
%Q |
%Y%m%d (例如1998 02 03) |
%u |
和%C 相同(例如Tue Feb 30 4:27:33 MST 1998) |
%v |
縮寫的每一周的日期(例如 T 表示Tuesday) |
%V |
%m%d %H%M%y ( 例如0203042798) |
除了解析和格式化日期外,Date::Manip 提供許多了函式,可以用更彈性的方式計算日期。
如下範例中就增加五個工作天到目前的日期。
你也可以使用Date_IsWorkDay,Date_NextWorkDay,Date_PrevWorkDay 函式處理工作天。
範例add_date.pl:使用DateCalc
use Date::Manip;
use strict;
my $dt = ParseDate("today"); # parse today into a date format
$dt = DateCalc($dt, "+ 5 business days"); # add 5 business days
print UnixDate($dt, "%F"), "n";
Date::Manip 讓你定義你自己的假期或是特殊的日子,並且將它們儲存在你指定的目錄或目前目錄的檔案中。
如果你想深入關於Date::Manip 如何保存設定檔的細節,請參考「Perl Module Reference」的Date::Manip 部份。
@來源:http://blog.xuite.net/mark.wu/x/4097977-PERL+%E6%97%A5%E6%9C%9F%E5%92%8C%E6%99%82%E9%96%93