前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >探究Python时间处理模块

探究Python时间处理模块

作者头像
Python中文社区
发布2018-01-31 13:01:28
9320
发布2018-01-31 13:01:28
举报
文章被收录于专栏:Python中文社区

不管是哪门语言,碰触时间处理相关议题时,如果开发者要认真面对,往往都会感到异常复杂。

复杂来自两个部份:时间本身就因为历史、经济、政治等考量而复杂,API本身的设计经常令人困惑或易于犯错。

因此,如果想要避开后者,唯一能凭藉的,就是对于前者的认识。

旧有的time模块

对于时间处理,Python内建的标准程式库有著两个模块,旧有的time模块,以及自Python 2.3开始出现的datetime模块。不少文件或书籍两者都会介绍,并且鼓励开发者应该使用datetime模块。

然而,实际上,并不是那么简单的分野。毕竟,在Python 3.x之中,time模块还是存在的,从2.3到3.x这么长的时间裡,都未被废弃,突显了time模块仍有其存在的价值。

第一个价值来自于time函式。

因为,这表示了一个绝对时间:自epoch开始至今经过的秒数。虽然大多数的系统epoch,都会是1970年1月1日0时0分0秒,不过,gmtime(0)可以告诉开发者正确的答案,尽管API上有gmt字样,实际上,表示了UTC。即便有许多开发者不知道这个事实,然而,GMT时间经常不严谨(且有争议性)地被当成是UTC时间。

其他有价值的部分,则是mktime函数与struct_time。

struct_time是个桥梁,担任著人类时间概念与机器时间概念之间的转换工作。如果开发者手中有个包含了时间各属性的struct_time实例,可以透过mktime转换为epoch秒数。举例来说,开发者若手中有个代表人类时间概念的datetime实例,可以透过timetuple方法取得struct_time,这样就能透过mktime转换为epoch秒数。

除此之外,对于time模块中其他API,基本上,就不鼓励使用了。

这特别是由于time模块中许多行为,都与底层平台相依,它们会呼叫平台上的C程序库,而有些函数底层可能行为不同或不支援,像是time.tzset()就只在Unix环境中,才可使用,这连带使得strptime函数在某些情况下,无法正常运作。

使用time模块来进行时间运算,或者是时区处理,也是极度不建议的尝试。

人类时间概念的datetime模块

人类在时间的表达上,有时只需要日期、有时只需要时间,有时会一起表达日期与时间,而且,通常不会特别声明时区,可能只会提及年、月、年月、月日、时分秒等,简而言之,人类在时间概念的表达,大多是笼统、片段的资讯。

Python的datetime模块,基本上可用来表达人类的时间概念。因为当中的datetime、date、time预设没有时区资讯,单纯用来表示一个日期或时间,不过这是API上的定义。若程序运行时不需处理时区转换问题,通常所在时区就暗示著是datetime、date、time的时区,因为人们若不特别提及时区,其实就是指本地时区居多。在《Effective Python》中的〈做法45〉,就建议:「本地时钟使用datetime而非time」。

datetime模块中,有一个不错的设计是,datetime本身不可变动(immutable),也考量了时间运算的问题,可以使用timedelta方法指定days、seconds、microseconds、milliseconds等单位,来建立一个时间计量(duration),这支援了+、-、*、/、//、%甚至abs等运算。因此,想知道现在的时间3天又5小时28分之后,会是什么时间,只要撰写datetime.now() + timedelta(days = 3, hours=-5, minutes = 28)就可以了。

不过,就算使用了datetime或date的today(),或者是datetime的now()、utcnow(),谨记著它们也是不带时区资讯的,因此严格来说,开发者不能说datetime.utcnow()建立的datetime实例,代表著UTC时间。例如,datetime.utcnow()若建立了datetime(2016, 5, 23, 6, 55, 30, 505080),这纯粹就只是代表著:「2016年 5月23日6点55分30秒505080微秒」这个时间概念罢了。

复杂的时区处理

对于日期与时间的处理议题上,只要涉及时区,往往就会变得极端复杂,因为牵涉了地理、法律、经济、社会,甚至政治等问题。

例如,Python的datetime实例在建立时,可以透过tzinfo参数指定时区资讯,这必须是tzinfo的实例,然而tzinfo是个抽象类别,Python官方文件中,提供了一些如何实作tzinfo子类别的范例,并且自Python 3.2起,新增了timezone类别作为tzinfo的子类别,用来提供基本的UTC偏移时区实作,其中的timezone.utc,就是指偏移为0小时的UTC时间。

因此,现在可以正式做个区分了。datetime(1975, 5, 26, 3, 20, 50, 0)只是个时间,然而t = datetime(1975, 5, 26, 3, 20, 50, 0, tzinfo = timezone.utc)就可以说它是个代表著UTC时间了,当我们想要转换至中国台湾时区的时间,由于中国台湾时区基本上就是偏移8个小时,所以,我们可以撰写为t.astimezone(timezone(offset = timedelta(hours = 8))。

不过,Python内建的timezone只单纯考量了UTC偏移,不考量日光节约时间等其他因素,若需要timezone以外的其他时区定义,目前来说,得额外安装社群贡献的pytz模块(PEP431规范了时区支援的改进,未来可能取代pytz模块)。而pytz模块使用的是Olson时区资料库,是许多语言及作业系统的时区资料来源。

尽管如此,时区与时区之间的转换,依旧复杂而麻烦,因此若应用程式需要储存时间资讯,或甚至进行时间运算,常见的建议是使用绝对的UTC时间,然后,在需要时,再透过astimezone的帮忙,转换为当地时区。

举个例子来说,应用程式在储存留言时间时,可以使用UTC时间,然而网页上要把时间呈现给使用者看时,才依照UTC时间转为对应时区的时间。如果需要在应用程式之间交换时间资讯,以UTC时间来作为交换,也会是个好选择。

语言间真正能过渡的部份

如果开发者从未认真处理过时间的问题,对于以上的时间概念,像是epoch、GMT、UTC等没有明确的认知,等到开始面对time或datetime模块等,也许会感到十分困惑。

针对时区的处理,开发者更可能不解API在使用上何以如此复杂,若是如此,建议了解几个需要知道的时间概念,虽然这边是在讲Python,然而过去探查JDK时间API演进而获取的时间知识,却是非常的受用。

举例而言,我就曾一度被datetime的now()、utcnow(),以及today()等混淆,误认为它们带有时区的概念。然而,后来我开始察觉到它们传回的物件上tzinfo是None,这令人迅速联想到JSR310的LocalDateTime、LocalDate、LocalTime等类别,以及背后所代表的概念。于是,我将time模块与datetime模块,整个重新探查了一遍,理清机器时间与人类时间概念间的差别,接下来,相关API如何使用,也就明朗起来了。

其实时间处理只是一个例子,在探查处理特定议题的API时,对于该门议题的背景知识,往往比找出API的参数、传回值、相依性等外在形式来得重要。

事实上,背景知识能引导开发者思考,如何正确地使用API,避开那些令人困惑的误区,这才是语言间真正能过渡的部份。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2016-11-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python中文社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档