返回首页 《从零开始学 Python》(第二版)

预备

基本数据类型

语句和文件

函数

错误和异常

模块

保存数据

实战

用Tornado做网站

科学计算

结尾

标准库 (5)

“一寸光阴一寸金,寸金难买寸光阴”,时间是宝贵的。

在日常生活中,“时间”这个属于是比较笼统和含糊的。在物理学中,“时间”是一个非常明确的概念。在 Python 中,“时间”可以通过相关模块实现。

calendar

>>> import calendar
>>> cal = calendar.month(2015, 1)
>>> print cal
    January 2015
Mo Tu We Th Fr Sa Su
          1  2  3  4
 5  6  7  8  9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

轻而易举得到了 2015 年 1 月的日历,并且排列的还那么整齐。这就是 calendar 模块。读者可以用 dir() 去查看这个模块下的所有内容。为了让读者阅读方便,将常用的整理如下:

calendar(year,w=2,l=1,c=6)

返回 year 年年历,3 个月一行,间隔距离为 c。 每日宽度间隔为 w 字符。每行长度为 21 W+18+2 C。l 是每星期行数。

>>> year = calendar.calendar(2015)
>>> print year
                                  2015

      January                   February                   March
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
          1  2  3  4                         1                         1
 5  6  7  8  9 10 11       2  3  4  5  6  7  8       2  3  4  5  6  7  8
12 13 14 15 16 17 18       9 10 11 12 13 14 15       9 10 11 12 13 14 15
19 20 21 22 23 24 25      16 17 18 19 20 21 22      16 17 18 19 20 21 22
26 27 28 29 30 31         23 24 25 26 27 28         23 24 25 26 27 28 29
                                                    30 31

       April                      May                       June
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
       1  2  3  4  5                   1  2  3       1  2  3  4  5  6  7
 6  7  8  9 10 11 12       4  5  6  7  8  9 10       8  9 10 11 12 13 14
13 14 15 16 17 18 19      11 12 13 14 15 16 17      15 16 17 18 19 20 21
20 21 22 23 24 25 26      18 19 20 21 22 23 24      22 23 24 25 26 27 28
27 28 29 30               25 26 27 28 29 30 31      29 30

        July                     August                  September
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
       1  2  3  4  5                      1  2          1  2  3  4  5  6
 6  7  8  9 10 11 12       3  4  5  6  7  8  9       7  8  9 10 11 12 13
13 14 15 16 17 18 19      10 11 12 13 14 15 16      14 15 16 17 18 19 20
20 21 22 23 24 25 26      17 18 19 20 21 22 23      21 22 23 24 25 26 27
27 28 29 30 31            24 25 26 27 28 29 30      28 29 30
                          31

      October                   November                  December
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
          1  2  3  4                         1          1  2  3  4  5  6
 5  6  7  8  9 10 11       2  3  4  5  6  7  8       7  8  9 10 11 12 13
12 13 14 15 16 17 18       9 10 11 12 13 14 15      14 15 16 17 18 19 20
19 20 21 22 23 24 25      16 17 18 19 20 21 22      21 22 23 24 25 26 27
26 27 28 29 30 31         23 24 25 26 27 28 29      28 29 30 31
                          30

isleap(year)

判断是否为闰年,是则返回 true,否则 false.

>>> calendar.isleap(2000)
True
>>> calendar.isleap(2015)
False

怎么判断一年是闰年,常常见诸于一些编程语言的练习题,现在用一个方法搞定。

leapdays(y1,y2)

返回在 Y1,Y2 两年之间的闰年总数,包括 y1,但不包括 y2,这有点如同序列的切片一样。

>>> calendar.leapdays(2000,2004)
1
>>> calendar.leapdays(2000,2003)
1

month(year,month,w=2,l=1)

返回 year 年 month 月日历,两行标题,一周一行。每日宽度间隔为 w 字符。每行的长度为 7* w+6。l 是每星期的行数。

>>> print calendar.month(2015, 5)
      May 2015
