本文重點討論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";
例二:以","為分隔符號輸出時間
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";
$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());
$now=localtime(); ($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst)=localtime();
1. 計算兩個時刻之間的時間段,
只需將它們轉換為對應的紀元秒,然後兩數相減即可:$difference_in_seconds=$later_datetime-$earlier_datetime;
$difference_in_minutes=$difference_in_seconds/60; $difference_in_hours=$difference_in_seconds/3600; $difference_in_day=$difference_in_seconds/86400;
$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 += 43200; #add on half a day $then = $then - $then%86400; #truncate to the day
你所真實須要的是在你自己的時區內計算紀元秒,而不是在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”。
前面介绍了时,分,年等值的意思,也了解了纪元秒的意思。
而日常生活中的日期和时间是用字符串来表示的,
怎样才能把日常所用的日期和时间串格式转换成纪元秒呢?
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中文網其他相關文章!