说明
《Python 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
Python 的 datetime 模块提供用于处理日期和时间的类。在支持日期时间数学运算的同时,实现的关注点更着重于如何能够更有效地解析其属性用于格式化输出和数据操作。
如 datetime.date,datetime 有以下几种对象类型:
类型 | 描述 |
---|---|
date | 简单型日期,以公历为原型, 属性: year, month, day |
time | 理想的一天时间,假设每天等于 246060 秒 ,无闰秒 ,属性: hour, minute, second, microsecond 和 tzinfo |
datetime | 日期和时间的结合,属性:year, month, day, hour, minute, second, microsecond, tzinfo |
timedelta | 两个时间或者日期的间隔时间,精确到微秒 |
tzinfo | 描述时区信息对象的抽象基类,处理时区及夏令时等问题 |
timezone | 实现了 tzinfo 抽象基类的子类,用于表示相对于 世界标准时间(UTC)的偏移量 |
他们的继承关系:
object
time
timedelta
date
datetime
tzinfo
timezone
我们知道,时间具有一定的地域性,一般就一个时间时会说北京时间或者美国东部时间。因此,时间中可分为感知型(Aware)和简单型(Naive),简单型就是没有时区信息的时间类型,感知型会数据时间对象的计算、生成物理位置为判断并给定时区。
规则为:
time 的判断方法是,设实例为t:
datetime 的判断方法是,设实例为d:
timedelta 不适用两种类型区分。两种类型时间可以转换,后文会介绍时区的转换方法。
date 对象代表一个理想化公历历法中的日期(年、月和日),即当今的格列高利历向前后两个方向无限延伸。公元 1 年 1 月 1日是第 1 日,公元 1 年 1 月 2 日是第 2 日,依此类推。
# 创建方法,所有参数都是必要且在要求的范围内
datetime.date(year, month, day)
参数不符合要求会抛出 ValueError 异常,范围要求:
同时,日期也要真实存在,否则也会报错,如:
# 不存在的日期
date(2021, 2, 29)
# ValueError: day is out of range for month
from datetime import date
date.today() # 当天日期
# datetime.date(2020, 11, 29)
# 转换自时间戳,忽略闰秒
date.fromtimestamp(1606639383)
# datetime.date(2020, 11, 29)
# 格列高利历序号的日期,其中公元1年1月1日的序号为 1
date.fromordinal(2020)
# datetime.date(6, 7, 13)
# 根据标准字符串返回日期类型
date.fromisoformat('2019-11-12')
# datetime.date(2019, 11, 12)
# 逆操作
date.isoformat(date(2019, 11, 12))
# '2019-11-12'
# 指定年第几周(第一周是完整周)内的第几天是哪天
date.fromisocalendar(2021, 1, 3)
# datetime.date(2021, 1, 6)
# 逆操作
date.isocalendar(datetime.date(2021, 1, 6))
# (2021, 1, 3)
# 支持最大最小日期
date.min
# datetime.date(1, 1, 1)
date.max
# datetime.date(9999, 12, 31)
# 两个日期对象的最小间隔
date.resolution
# datetime.timedelta(days=1)
# 创建实例
d = date(2020, 11, 12)
d # datetime.date(2020, 11, 12)
# 日期的年月日数字
d.year # 2020
d.month # 11
d.day # 12
布尔运算时 date 都会被认为是真值,支持的运算:
# 一个日期等于另外一个日期加上间长
date2 = date1 + timedelta
# 也可以减去时长计算得到
date2 = date1 - timedelta
# 两个日期想减得到一个 timedelta 时长对象
timedelta = date1 - date2
# 两个日期可以比较大小,得到布尔值
date1 < date2
# ctime() 风格字符
d.ctime() # 'Tue Nov 12 00:00:00 2020'
# 日历元组
d.isocalendar() # (2020, 46, 4)
# 标准字符格式
d.isoformat() # '2020-11-12'
# 星期几
d.isoweekday() # 4 周四
d.weekday() # 3 从0开始的周序号
# 替换对年月日,月份
d.replace(month=10) # datetime.date(2020, 10, 12)
# 格式化为字符串,参见官网格式代码
d.strftime('%Y年%m月%d') # '2020年11月12'
# 返回一个 time.struct_time, 见 time 对象介绍
d.timetuple()
# time.struct_time(tm_year=2020, ..., tm_min=0,
# tm_sec=0, tm_wday=3, tm_yday=317, tm_isdst=-1)
# 格列高利历序号
d.toordinal() # 737741
注意:datetime 由于是 date 了类,也支持上述这些方法,介绍到 datetime 的时候我还会再提。
一个 time 对象代表某日的(本地)时间,它独立于任何特定日期,并可通过 tzinfo 对象来调整为可感知的时间类型。
# 所有参数是可选的,参数有范围限制
datetime.time(hour=0, minute=0,
second=0, microsecond=0,
tzinfo=None, *, fold=0)
要来引发 ValueError ,需要按各参数的范围:
from datetime import time
# 早最的可表示
time.min # time, time(0, 0, 0, 0)。
# 最晚的可表示
time.max # time, time(23, 59, 59, 999999)。
# time 对象之间可能的最小间隔, time间不支持算术运算
time.resolution # timedelta(microseconds=1)
# 标准格式字符串转时间类型
time.fromisoformat('14:15:16')
# datetime.time(14, 15, 16)
from datetime import time
from datetime import timezone
t = time(hour=12, minute=13, second=14,
microsecond=15, tzinfo=timezone.utc, fold=0)
t # datetime.time(12, 13, 14, 15, tzinfo=datetime.timezone.utc)
# 时分秒毫秒数字
t.hour # 12
t.minute # 13
t.second # 14
t.microsecond # 15
# 时区
t.tzinfo # datetime.timezone.utc
# 边界时间, 0 早于此时间
t.fold # 0
运算方面,支持比较运算,不支持数学运算,布尔运算时 time 总为真值。简单型而另一方是感知型,则如果尝试进行顺序比较将引发 TypeError。对于相等比较,简单型实例将永远不等于感知型实例。
# 替换指定时间单位
t.replace(hour=10)
# datetime.time(10, 13, 14, 15, tzinfo=...utc, fold=1)
# 标准时间字符串,有单位为0样式不同
t.isoformat() # 同 t.__str__()
# '12:13:14.000015+00:00'
# 截止指定单位,无效单位 ValueError
t.isoformat(timespec='minutes')
# '12:13+00:00'
# 格式化为字符串
t.strftime('%H时%M分%S秒') # '12时13分14秒'
t.__format__('%H时%M分%S秒') # 同上
# 与 utc 的时差,偏移
t.utcoffset() # datetime.timedelta(0)
# 时区名称
t.tzname() # 'UTC'
# 夏令时(DST): 无
t.dst() # None
datetime 除了年月日还包含时分秒毫秒时间信息,datetime 对象是包含来自 date 对象和 time 对象的所有信息的单一对象。
之前提到,datetime 由于是 date 了类,也支持 date 的各种操作方法,因此这里可能不介绍上边 date 介绍过的内容。
用如下形式构造,参数的取值范围同 date 和 time 相应部分的参数范围:
# year, month 和 day 参数是必须的
datetime.datetime(year, month, day,
hour=0, minute=0, second=0,
microsecond=0, tzinfo=None, *, fold=0)
会返回一个 datetime 对象。
# 支持最大最小时间
datetime.max
# datetime.datetime(9999, 12, 31, 23, 59, 59, 999999)
datetime.min
# datetime.datetime(1, 1, 1, 0, 0)
# 两个 datetime 最小间隔
datetime.resolution
# datetime.timedelta(microseconds=1)
# 当前时间
datetime.today()
# datetime.datetime(2020, 11, 29, ..., 77277)
import time
datetime.fromtimestamp(time.time()) # 同上
datetime.now(tz=None) # 同上,但可以传时间
# 当前的 utc 时间,时区为 None
datetime.utcnow()
# datetime.datetime(2020, 11, 29,..., 561958)
# 建议创建感知型当前时间
datetime.now(timezone.utc)
# 通过时间戳返回 datetime
datetime.fromtimestamp(1606650705, tz=None)
# datetime.datetime(2020, 11, 29, 19, 51, 45)
# 假定时间戳时间为 utc 时间
datetime.utcfromtimestamp(1606650705)
# datetime.datetime(2020, 11, 29, 11, 51, 45)
# 格列高利历序号
datetime.fromordinal(2020)
# datetime.datetime(6, 7, 13, 0, 0)
# 日期和时间拼合成一个 datetime, 如传入 datetime 忽略时间部分
from datetime import date, time, datetime
datetime.combine(date(2020,11,12), time(13,14,15), tzinfo=None)
# datetime.datetime(2020, 11, 12, 13, 14, 15)
# 从标准格式字符串转为 datetime
datetime.fromisoformat('2020-11-12 13:14:15')
# datetime.datetime(2020, 11, 12, 13, 14, 15)
# 带时区的
datetime.fromisoformat('2020-11-12T04:05:06+04:00')
# datetime.datetime(2020, 11, 12, 4, 5, 6,
# tzinfo=datetime.timezone(datetime.timedelta(seconds=14400)))
# 返回以 year, week 和 day 值指明的 ISO 历法日期所对应的 datetime
datetime.fromisocalendar(2021, 1, 1)
# datetime.datetime(2021, 1, 4, 0, 0)
# 逆操作
datetime.isocalendar(datetime(2021, 1, 4, 0, 0))
# (2021, 1, 1)
# 已知格式从字符中解析出时间
datetime.strptime('2020年11月12的13点', '%Y年%m月%d的%H点')
# datetime.datetime(2020, 11, 12, 13, 0)
# 各时间单位的值
t.year # 2020
t.month # 11
t.day # 29
t.hour # 12
t.minute # 12
t.second # 47
t.microsecond # 88702
# 时区
t.tzinfo # None
# 边界
t.fold # 0 早于
布尔运算时 datetime 都会被认为是真值,支持的运算:
# 一个日期时间等于另外一个日期时间加上间长
datetime2 = datetime1 + timedelta
# 也可以减去时长计算得到
datetime2 = datetime1 - timedelta
# 两个时间相减得到一个 timedelta 时长对象
timedelta = datetime1 - datetime2
# 两个日期时间可以比较大小,得到布尔值
datetime1 < datetime2
注:较早的时间小于较晚的时间。
# 部分时间
t.date() # date 类型及部分
# datetime.date(2020, 11, 29)
t.time() # time 类型及部分
# datetime.time(12, 12, 46, 88702)
t.timetz() # 带时区信息的时间对象 time
# 替换指定单位, datetime 构造方法中的都可替换如时区、fold
t.replace(year=2021, day=10)
# datetime.datetime(2021, 11, 10, ..., 88702)
# 转换时区
t.astimezone(timezone.utc)
# datetime.datetime(2020, 11, 29, 4, 12,
# 46, 88702, tzinfo=datetime.timezone.utc)
# 和 utc 的时差
t.astimezone(timezone.utc).utcoffset()
# datetime.timedelta(0)
# 夏令时
t.dst() # None
# 时区名称
t.astimezone(timezone.utc).tzname()
# 'UTC'
# 返回 struct_time, 可迭代
t.timetuple()
# time.struct_time(tm_year=2020, tm_mon=11,
# tm_mday=29, tm_hour=12, tm_min=12, tm_sec=46,
# tm_wday=6, tm_yday=334, tm_isdst=-1)
[i for i in t.timetuple()]
# [2020, 11, 29, 12, 12, 46, 6, 334, -1]
t.utctimetuple() # tm_isdst 会强制设为0
# 格列高利历序号
t.toordinal() # 737758
# 返回时间戳
t.timestamp() # 1606623166.088702
# 整数代表星期几,0是周一
t.weekday() # 6 周日
# 整数代表星期几,1是周一
t.isoweekday() # 7
# 返回 year, week 和 weekday 的 named tuple
t.isocalendar() # (2020, 48, 7)
# 返回标准格式
t.isoformat()
# '2020-11-29T12:12:46.088702'
t.isoformat('B')
# '2020-11-29B12:12:46.088702'
t.isoformat('T', 'hours') # '2020-11-29T12'
# ctime 风格字符
t.ctime()
# 'Sun Nov 29 12:12:46 2020'
t.strftime('%Y年%M月%d日 %H:%M:%S')
t.__format__('%Y年%M月%d日 %H:%M:%S')
# '2020年12月29日 12:12:46'
timedelta 对象表示两个 date(注意:datetime 是它的子类) 之间或者 time 之间的时间间隔。
# 所有参数都是可选的并且默认为 0
datetime.timedelta(days=0, seconds=0, microseconds=0,
milliseconds=0, minutes=0,
hours=0, weeks=0)
这些参数可以是整数或者浮点数,也可以是正数或者负数。只有 days, seconds 和 microseconds 会存储在内部。 参数单位的换算规则如下:
并且 days, seconds, microseconds 会经标准化处理以保证表达方式的唯一性,即:
timedelta.min # 最小时长,反向时长
# datetime.timedelta(days=-999999999)
timedelta.max # 最大时长
# datetime.timedelta(days=999999999, seconds=86399, microseconds=999999)
timedelta.resolution # 时长最小间隔
# datetime.timedelta(microseconds=1)
td = timedelta(seconds=999999)
td
# datetime.timedelta(days=11, seconds=49599)
# 时长天数
td.days # 11
# 时长秒数
td.seconds # 49599
# 时间毫秒数
td.microseconds # 0
时长支持多样的运算:
# 两个时长相加
t2 + t3
# 两个时长相减
t2 - t3
# 时长加倍
t2 * 3
# 浮点相乘
f * t2
# 相除,倍数
t2 / t3
# 取余
t2 // i
t2 // t3
t2 % t3
# 商和余数
q, r = divmod(t1, t2)
# 取反
+t1
-t1
# 绝对值
abs(t)
# 转为字符
str(t)
# 对象的字符串表示形式
repr(t)
# 时长的秒数
td.total_seconds()
# 999999.0
# 转其他时间单位可以除以相应秒数
# 长时小时
td.total_seconds()/(60*60)
# 277.7775
datetime.tzinfo 这是一个抽象基类,也就是说该类不应被直接实例化。 请定义 tzinfo 的子类来捕获有关特定时区的信息。
一般不常用,其功能用三方库代替,可参考官网进行学习。
timezone 类继承与基类 tzinfo,它的每个实例都表示一个由 UTC 的固定偏移量定义的时区。此类的对象不可被用于代表某些特殊地点的时区信息,这些地点在一年的不同日期会使用不同的时差,或是在历史上对民用时间进行过调整。
# offset 必传
datetime.timezone(offset, name=None)
参数解析:
如:
from datetime import timezone, timedelta, datetime
offset = timedelta(hours=8)
bjtz = timezone(offset, name='北京时间')
t = datetime.now(tz=timezone.utc)
t # utc 时间
# datetime.datetime(2020, 11, 29, 13, 50, 35, 13639,
# tzinfo=datetime.timezone.utc)
bj_t = t.astimezone(tz=bjtz) # 转为北京时间
bj_t
# datetime.datetime(2020, 11, 29, 21, 50, 35, 13639,
# tzinfo=datetime.timezone(datetime.timedelta(seconds=28800), '北京时间'))
bj_t.tzname()
# '北京时间'
另外,dateutil 三方库可轻松解决时区的问题,可了解学习。
strftime() 和 strptime() 都是与时间对象和时间字符串之间的转换操作,区别为:
strftime | strptime | |
---|---|---|
简述 | f 意为 format 格式化 | p 意为 parse 解析 |
功能用法 | 时间对象转为字符串 | 字符串转为 datetime 对象 |
方法类型 | 实例方法 | 类方法 |
有此方法的对象 | date; datetime; time | datetime |
语法 | objet.strftime(format) |
datetime.strptime(date_string, format) |
关于 p 的其他一些理解:produce、Pointer 注、Parser、Posix、Put。
关于 strftime 的格式符号可参考:Python Strftime 时间字符格式化备忘速查手册。
示例:
from datetime import datetime
# 转为字符
time = datetime.now()
time.strftime('%Y-%m-%d')
# '2021-01-28'
# 转为时间
from datetime import datetime
datetime.strptime('2021-01-28', '%Y-%m-%d')
# datetime.datetime(2021, 1, 28, 0, 0)
两个常量:
import datetime
# 允许的最大最小年份
datetime.MAXYEAR # 9999
datetime.MINYEAR # 1
更新时间:2022-02-13 11:20:28 标签:pythone 内置库 时间