博采众长穿梭时空|Maya库使用笔记

Maya简介

用time、datetime等内置库处理时区需要挺多的代码,而且写法很不优雅,Maya是一个不错的第三方时间库,在pytz、pendulum等库基础上增强了对时区的处理。
Maya的时间对象是自定义的MayaDT对象,是按时间戳表示的,因此在时区问题上更容易进行转换了。从功能上看,Maya的时间创建能力上排名前列,在时间偏移和属性获取上方面接口也挺简洁,综合来看是不错的Python时间库,在GitHub上目前有3.2k的star

时间输入与转换

Maya提供了丰富的接口用于从各种数据中解析出时间对象,既有简约的from_datetime()把datetime对象转为MayaDT时间对象,也有强大的when()parse()从字符串中解析时间要素。一些示例代码如下。

1
2
3
4
5
6
7
8
9
10
11
import maya
maya.parse('2020-12-08T03:15') #字符串转maya时间对象
#Out[]:<MayaDT epoch=1607397346.636102>
maya.when('1011-02-07') #因为是用的epoch,小于1970年是负数
#<MayaDT epoch=-30259958400.0>
dt=maya.now() #获取当前时间
maya.when('tomorrow') #明天的这个时候,直接从自然语言转MayaDT
maya.MayaDT.from_datetime(datetime.now()) #datetime对象转MayaDT
maya.MayaDT.from_struct(time.gmtime())
maya.MayaDT(1606533154) #时间戳转Maya时间对象
dt.day #获取时间要素属性

Maya库记录时间对象是用epoch时间戳,表示的是时间基准点至特定时间dt的总秒数,该基准点在Unix及类Unix系统中是格林威治时间1970年01月01日00时0分0秒,也称为Unix时间戳(Timestamp)。
Maya可以充分地把其他基础库的时间对象转为MayaDT对象。
另一方面,把一个MayaDT对象转为datetime对象或者转换为字符串也挺简单。

  • dt.datetime():把dt转为datetime对象;
  • dt.date:转为datetime库的date对象,也就是只保留年月日,date后面没有小括号;
  • dt.epoch:输出时间戳;
  • dt.iso8601():输出符合ISO-8601标准 的字符串,例如’2020-12-07T00:00:00Z’;对应的还有dt.rfc3339()dt.rfc2822()

要输出为自定形式的字符串会麻烦一些,没有format方法可以用,需要用maya.Datetime.strftime(dt.datetime(),fmt)进行转换,fmt是time模块所支持的占位字符串,例如’%Y-%m-%d %H:%M:%S’。这里maya.Datetime就是用的datetime库的strftime。

属性获取与特性

MayaDT展示的虽然是epoch一个浮点数,其获取时间对象的年月日等时间要素的接口并不少,可以很自然地通过dt.day等得到时间要素,和datetime没有隔阂,year、month、second等都有,通过dt.timezone获取时区。其默认的时区是UTC的,其特性是获取属性时是转换为datetime再获取属性的。

1
2
3
4
5
6
7
8
9
10
11
12
dt=maya.parse('2020-12-07')
dt.year #2020
dt.timezone #UTC
dt.local_datetime()
dt.local_timezone
dt.iso8601()
dt.slang_time() #输出为自然语言

class MayaDT(object):
@property
def year(self):
return self.datetime().year

Maya也是支持自然语言的输出的,只需要使用dt.slang_time(),也可以结合时间偏移功能连缀使用。slang是俚语的意思。MayaDT有slang_time和slang_date两个方法可以使用,slang_date更专注在日期维度的表达。

1
2
3
4
5
6
7
8
9
dt=maya.when('2020, 12, 7')
dt.slang_time()
# '8 hours ago'
dt.add(days=10).slang_time()
# 'in 1 week'
dt.snap('@d+3h').slang_time()
# '5 hours ago'
dt.slang_date()
# 'today'

时间偏移及序列

Maya对时间偏移抽象的接口是add和subtract,和其他库接口一致。dt.subtract(days=1)代表dt向前推移1天,输入的参数是years、days这些,数值可以为负数,subtract(days=-1)和add(days=1)效果是一致的。另外一种简写的方法是使用snap,例如dt.snap('@d+3h')表示在dt当天的基础上加3个小时,只要符合规则,可以写dt.snap("+8h@d+1d+11h") 这类复杂的操作,这三个方法生成的是新对象,不是直接修改原dt对象。
Maya的snap方法是调用的snaptime库,具体snap字符串参数的规则可以看snaptime文档

Maya要生成一个时间序列可以使用maya.intervals或者MayaInterval类,实例如下。

1
2
3
4
5
6
list(maya.intervals(start=maya.now(),
end=maya.now().add(days=1),
interval=60*60))
#生成start到end的每小时间隔的时间值序列

[i for i in maya.MayaInterval(start=now, end=now.add(hours=1))]

MayaInterval的参数有start、end和duration,duration间隔单位也是秒。

总结

Maya通过把时间统一表示为时间戳避免了各种时区问题,能够达到独立于系统和机器环境,站在datetime、pendulum、snaptime等模块的肩膀上,实现了各种实用的时间计算方法,增强了对时区的处理,在满足基本功能的基础上,别有特色地简化了满足ISO-8601、RFC-2822时间表达字符串的输入输出。

参考资料