Python 语言及其应用 Chapter_10 Note 3 时间time



日期和时间
程序员们需要花费大量时间来处理日期和时间。我们会讨论一些常见的问题,之后会介绍
一些对应的最佳实践和能够帮助缓解问题的小技巧。
可以用多种方式来表示日期,甚至多到让人厌烦。即使是使用罗马历的英语国家也有很多
表示日期的方法:
• July 29 1984
• 29 Jul 1984
• 29/7/1984
• 7/29/1984
表示日期的第一个问题就是二义性。从上面的例子可以很容易看出,7 表示月份,29 表示
天数,因为月份不可能是29。但是1/6/2012 呢?它到底是1 月6 日还是6 月1 日呢?


罗马历中,月份的名字在不同语言中差别很大。在其他文化中,年份和月份本身的定义都
有可能不一样。
闰年是另一个问题。你可能知道,每隔4 年会出现一个闰年(夏季奥运会和美国总统选举
也是隔四年一次)。不过你知道吗,年份是整百数时,必须是400 的倍数才是闰年。下面
的代码可以检测是否是闰年:
>>> import calendar
>>> calendar.isleap(1900)
False
>>> calendar.isleap(1996)
True
>>> calendar.isleap(1999)
False
>>> calendar.isleap(2000)
True
>>> calendar.isleap(2002)
False
>>> calendar.isleap(2004)
True
时间则有另外的问题,主要是因为时区以及夏时制。观察时区图会发现,时区是按照政治
和历史因素分割的,并不是按照经度15 度(360 度/24)分割。不同国家每年夏时制的开
始和结束时间也不一样。实际上,南半球和北半球的夏时制时间段刚好相反(细想就知道
原因了)。
Python 的标准库中有很多日期和时间模块:datetime、time、calendar、dateutil,等等。
有些在功能上有重复,还有点不好理解。



 datetime模块
首先介绍一下标准datetime 模块。它定义了4 个主要的对象,每个对象都有很多方法:
• date 处理年、月、日
• time 处理时、分、秒和分数
• datetime 处理日期和时间同时出现的情况
• timedelta 处理日期和/ 或时间间隔

你可以指定年、月、日,来创建一个date 对象。这些值之后会变成对象的属性:
>>> from datetime import date
>>> halloween = date(2014, 10, 31)
>>> halloween
datetime.date(2014, 10, 31)
>>> halloween.day
31
>>> halloween.month
10
>>> halloween.year
2014

可以使用isoformat() 方法打印一个date 对象:                                               #注意,这个方法的一个特性是,打印出来的是字符串
>>> halloween.isoformat()
'2014-10-31'

iso 是指ISO 8601,一种表示日期和时间的国际标准。这个标准的显示顺序是从一般(年)
到特殊(日)。它也可以对日期进行正确的排序:先按照年,然后是月,最后是日。我经
常在程序中使用这种格式表示日期,还会在存储和日期相关的数据时当作文件名。下一节
会介绍更复杂的strptime() 和strftime() 方法,它们分别用来解析和格式化日期。


下面的例子使用today() 方法生成今天的日期:
>>> from datetime import date
>>> now = date.today()
>>> now
datetime.date(2014, 2, 2)

下面的例子使用timedelta 对象来实现date 的加法
>>> from datetime import timedelta
>>> one_day = timedelta(days=1)
>>> tomorrow = now + one_day                 #这里的now是上一例里面的now
>>> tomorrow
datetime.date(2014, 2, 3)
>>> now + 17*one_day
datetime.date(2014, 2, 19)
>>> yesterday = now - one_day
>>> yesterday
datetime.date(2014, 2, 1)

date 的范围是date.min( 年= 1, 月= 1, 日= 1) 到date.max( 年= 9999, 月= 12,
日= 31)。因此,不能使用它来进行和历史或者天文相关的计算。


datetime 模块中的time 对象用来表示一天中的时间:
>>> from datetime import time
>>> noon = time(12, 0, 0)
>>> noon
datetime.time(12, 0)
>>> noon.hour
12
>>> noon.minute
0
>>> noon.second
0
>>> noon.microsecond
0