Mo Tu We Th Fr Sa Su
             1  2  3
 4  5  6  7  8  9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31

monthcalendar(year,month)

返回一个列表,列表内的元素还是列表,这叫做嵌套列表。每个子列表代表一个星期,都是从星期一到星期日,如果没有本月的日期,则为 0。

>>> calendar.monthcalendar(2015, 5)
[[0, 0, 0, 0, 1, 2, 3], [4, 5, 6, 7, 8, 9, 10], [11, 12, 13, 14, 15, 16, 17], [18, 19, 20, 21, 22, 23, 24], [25, 26, 27, 28, 29, 30, 31]]

读者可以将这个结果和 calendar.month(2015, 5) 去对照理解。

monthrange(year,month)

返回一个元组,里面有两个整数。第一个整数代表着该月的第一天从星期几是(从 0 开始,依次为星期一、星期二,直到 6 代表星期日)。第二个整数是该月一共多少天。

>>> calendar.monthrange(2015, 5)
(4, 31)

从返回值可知,2015 年 5 月 1 日是星期五,这个月一共 31 天。这个结果,也可以从日历中看到。

weekday(year,month,day)

输入年月日,知道该日是星期几(注意,返回值依然按照从 0 到 6 依次对应星期一到星期六)。

>>> calendar.weekday(2015, 5, 4)    #星期一
0
>>> calendar.weekday(2015, 6, 4)    #星期四
3

time

time()

time 模块是常用的。

>>> import time
>>> time.time()
1430745298.391026

time.time() 获得的是当前时间(严格说是时间戳),只不过这个时间对人不友好,它是以 1970 年 1 月 1 日 0 时 0 分 0 秒为计时起点,到当前的时间长度(不考虑闰秒)

UNIX 时间,或称 POSIX 时间是 UNIX 或类 UNIX 系统使用的时间表示方式:从协调世界时 1970 年 1 月 1 日 0 時 0 分 0 秒起至现在的总秒数,不考虑秒

现时大部分使用 UNIX 的系统都是 32 位元的,即它们会以 32 位二進制数字表示时间。但是它们最多只能表示至协调世界时间 2038 年 1 月 19 日 3 时 14 分 07 秒(二进制:01111111 11111111 11111111 11111111,0x7FFF:FFFF),在下一秒二进制数字会是 10000000 00000000 00000000 00000000,(0x8000:0000),这是负数,因此各系统会把时间误解作 1901 年 12 月 13 日 20 时 45 分 52 秒(亦有说回鬼到 1970 年)。这时可能会令软件发生问题,导致系统瘫痪。

目前的解決方案是把系統由 32 位元转为 64 位元系统。在 64 位系统下,此时间最多可以表示到 292,277,026,596 年 12 月 4 日 15 时 30 分 08 秒。

有没有对人友好一点的时间显示呢?

localtime()

>>> time.localtime()
time.struct_time(tm_year=2015, tm_mon=5, tm_mday=4, tm_hour=21, tm_min=33, tm_sec=39, tm_wday=0, tm_yday=124, tm_isdst=0)

这个就友好多了。得到的结果可以称之为时间元组(也有括号),其各项的含义是:

索引 属性 含义
0 tm_year
1 tm_mon
2 tm_mday
3 tm_hour
4 tm_min
5 tm_sec
6 tm_wday 一周中的第几天
7 tm_yday 一年中的第几天
8 tm_isdst 夏令时
>>> t = time.localtime()
>>> t[1]
5

通过索引,能够得到相应的属性,上面的例子中就得到了当前时间的月份。

其实,time.localtime() 不是没有参数,它在默认情况下,以 time.time() 的时间戳为参数。言外之意就是说可以自己输入一个时间戳,返回那个时间戳所对应的时间(按照公元和时分秒计时)。例如:

>>> time.localtime(100000)
time.struct_time(tm_year=1970, tm_mon=1, tm_mday=2, tm_hour=11, tm_min=46, tm_sec=40, tm_wday=4, tm_yday=2, tm_isdst=0)

gmtime()

