Perl時間處理函數使用詳解

巴扎黑
發布: 2017-09-05 11:22:42
原創
1713 人瀏覽過

本文重點討論Perl時間處理函數的概念,Perl能在絕大多數作業系統運作,可以方便地向不同作業系統遷移,並且Perl借取了C、sed、awk、shellscripting以及很多其他程式語言的特性

一. Perl時間的表示函數

1. 表示日期的方式多樣:
"18Jan1973";
"18/01 /1973";
"01/18/1973";
"Jan181973";
"18-01-73";
"18-01-1973";
"01/ 73".
其中有些格式意思不清(如"01-06-1973",是表示6月1日呢,還是表示1月6日呢?)
如果不規定日期的表示形式,是很難處理的.

想理解"18Jan1973"和"6Sep1950"之間的區別,需要把它們轉換為數字表示.
Unix內部運用紀元秒錶示時間。
日期和時間加起來表示:
自格林威志時間1970年1月1日午夜時分(紀元)到當前時刻之間的秒數。
如, "18 Jan 1973:(假定為午夜時分)的紀元秒為96163200。

2. 在該系統中,午夜表示一天的開始時刻。

讓我們透過Perl中提供的gmtime函數產生一個日期。 #例一:
呼叫gmtime()函數,你會得到一系列值的列表,包括時,分,秒,日期,月份,年份等.

#!/usr/bin/perl
use Time::localtime;

$t_num = 96163200;
$tm = scalar(gmtime($t_num));
print $tm,"\n";
登入後複製

輸出:

Thu Jan 18 00:00:00 1973


例二:以","為分隔符號輸出時間

print join(",", gmtime(96163200 ));
0,0,0,18,0,73,4,17,0

語意:

前3個數字: 0,0,0, 分別表示秒, 分, 時. 小時是從0-23,故下午是12時往後.
第4個數: 18, 表示該月中的天數(本例中為18號)。 5個數: 0 , 表示月份,從0開始(代表1月份)。

@months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
$month = @months[(gmtime($t_num))[4]];
print "MONTH: ",$month,"\n";
登入後複製

第6個數: 73, 年份, (本例中為73)的表示有點特殊。
為什麼要這樣表示呢?
這是因為C語言就是這樣處理的。 4位數的年份,表示如下:

$year=(gmtime(96163200))[5]+1900;


如果你不了解這種處理方式,就會製造出Y2K疑問,你也許會這樣寫:

$year="19".(gmtime(96163200))[5]; #出錯!表示一星期中的第幾天(星期日為0).
第8個數: 17, 一年中的第幾天(0表示一年中的第一天).
第9個數: 0 , 能不能採用夏時制(0表示不採用,正數表示採用,負數表示不可知).


3. Perl中的time()函數返回以紀元秒錶示的目前日期和時間。 ##

$now=localtime(time());
($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst)=localtime(time());
登入後複製

如果呼叫localtime()或gmtime()時不帶參數,它將自己呼叫time()


$now=localtime();
($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst)=localtime();
登入後複製


二. Perl時間處理函數中(日期和時間運算)

1. 計算兩個時刻之間的時間段,

只需將它們轉換為對應的紀元秒,然後兩數相減即可:

$difference_in_seconds=$later_datetime-$earlier_datetime;

要把秒轉換為分,時,或天數,只須要分別將它們除以60, 3600和86400即可:



$difference_in_minutes=$difference_in_seconds/60;
$difference_in_hours=$difference_in_seconds/3600;
$difference_in_day=$difference_in_seconds/86400;
登入後複製

2. 計算"4天後是幾號?":


$then=time()+86400*4;
print scalar(localtime($then));
登入後複製
它給出的答案精確到秒。

例如,

如果4天後的紀元秒值為932836935,你可以輸出日期的字串如下;Sat Jul 24 11:23:17 1999

#3.輸出某個日期的午夜時分

如"Sat Jul 24 00:00:00 1999",
運用如下模組:

$then=$then-$then%86400;#去掉那個日期的尾巴


類似地,你可以用四捨五入法,輸出最靠近午夜時分的日期:


$then += 43200; #add on half a day
$then = $then - $then%86400; #truncate to the day
登入後複製

如果你的時區距離GMT為相差偶數個小時,這就管用了。

並不是所有的時區都是很容易處理的。

