[PERL] 22-日期和時間

URL Link //n.sfs.tw/13033

2019-01-16 01:47:01 By 張○○

程式上常會需要取用到日期或時間,Perl 的日期和時間的取得可使用內建的方法或是套件。

取得時間

使用time() 函數,會取得一個時戳( timestamp),一個長整數。

* Unix timestamp 時戳是自1970年1月1日(00:00:00 GMT)以來經過的秒數。

print time; #1547744758

 

把時戳轉成習慣的日期時間

可使用 localtime() 函數

my (@ti) = localtime;
print  "@ti"; #28 10 1 18 0 119 5 17 0

當localtime沒帶入參數的時間,會以目前時間作轉換

如果要計算某時戳的可讀日期時間,把他放在引數中即可,有鑑於PERL的彈性,下面4種寫法都可以。

my (@ti) = localtime 1501234567;
my (@ti) = localtime(1501234567);
my (@ti) = localtime "1501234567";
my (@ti) = localtime("1501234567");

 

localtime日期時間

localtime取回陣列是一個陣列,項目為:

秒- 0-59

分- 0-59

小時- 0-23

日- 1-31

月- 0-11,由0起算,1月顯示0,8月顯示7

年- 由1900年起算,2019年顯示 119

星期- 0-6,星期日0起算,星期六為6

一年的第幾天- 0-365,由0起算 1/1為0,年尾12/31為364或365

日光節約時間?0或1

gmtime 日期時間

和 localtime 一樣的函數,差別在於他取回的是格林威治時間

my (@tg) = gmtime(time);

對非格林威治時間的地區來說,你得把誤差加上去例如。台灣地區,小時數要+8。此函數使用時機為:

當你在世界各地有不同的主機,需要取得一致性的時間(例如同樣在格林威治半夜2:00傳送資料到XXX)

其它情況不要使用,以免…

例如取回的結果Taiwan

30 52 2 18 0 119 5 17 0 (localtime)
30 52 18 17 0 119 4 16 0 (gmtime)

使用清單取回各數值

PERL可以使用清單LIST的方法一次指定所有的項目

my ($sec, $min, $hour, $day, $mon, $year, $wday, $wyear, $dlsaving ) = localtime(time);

 

產生日期和時間格式的幾個範例

我們常用的日期格式有幾種,例如

2019-01-18
2019/01/18
01-18-2019
19-01-18
01-18-19
19-01 (不要日)

時間格式有

03:44:32
03:44 (不要秒)

等等。下面介紹幾種方法:

 

使用字串相黏

不想搞得太複雜的話,使用字串相黏的方式自行組合,只是要記得$year 是從1900 年啟算;而月份的話是從0起算。

$d=join("-",($year+1900,$mon+1,$day)); #2019-1-18
$d=join("-",($year+1900,$mon+1,$day)); #2019/1/18
$t=join(":",($hour,$min,$sec)); #10:4:8

這種方法取得的日期時間都如果單個數字的話都沒辦法自動補0。

 

採用 sprintf

$d= sprintf("%4d-%02d-%02d",$year+1900,$mon+1,$day); #2019-01-18
$t= printf("%02d:%02d:%02d",$hour,$min,$sec); #10:04:08

看來使用 sprintf就能解決所有的問題。

 

使用strftime

如果想給自己找麻煩的話,可以採用 strftime 函數,可以產生更多樣的格式。

但他必需要安裝 POSIX::strftime::GNU 模組,有安裝的問題可參考 [PERL] 使用CPAN安裝模組

由於 strftime 完全支援 localtime,使用方式,其中第一項為格式,第二項請代入 localtime的時間陣列:

$str = strftime($format, @time)

使用範例:

use POSIX::strftime::GNU;
use POSIX 'strftime';
print strftime('%a, %d %b %Y %T %z', localtime); # Fri, 18 Jan 2019 02:01:43 +0800

第3行

  %a 星期縮寫 Sun .. Sat
  %d 日期 1-31
  %b 月份縮寫
  %Y 四碼年2019
  %T 時間 hh:mm:ss
  %z UTC時間