localtime() 得到的是本地时间,如果要国际化,就最好使用格林威治时间。可以这样:

>>> import time
>>> time.gmtime()
time.struct_time(tm_year=2015, tm_mon=5, tm_mday=4, tm_hour=23, tm_min=46, tm_sec=34, tm_wday=0, tm_yday=124, tm_isdst=0)

格林威治标准时间(中国大陆翻译:格林尼治平均时间或格林尼治标准时间,台、港、澳翻译:格林威治标准时间;英语:Greenwich Mean Time,GMT)是指位于英国伦敦郊区的皇家格林威治天文台的标准时间,因为本初子午线被定义在通过那裡的经线。

还有更友好的:

asctime()

>>> time.asctime()
'Mon May  4 21:46:13 2015'

time.asctime() 的参数为空时,默认是以 time.localtime() 的值为参数,所以得到的是当前日期时间和星期。当然,也可以自己设置参数:

>>> h = time.localtime(1000000)
>>> h
time.struct_time(tm_year=1970, tm_mon=1, tm_mday=12, tm_hour=21, tm_min=46, tm_sec=40, tm_wday=0, tm_yday=12, tm_isdst=0)
>>> time.asctime(h)
'Mon Jan 12 21:46:40 1970'

注意,time.asctime() 的参数必须是时间元组,类似上面那种。不是时间戳,通过 time.time() 得到的时间戳,也可以转化为上面形式:

ctime()

>>> time.ctime()
'Mon May  4 21:52:22 2015'

在没有参数的时候,事实上是以 time.time() 的时间戳为参数。也可以自定义一个时间戳。

>>> time.ctime(1000000)
'Mon Jan 12 21:46:40 1970'

跟前面得到的结果是一样的。只不过是用了时间戳作为参数。

在前述函数中,通过 localtime()、gmtime() 得到的是时间元组,通过 time() 得到的是时间戳。有的函数如 asctime() 是以时间元组为参数,有的如 ctime() 是以时间戳为函数。这样做的目的是为了满足编程中多样化的需要。

mktime()

mktime() 也是以时间元组为参数,但是它返回的不是可读性更好的那种样式,而是:

>>> lt = time.localtime()
>>> lt
time.struct_time(tm_year=2015, tm_mon=5, tm_mday=5, tm_hour=7, tm_min=55, tm_sec=29, tm_wday=1, tm_yday=125, tm_isdst=0)
>>> time.mktime(lt)
1430783729.0

返回了时间戳。就类似于 localtime() 的逆过程(localtime() 是以时间戳为参数)。

以上基本能够满足编程需要了吗?好像还缺点什么,因为在编程中,用的比较多的是“字符串”,似乎还没有将时间转化为字符串的函数。这个应该有。

strftime()

函数格式稍微复杂一些。

Help on built-in function strftime in module time:

strftime(...) strftime(format[, tuple]) -> string

Convert a time tuple to a string according to a format specification. See the library reference manual for formatting codes. When the time tuple is not present, current time as returned by localtime() is used.

将时间元组按照指定格式要求转化为字符串。如果不指定时间元组,就默认为 localtime() 值。我说复杂,是在于其 format,需要用到下面的东西。

格式 含义 取值范围(格式)
%y 去掉世纪的年份 00-99,如"15"
%Y 完整的年份 如"2015"
%j 指定日期是一年中的第几天 001-366
%m 返回月份 01-12
%b 本地简化月份的名称 简写英文月份
%B 本地完整月份的名称 完整英文月份
%d 该月的第几日 如 5 月 1 日返回"01"
%H 该日的第几时(24 小时制) 00-23
%l 该日的第几时(12 小时制) 01-12
%M 分钟 00-59
%S 00-59
%U 在该年中的第多少星期(以周日为一周起点) 00-53
%W 同上,只不过是以周一为起点 00-53
%w 一星期中的第几天 0-6
%Z 时区 在中国大陆测试,返回 CST,即 China Standard Time
%x 日期 日/月/年
%X 时间 时:分:秒
%c 详细日期时间 日/月/年 时:分:秒
%% ‘%’字符 ‘%’字符
%p 上下午 AM or PM