参数的顺序是按照时间单位从大(时)到小(微秒)排列。如果没有参数,time 会默认全
部使用0。顺便说一句,能够存取微秒并不意味着你能从计算机中得到准确的微秒。每秒
的准确度取决于硬件和操作系统中的很多因素。


datetime 对象既包含日期也包含时间。你可以直接创建一个datetime 对象,如下所示,表
示2014 年1 月2 日上午3:04,5 秒6 微秒:

>>> from datetime import datetime
>>> some_day = datetime(2014, 1, 2, 3, 4, 5, 6)

>>> some_day
datetime.datetime(2014, 1, 2, 3, 4, 5, 6)

datetime 对象也有一个isoformat() 方法:
>>> some_day.isoformat()
'2014-01-02T03:04:05.000006'
中间的T 把日期和时间分割开



datetime 有一个now() 方法,可以用它获取当前日期和时间:
>>> from datetime import datetime
>>> now = datetime.now()
>>> now
datetime.datetime(2014, 2, 2, 23, 15, 34, 694988)
14
>>> now.month
2
>>> now.day
2
>>> now.hour
23
>>> now.minute
15
>>> now.second
34
>>> now.microsecond
694988


可以使用combine() 方法把一个date 对象和一个time 对象合并成一个datetime 对象:
>>> from datetime import datetime, time, date                   #这里补一个基础知识,import后面可以连续跟N个对象
>>> noon = time(12)
>>> this_day = date.today()
>>> noon_today = datetime.combine(this_day, noon)
>>> noon_today

datetime.datetime(2014, 2, 2, 12, 0)


也可以使用date() 和time() 方法从datetime 中取出date 和time 部分
>>> noon_today.date()
datetime.date(2014, 2, 2)
>>> noon_today.time()
datetime.time(12, 0)


---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

使用time模块
Python 的datetime 模块中有一个time 对象,Python 还有一个单独的time 模块,这有点令
人困扰。此外,time 模块还有一个函数叫作time()。

一种表示绝对时间的方法是计算从某个起始点开始的秒数。Unix 时间使用的是从1970 年
1 月1 日0 点开始的秒数1。这个值通常被称为纪元
,它是不同系统之间最简单的交换日期
时间的方法。
time 模块的time() 函数会返回当前时间的纪元值:
>>> import time
>>> now = time.time()
>>> now
1391488263.664645
数一下位数,从1970 年新年2 到现在已经过去了超过十亿秒。时间都去哪儿了?
可以用ctime() 把一个纪元值转换成一个字符串:
>>> time.ctime(now)
'Mon Feb 3 22:31:03 2014'


纪元值是不同系统(比如JavaScript)之间交换日期和时间的一种非常有用的方法。但是,
有时候想要真正的日期而不是一串数字,这时可以使用struct_time 对象。localtime() 会
返回当前系统时区下的时间,gmtime() 会返回UTC 时间

>>> time.localtime(now)
time.struct_time(tm_year=2014, tm_mon=2, tm_mday=3, tm_hour=22, tm_min=31,
tm_sec=3, tm_wday=0, tm_yday=34, tm_isdst=0)
>>> time.gmtime(now)
time.struct_time(tm_year=2014, tm_mon=2, tm_mday=4, tm_hour=4, tm_min=31,
tm_sec=3, tm_wday=1, tm_yday=35, tm_isdst=0)


如果省略localtime() 或者gmtime() 的参数,默认会返回当前时间。
对应上面两个函数的是mktime(),它会把struct_time 对象转换回纪元值:
>>> tm = time.localtime(now)
>>> time.mktime(tm)
1391488263.0