你所真實須要的是在你自己的時區內計算紀元秒,而不是在GMT中計算。

Perl中的名為Time::Local的模組,
可以提供兩個函數timelocal()和timegm()。其回傳值同localtime()和gmtime()一樣。

use Time::Local;
$then = time() + 4*86400;
$then = timegm(localtime($then)); #local epoch seconds
$then -= $then%86400; #truncate to the day
$then = timelocal(gmtime($then)); #back to gmt epoch seconds
print scalar(localtime$then,“\n”。
登入後複製


三. Perl時間處理函數中日常生活所用的日期和時間的表示

前面介绍了时,分,年等值的意思,也了解了纪元秒的意思。
而日常生活中的日期和时间是用字符串来表示的,
怎样才能把日常所用的日期和时间串格式转换成纪元秒呢?

1. 要领之一是写出语法分析小程序,该要领灵活而高速:


#!/usr/bin/perl

use Time::Local;
@months{qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)}=(0..11);
$_ = "19 Dec 1997 15:30:02";
/(\d\d)\s+(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)/ or die "Notadate";


$mday=$1;
$mon=exists($months{$2})?$months{$2}:die"Badmonth";
$year=$3-1900;
($h,$m,$s)=($4,$5,$6);
$epoch_seconds = timelocal($s,$m,$h,$mday,$mon,$year);


print "day: ",$mday,"\n";
print "mon: ",$mon,"\n";
print "year: ",$year,"\n";
print "seconds: ",$epoch_seconds,"\n";
登入後複製

2. 一个更通用些的要领,是从CPAN安装Date::Manip模块。


useDate::Manip;
$epoch_seconds=UnixDate("19 Dec 1997 15:30:02","s");
登入後複製

留心,由于Date::Manip是个大模块,运用该模块时,将会添加你的程序的启动时间。
其中一个原由是Date::Manip将对多种不同的格式执行识别,
如:
"today"
"now"
"first sunday in april 2000"
"3:15,today"
"3:15 pm,first sunday in april 2000"
"2000/01/18 09:15" Date Manipulation
2036,2037,2038,…,1901?!

四. 大多数C程序把纪元秒存为有符号整数,可表示正的和负的日期;
但计算机存储器所表示的整数大小是有限的, 用有限的位数来表示秒.
这就是说,我们在计算纪元秒时, 所表示的日期是有限定的。
确切的限度取决于你的机器所能表示的整数的位数。

Perl最多以32位的长度存储整数。
粗略地讲,有一位用来表示正负号,其余31位来表示数。
如果8位,你可以存储的最大数是255,即2的8次方减1。
故Perl中所存储的32位符号数中的最大数为:


print 2**31-1,"\n";
2147483647
登入後複製

这个数字对应了哪个日期呢?


print scalar(gmtime(2**31-1)),"\n";
Tue Jan 19 03:14:07 2038
登入後複製

在那个时刻的1秒之后会发生什么呢?


print scalar(gmtime(2**31)),"\n";
Fri Dec 13 20:45:52 1901
登入後複製

对于32位有符号整数来说,2**31太大了。
它"翻卷过去了",其符号位被置为负号,因而成为了所能表示的最大负数。
这对应于1970年开始时刻之前的秒的最大值。
其结果说明了什么呢?你不能存储gmtime(2**31)之前或gmtime(2**31-1)之后的以纪元秒表示的日期。
你可千万不要想不开,这可不是什么大疑问。
如果你要用到32位有符号整数表示的纪元秒以外的时间,你只须要改动你的表示方式,
你可从CPAN中找到不少日期模块,其中的Date::Calc和Date::Manip很可能是功能最强的两个模块。
这两个模块运用自己的日期表示方式,以防止Y1901-Y2038的限定。
Date::Manip运用罗马历法,从公元0000到公元9999。
Date::Calc也运用罗马历法,可表示的年份从1到32767。

总结

Perl时间处理函数中对于在1902-2037范围内的日期和时期表示,把它们转换为纪元秒,
要存取这些数,你只需运用整数算术运算,gmtime()和localtime()函数,以及标准的Time::Local模块。
如果要对该范围以外的日期执行计算或者要分析某特殊的日期格式,
你可以运用CPAN中的Date::Manip和Date::Calc模块。

以上是Perl時間處理函數使用詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!