简要列举如下:

>>> time.strftime("%y,%m,%d")
'15,05,05'
>>> time.strftime("%y/%m/%d")
'15/05/05'

分隔符可以自由指定。既然已经变成字符串了,就可以“随心所欲不逾矩”了。

strptime()

Help on built-in function strptime in module time:

strptime(...) strptime(string, format) -> struct_time

Parse a string to a time tuple according to a format specification. See the library reference manual for formatting codes (same as strftime()).

strptime() 的作用是将字符串转化为时间元组。请注意的是,其参数要指定两个,一个是时间字符串,另外一个是时间字符串所对应的格式,格式符号用上表中的。例如:

>>> today = time.strftime("%y/%m/%d")
>>> today
'15/05/05'
>>> time.strptime(today, "%y/%m/%d")
time.struct_time(tm_year=2015, tm_mon=5, tm_mday=5, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=1, tm_yday=125, tm_isdst=-1)

datetime

虽然 time 模块已经能够把有关时间方面的东西搞定了,但是,在某些调用的时候,还感觉不是很直接,于是又出来了一个 datetime 模块,供程序猿和程序媛们选择使用。

datetime 模块中有几个类:

  • datetime.date:日期类,常用的属性有 year/month/day
  • datetime.time:时间类,常用的有 hour/minute/second/microsecond
  • datetime.datetime:日期时间类
  • datetime.timedelta:时间间隔,即两个时间点之间的时间长度
  • datetime.tzinfo:时区类

date 类

通过实例了解常用的属性:

>>> import datetime
>>> today = datetime.date.today()
>>> today
datetime.date(2015, 5, 5)

这里其实生成了一个日期对象,然后操作这个对象的各种属性。用 print 语句,可以是视觉更佳:

>>> print today
2015-05-05
>>> print today.ctime()
Tue May  5 00:00:00 2015
>>> print today.timetuple()
time.struct_time(tm_year=2015, tm_mon=5, tm_mday=5, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=1, tm_yday=125, tm_isdst=-1)
>>> print today.toordinal()
735723

特别注意,如果你妄图用 datetime.date.year(),是会报错的,因为 year 不是一个方法,必须这样行:

>>> print today.year
2015
>>> print today.month
5
>>> print today.day
5

进一步看看时间戳与格式化时间格式的转换

>>> to = today.toordinal()
>>> to
735723
>>> print datetime.date.fromordinal(to)
2015-05-05

>>> import time
>>> t = time.time()
>>> t
1430787994.80093
>>> print datetime.date.fromtimestamp(t)
2015-05-05

还可以更灵活一些,修改日期。

>>> d1 = datetime.date(2015,5,1)
>>> print d1
2015-05-01
>>> d2 = d1.replace(year=2005, day=5)
>>> print d2
2005-05-05

time 类

也要生成 time 对象

>>> t = datetime.time(1,2,3)
>>> print t
01:02:03

它的常用属性:

>>> print t.hour
1
>>> print t.minute
2
>>> print t.second
3
>>> t.microsecond
0
>>> print t.tzinfo
None

timedelta 类

主要用来做时间的运算。比如:

>>> now = datetime.datetime.now()
>>> print now
2015-05-05 09:22:43.142520

没有讲述 datetime 类,因为在有了 date 和 time 类知识之后,这个类比较简单,我最喜欢这个 now 方法了。

对 now 增加 5 个小时

>>> b = now + datetime.timedelta(hours=5)
>>> print b
2015-05-05 14:22:43.142520

增加两周

>>> c = now + datetime.timedelta(weeks=2)
>>> print c
2015-05-19 09:22:43.142520

计算时间差:

>>> d = c - b
>>> print d
13 days, 19:00:00

总目录   |   上节:标准库(4)   |   下节:标准库(6)

如果你认为有必要打赏我,请通过支付宝:qiwsir@126.com,不胜感激。

上一篇: 标准库(4) 下一篇: 标准库(6)