此函數的優點是可以以當地的語言顯示時間,例如上例要顯示中文,只要在shell指定語系

# export LC_TIME=zh_TW.UTF-8

就可以顯示中文的日期:

五, 18  1月 2019 02:18:52 +0800

有關更多的參數,可參考[2],此外,strftime的格式參數和作業系統的date格式幾乎相同 Linux shell 的date表示法

* 如果你不能顯示正確的中文日期時間的話,請參考這一篇 關於語系 locale 的設定

 

使用Date::Format 套件

使用Date::Format 套件的方法[3]

use Date::Format;
print time2str("%D", time); #01/18/19
print time2str("%m/%d/%Y", time); #01/18/2019
@lt= localtime;
print strftime("%a %b %e %T %Y", @lt); #Fri Jan 18 03:20:32 2019
print ctime(time); #Fri Jan 18 03:20:32 2019 
print asctime(@lt); $Fri Jan 18 03:20:32 2019

說明:

time2str和strftime(和上面的strftime的套件不同函數名一樣)的差異在於一個代入要時戳,另一個是要代入陣列。

ctime和asctime也是,差異在於一個代入要時戳,另一個是要代入陣列。

第5-7行 結果一樣,因為ctime,asctime設定輸出的格式就是"%a %b %e %T %Y"

 

把日期時間字串轉成 timestamp

前面提到的都是把 timestamp轉成日期時間字串,相反的日期時間要轉回timestamp怎麼做?

使用Date::Manip 套件[4]

use Date::Manip;
print UnixDate('2019/09/07 04:13:51', "%s"); #1567844031
print UnixDate("Fri Jan 18 03:20:32 2019", "%s"); #1547799632
print UnixDate("1st Thursday in June 1992", "%s");  #707630400

使用函數 UnixDate就能將日期字串轉成秒。

 

使用 ParseDate來解析字串

use Date::Manip;

print $date = ParseDate("today"); #2019011900:00:00
print $date = ParseDate("now"); #2019011902:34:06
print $date = ParseDate("05/10/93"); #1993051000:00:00
print $date = ParseDate("12:30 Dec 12th 1880"); #1880121212:30:00
print $date = ParseDate("8:00pm December tenth"); #2019121020:00:00

* 字串有中文字無法解析

* 如果你的字串無法解析的話,回傳是空的字串

特別注意

在使用這個套件時,務必設定時區,否則得到的結果可能不是正確的結果
設定的方式是到OS下面打入這行指令

$ export TZ=Asia/Taipei

使用Time::Local;

使用Time::Local套件提供的timelocal指令,就可以避免時區的問題,但麻煩的是字串你得自己用*regex來解。

畢竟時間字串一般都很規律,可以自己解析[5]

use Time::Local

my $date = '23.01.2019  11:35:00';
my ($mday,$mon,$year,$hour,$min,$sec) = split(/[\s.:]+/, $date);
my $time = timelocal($sec,$min,$hour,$mday,$mon-1,$year); #1562988900

月份是從0開始起算。

*regex 正規表達式Regular Express的非正式縮寫

 

結論

1. 取得時戳用 time

2. 分析時戳用 localtime(時戳)

3. 產生指定日期時間格式使用sprinft, strftime 等多種方式

4. 分析複雜日期字串用 Date::Format 套件

5. 中文字串目前無法解析

6. 日期時間的函數永遠要注意時區,考慮時區很燒腦

 

參考資料

[1] http://tw.gitbook.net/perl/perl_localtime.html

[2] https://metacpan.org/pod/POSIX::strftime::GNU

[3] Date::Format https://metacpan.org/pod/Date::Format

[4] Date::Manip EXAMPLE https://metacpan.org/pod/distribution/Date-Manip/lib/Date/Manip/Examples.pod

[5] https://stackoverflow.com/questions/7726514/how-to-convert-text-date-to-timestamp

 

上一篇 21-使用資料庫
回到目錄 01-撰寫第一隻PERL程式
下一篇 23-多執行緒


重編原文 2009-10-21 15:02:45