这个值和之前now() 返回的纪元值并不完全相同,因为struct_time 对象只能精确到秒
一些建议:尽量多使用UTC 来代替时区。UTC 是绝对时间,和时区无关。如果你有服务
器,把它的时间设置为UTC,不要使用本地时间。
还有一些建议(都是免费的):如果有可能,绝对不使用夏时制时间。如果使用了夏时制
时间,那每年的一段时间(春季)会少一个小时,另一段时间(秋季)会多一个小时。出
于某些原因,许多组织在它们的计算机系统中使用夏时制,但是每年都需要处理数据重复
和丢失。说起来都是泪。




读写日期和时间
isoformat() 并不是唯一一种可以打印日期和时间的方法。前面已经见过,time 模块中的
ctime() 函数可以把纪元转换成字符串:
>>> import time
>>> now = time.time()
>>> time.ctime(now)
'Mon Feb 3 21:14:36 2014'


也可以使用strftime() 把日期和时间转换成字符串。这个方法在datetime、date 和time 对
象中都有,在time 模块中也有。strftime() 使用格式化字符串来指定输出,详见表10-1。


数字都是左侧补零。


下面是time 模块中的strftime() 函数。它会把struct_time 对象转换成字符串。我们首先                                       #记住,这里是把struct_time对象变成str!!!
定义格式化字符串fmt,然后使用它:
>>> import time
>>> fmt = "It's %A, %B %d, %Y, local time %I:%M:%S%p"
>>> t = time.localtime()
>>> t
time.struct_time(tm_year=2014, tm_mon=2, tm_mday=4, tm_hour=19,
tm_min=28, tm_sec=38, tm_wday=1, tm_yday=35, tm_isdst=0)
>>> time.strftime(fmt, t)
"It's Tuesday, February 04, 2014, local time 07:28:38PM"

如果使用date 对象的strftime() 函数,只能获取日期部分,时间默认是午夜:

>>> from datetime import date
>>> some_day = date(2014, 7, 4)
>>> fmt = "It's %B %d, %Y, local time %I:%M:%S%p"
>>> some_day.strftime(fmt)
"It's Friday, July 04, 2014, local time 12:00:00AM"


对于time 对象,只会转换时间部分
>>> from datetime import time
>>> some_time = time(10, 35)
>>> some_time.strftime(fmt)
"It's Monday, January 01, 1900, local time 10:35:00AM"
显然,你肯定不想使用time 对象的时间部分,因为它们毫无意义。


---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


如果要把字符串转换成日期或者时间,可以对同样的格式化字符串使用strptime() 函数。
这里不能使用正则表达式,字符串的非格式化部分(没有% 的部分)必须完全匹配。假设
可以匹配格式“年- 月- 日”,比如2012-01-29,如果目标字符串中用空格代替破折号
解析时会发生什么呢?
>>> import time
>>> fmt = "%Y-%m-%d"
>>> time.strptime("2012 01 29", fmt)                          #没有破折号,会报错,必须要有!!!
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Library/Frameworks/Python.framework/Versions/3.3/lib/
python3.3/_strptime.py", line 494, in _strptime_time
tt = _strptime(data_string, format)[0]
File "/Library/Frameworks/Python.framework/Versions/3.3/lib/
python3.3/_strptime.py", line 337, in _strptime
(data_string, format))
ValueError: time data '2012 01 29' does not match format '%Y-%m-%d'


如果传入strptime() 的字符串中有破折号会怎么样呢?
>>> time.strptime("2012-01-29", fmt)
time.struct_time(tm_year=2012, tm_mon=1, tm_mday=29, tm_hour=0, tm_min=0,
tm_sec=0, tm_wday=6, tm_yday=29, tm_isdst=-1)


即使字符串看起来可以匹配格式,但如果超出取值范围也会报错
>>> time.strptime("2012-13-29", fmt)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Library/Frameworks/Python.framework/Versions/3.3/lib/
python3.3/_strptime.py", line 494, in _strptime_time
tt = _strptime(data_string, format)[0]
File "/Library/Frameworks/Python.framework/Versions/3.3/lib/
python3.3/_strptime.py", line 337, in _strptime
(data_string, format))
ValueError: time data '2012-13-29' does not match format '%Y-%m-%d'



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值