你已经级掌握了时,分,年等值的含义,也了解了纪元秒的含义。而日常生活中的日期和时间是用字符串来表示的,你怎样才能把日常所用的日期和时间串格式转换成纪元秒呢?
方法之一是写出语法分析小程序,该方法灵活而快速:
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"; /(dd)s+(w+)s+(d+)s+(d+):(d+):(d+)/ or die "Not a date"; $mday = ; $mon = exists($months{}) ? $months{} : die "Bad month"; $year = — 1900; ($h, $m, $s) = (, , ); $epoch_seconds = timelocal($s,$m,$h,$mday,$mon,$year); |
一个更通用些的方法,是从CPAN(Perl综合网)中安装Date::Manip 模块。
use Date::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:15pm, 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, " ";
2147483647
这个数字对应了哪个日期呢?
print scalar(gmtime 2**31-1), " ";
Tue Jan 19 03:14:07 2038
在那个时刻的1秒之后会发生什么呢?
print scalar(gmtime 2**31), " ";
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。
上一页 | 下一页 |
常见的日期和时间操作 | 总结 |