优秀的编程知识分享平台

网站首页 > 技术文章 正文

python散装笔记——5: 日期和时间(2)

nanyue 2025-02-13 13:32:14 技术文章 8 ℃

7: 将时间戳转换为日期时间

datetime 模块可以将 POSIX 时间戳转换为 ITC datetime 对象。

纪元是从 1970 年 1 月 1 日午夜开始计算的。

import time
from datetime import datetime

seconds_since_epoch=time.time() # 1734846726.456807
utc_date=datetime.utcfromtimestamp(seconds_since_epoch) # datetime.datetime(2024, 12, 22, 05, 52, 06, 456807)

8: 准确从日期中减去月份

使用 calendar 模块

import calendar
from datetime import date

def monthdelta(date, delta):
    m, y = (date.month+delta) % 12, date.year + ((date.month)+delta-1) // 12
    if not m: m = 12
    d = min(date.day, calendar.monthrange(y, m)[1])
    return date.replace(day=d,month=m, year=y)

next_month = monthdelta(date.today(), 1) # datetime.date(2025, 01, 22)

使用 dateutils 模块


import datetime
import dateutil.relativedelta

d = datetime.datetime.strptime("2013-03-31", "%Y-%m-%d")
d2 = d - dateutil.relativedelta.relativedelta(months=1) #datetime.datetime(2013, 2, 28, 0, 0)

9: 用ISO8601单文件库解析 ISO 8601 时间戳

Python 对 ISO 8601 时间戳的解析支持有限。对于 strptime,您需要知道它的确切格式。更复杂的是,日期时间的字符串化是一个 ISO 8601 时间戳,空格作为分隔符,6 位数作为分数:

str(datetime.datetime(2024, 7, 22, 9, 25, 59, 555555))
# '2024-07-22 09:25:59.555555'

但如果分数为 0,则不输出分数部分

str(datetime.datetime(2024, 7, 22, 9, 25, 59, 0))
# '2024-07-22 09:25:59'

但这两种形式的 strptime 需要不同的格式。此外,strptime 完全不支持解析带有:的分钟时区,因此可以解析 “2016-07-22 09:25:59+0300”,但不能解析标准格式 “2016-07-22 09:25:59+03:00”。

有一个名为 iso8601 的单文件库可以正确解析 ISO 8601 时间戳,而且只能解析 ISO 8601 时间戳。

它只用一个函数就能支持分数、时区和 T 分隔符:

import iso8601
iso8601.parse_date('2024-07-22 09:25:59')
# datetime.datetime(2024, 7, 22, 9, 25, 59, tzinfo=)
iso8601.parse_date('2024-07-22 09:25:59+03:00')
# datetime.datetime(2024, 7, 22, 9, 25, 59, tzinfo=)
iso8601.parse_date('2024-07-22 09:25:59Z')
# datetime.datetime(2024, 7, 22, 9, 25, 59, tzinfo=)
iso8601.parse_date('2024-07-22T09:25:59.000111+03:00')
# datetime.datetime(2024, 7, 22, 9, 25, 59, 111, tzinfo=)

如果没有设置时区,iso8601.parse_date 默认使用 UTC。可以使用 default_zone 关键字参数更改默认时区。值得注意的是,如果关键字参数为 None 而不是默认值,那么那些没有明确时区的时间戳就会以天真的日期时间返回:

iso8601.parse_date('2024-07-22T09:25:59', default_timezone=None)
# datetime.datetime(2024, 7, 22, 9, 25, 59)
iso8601.parse_date('2024-07-22T09:25:59Z', default_timezone=None)
# datetime.datetime(2024, 7, 22, 9, 25, 59, tzinfo=)

Section 5.10: 获取 ISO 8601 时间戳

不含时区,有微秒

from datetime import datetime

datetime.now().isoformat()
# Out: '2024-12-22T14:29:55.770670'

有时区,有微秒

from datetime import datetime
from dateutil.tz import tzlocal

datetime.now(tzlocal()).isoformat()
# Out: '2024-12-22T14:30:57.692109+08:00'

有时区,无微秒

from datetime import datetime
from dateutil.tz import tzlocal

datetime.now(tzlocal()).replace(microsecond=0).isoformat()
# Out: '2024-12-22T14:31:42+08:00'

11: 将包含短时区名称的字符串解析为时区感知的日期时间对象

使用 dateutil 库,就像前面解析时区感知时间戳的示例一样,也可以解析带有指定 “短 ”时区名称的时间戳。

对于使用短时区名称或缩写格式化的日期,这些时区名称或缩写通常比较含糊(例如 CST,可以是中央标准时间、中国标准时间、古巴标准时间等--更多信息请参见此处),或者不一定能在标准数据库中找到,因此有必要在时区缩写和 tzinfo 对象之间指定一个映射。

from dateutil import tz
from dateutil.parser import parse

ET = tz.gettz('US/Eastern')
CT = tz.gettz('US/Central')
MT = tz.gettz('US/Mountain')
PT = tz.gettz('US/Pacific')

us_tzinfos = {'CST': CT, 'CDT': CT,
              'EST': ET, 'EDT': ET,
              'MST': MT, 'MDT': MT,
              'PST': PT, 'PDT': PT}

dt_est = parse('2014-01-02 04:00:00 EST', tzinfos=us_tzinfos)
dt_pst = parse('2016-03-11 16:00:00 PST', tzinfos=us_tzinfos)

运行后

dt_est
# datetime.datetime(2014, 1, 2, 4, 0, tzinfo=tzfile('/usr/share/zoneinfo/US/Eastern'))
dt_pst
# datetime.datetime(2016, 3, 11, 16, 0, tzinfo=tzfile('/usr/share/zoneinfo/US/Pacific'))

值得注意的是,如果使用 pytz 时区,该方法将无法正确本地化:

from dateutil.parser import parse
import pytz
EST = pytz.timezone('America/New_York')
dt = parse('2024-02-03 09:17:00 EST', tzinfos={'EST': EST})

这只是将 pytz 时区附加到日期时间:

dt.tzinfo # Will be in Local Mean Time!
# 

如果使用这种方法,可能应该在解析后重新本地化日期时间的本地部分:

dt_fixed = dt.tzinfo.localize(dt.replace(tzinfo=None))
dt_fixed.tzinfo # Now it's EST.
# )

12: 模糊日期时间解析(从文本中提取日期时间)

可以使用 dateutil 解析器在 “模糊 ”模式下从文本中提取日期,在这种模式下,字符串中未被识别为日期的部分将被忽略。

from dateutil.parser import parse

dt = parse("Today is January 1, 2047 at 8:21:00AM", fuzzy=True)
print(dt)

dt 现在是一个日期时间对象,您将看到 datetime.datetime(2047, 1, 1, 8, 21) 打印出来。

13: 对日期进行迭代

有时,您想遍历从开始日期到结束日期的一系列日期。这可以使用 datetime 库和 timedelta 对象来实现:

import datetime

# The size of each step in days
day_delta = datetime.timedelta(days=1)

start_date = datetime.date.today()
end_date = start_date + 7*day_delta

for i in range((end_date - start_date).days):
  print(start_date + i*day_delta)

这就产生了:

2024-12-22
2024-12-23
2024-12-24
2024-12-25
2024-12-26
2024-12-27
2024-12-28

运行及结果的截图:

最近发表
标签列表