python| python中日期时间处理

随着得物越做越大越做越强, 国际化的脚步也越来越快. 国际化给程序带来2大类需要处理的问题: 语言日期时间. 这篇主要聊 日期时间处理.

词汇 abbr

很多问题往往只是语言的迷雾, 穿透语言表达的概念和定义, 就能解决很多问题.

  • area.地区 i18n.国际化.zh_CN.语言代码(iso639).国家代码(iso3166) i10n.本地化
  • dt.datetime.日期时间 date.日期 time.时间
  • tz.timezone.时区 UTC.协调世界时=GMT.格林尼治标准时.gmt loc.localtime.localWallClockTime DST.夏令时.人为
    • CST.中国标准时间=PRC=Asia/Shanghai=+0800=东八区
    • EST.美国东部标准时间 EDT.美国东部夏令时
  • ts.timestamp.时间戳
  • fmt.fromat.日期时间的显示格式

后文遇到相关词汇可以直接对照来看.

最佳实践 BestPractice

The preferred way of dealing with times is to always work in UTC, converting to localtime only when generating output to be read by humans. -- https://pypi.org/project/pytz

  • 简单概括: 在处理时间问题时, 一直使用 UTC, 只在需要展示时按照对应地区进行处理. gmt✅ loc❌
    • 只使用包含时区的时期时间数据
    • ts.时间戳 即 UTC, 需要增加 tz 信息进行 fmt
    • 处理时保持一致性: gmt 归 gmt, loc 归 loc

py 中相关包与函数

在进入代码之前, 约定 本地地区CST.中国标准时间.

  • 包: time datetime pytz calendar
    • strptime: str-parse-time
    • strftime: str-format-time
  • 相关日期时间表示: ts.时间戳 class time.struct_time(后面简写为 st) class datetime.datetime(后面简写为 dt) str.fmt
    • ts
      • st>ts: calendar.timegm(gmt_st) time.mktime(loc_st)
      • dt>ts: dt.timestamp()
    • st
      • ts>st: gmt_st=time.gmtime() loc_st=time.localtime()
      • dt>st: dt.timetuple()
      • str>st: time.strptime(str, fmt)
    • dt
      • ts>dt: datetime.fromtimestamp(ts, tz=utc) datetime.fromtimestamp(ts, tz=cst)
        • datetime.now(tz=utc)使用当前时间作为ts
        • datetime.today() 也使用当前时间作为ts, 但是无时区信息, 不建议使用
      • str>dt: dt.strptime(str, fmt)
    • str
      • st>str: time.strftime(fmt, st)
      • dt>str: dt.strftime(fmt)
  • gmt 归 gmt
    • time.gmtime() calendar.timegm()
    • utc=pytz.utc
  • loc 归 loc: 以 CST 为例
    • time.localtime() time.mktime()
    • time.zone=-28800 cst=pytz.timezone('PRC')
      py中不同时间表示

关于时期时间的显示 format

查看 formt 文档:

[图片上传失败...(image-90d990-1634529818435)]

简单示例:

import time

fmt = '%Y-%m-%d %H:%M:%S %Z%z' # 'date time timezone`
s = time.strftime(fmt, time.localtime()) # '2021-10-17 01:11:22 CST+0800'
print(s)

关于时间戳

  • 简单处理, 约定: ts.时间戳使用int, 精确到
  • 重要的事情再强调一遍: ts.时间戳 都是 UTC 下的, 需要时区信息 fmt 成 datetime str
-0800 UTC CST=+0800
ts.offset 28800s 0 -28800s
同一时刻ts相等 ts ts ts
相同日期时间的ts ts+offset ts+offset ts+offset

当前 ts:

import calendar
import time

ts = int(time.time()) # 1634447629
loc_ts = int(time.mktime(time.localtime())) # 1634447629
print(ts, loc_ts)

指定时刻的 ts:

import calendar
import time

fmt = '%Y-%m-%d %H:%M:%S %Z%z'
st = time.strptime('2021-10-17 01:11:22 CST+0800', fmt)
ts = calendar.timegm(st) # 1634433082
loc_ts = int(time.mktime(st)) # 1634433082
print(ts, loc_ts)

同一时刻

  • 同一个时刻: ts 相等, st/dt 表示的时刻相同, str 根据 fmt 变化
import calendar
import time
from datetime import datetime

import pytz

utc = pytz.utc  # utc.zone
cst = pytz.timezone('PRC')  # CST.中国标准时间=PRC=Asia/Shanghai

fmt_datetime = '%Y-%m-%d %H:%M:%S'

# 同一个时刻: ts 相等, st/dt 表示的时刻相同, str 根据 fmt 变化
# ts>st
gmt_st = time.gmtime()
loc_st = time.localtime()
# st>ts ts=gmt_ts=loc_ts
ts = int(time.time())
gmt_ts = calendar.timegm(gmt_st)
loc_ts = int(time.mktime(loc_st))
# ts>dt
gmt_dt = datetime.now(tz=utc)
loc_dt = datetime.now(tz=cst)
gmt_dt2 = datetime.today().astimezone(tz=utc)
loc_dt2 = datetime.today().astimezone(tz=cst)
gmt_ts2dt = datetime.fromtimestamp(ts, tz=utc)
loc_ts2dt = datetime.fromtimestamp(ts, tz=cst)
# dt>ts
gmt_dt_ts = int(gmt_dt.timestamp())
loc_dt_ts = int(loc_dt.timestamp())
# dt>st
gmt_dt_st = gmt_dt.timetuple()
loc_dt_st = loc_dt.timetuple()

# fmt_datetime: 不含时区的日期时间字符串
# st/dt>str
gmt_str = time.strftime(fmt_datetime, gmt_st)
loc_str = time.strftime(fmt_datetime, loc_st)
gmt_dt_str = gmt_dt.strftime(fmt_datetime)
loc_dt_str = loc_dt.strftime(fmt_datetime)
# str>st: 无时区, 不建议使用
gmt_str2st = time.strptime(gmt_str, fmt_datetime)
loc_str2st = time.strptime(loc_str, fmt_datetime)
# str>ts
gmt_str2ts = calendar.timegm(time.strptime(gmt_str, fmt_datetime))
loc_str2ts = int(time.mktime(time.strptime(loc_str, fmt_datetime)))
# str>dt
gmt_str2dt = datetime.strptime(loc_str, fmt_datetime).astimezone(tz=utc)  # ✅
gmt_str2dt2 = datetime.strptime(gmt_str, fmt_datetime).astimezone(tz=utc)  # ❌
loc_str2dt = datetime.strptime(loc_str, fmt_datetime).astimezone(tz=cst)
py日期时间: 同一时刻

相同日期时间

  • 相同零点时间, 比如 本地时间零点 2021-10-18 00:00:00
import time
from datetime import datetime

import pytz

utc = pytz.utc  # utc.zone
cst = pytz.timezone('PRC')  # CST.中国标准时间=PRC=Asia/Shanghai
fmt_date = '%Y-%m-%d'

# 相同日期时间: 当日零点
# fmt_datetime 相同: 当日零点
ts = int(time.time())
offset = time.timezone
gmt_ts_zero = ts - ts % 86400
loc_ts_zero = gmt_ts_zero + time.timezone
gmt_dt_zero = datetime.fromtimestamp(gmt_ts_zero).astimezone(tz=utc)
loc_dt_zero = datetime.fromtimestamp(loc_ts_zero).astimezone(tz=cst)
gmt_str_zero = time.strftime(fmt_date, time.gmtime(gmt_ts_zero))
loc_str_zero = time.strftime(fmt_date, time.localtime(loc_ts_zero))
loc_dt2str_zero = datetime.now(tz=cst).date()
py 相同零点日期时间
  • 相同零点时间: 某日零点时的 date 与 ts
import calendar
import time

fmt = '%Y-%m-%d %H:%M:%S %Z%z'
fmt_date = '%Y-%m-%d'

st = time.strptime('2021-10-17 01:11:22 CST+0800', fmt)
ts = calendar.timegm(st) # 1634433082
print(ts)

ts = ts - ts % 86400  # '2021-10-17 00:00:00 +0000'
d = time.strftime(fmt_date, time.gmtime(ts))
loc_d = time.strftime(fmt_date, time.localtime(ts))
print(ts, d, loc_d)

offset = time.timezone  # -28800
loc_date_ts = ts - offset  # '2021-10-16 16:00:00 +0000' '2021-10-17 00:00:00 +0800'
print(offset, loc_date_ts)
  • 任一相同日期时间字符串
import calendar
import time
from datetime import datetime

import pytz

utc = pytz.utc  # utc.zone
cst = pytz.timezone('PRC')  # CST.中国标准时间=PRC=Asia/Shanghai
s = '2021-10-18 10:57:10'
fmt_datetime = '%Y-%m-%d %H:%M:%S'
st = time.strptime(s, fmt_datetime)  # 无时区信息, 不建议使用
gmt_ts = calendar.timegm(st)
loc_ts = int(time.mktime(st))  # loc_ts=gmt_ts+time.zone
gmt_dt = datetime.strptime(s, fmt_datetime).astimezone(tz=utc)
loc_dt = datetime.strptime(s, fmt_datetime).astimezone(tz=cst)
py 任一相同日期时间

时区的那些事儿

  • py 中使用 pytz 设置时区
import pytz

utc = pytz.utc  # utc.zone
cst = pytz.timezone('PRC')  # CST.中国标准时间=PRC=Asia/Shanghai
print(pytz.all_timezones)  # 查看时区

更详细的 timezone 信息: https://en.wikipedia.org/wiki/Time_zone

  • 时间差(秒)转timezone
import time
from datetime import datetime, timezone, timedelta

seconds = 28800
ts = int(time.time())
tz = timezone(timedelta(seconds=seconds))
dt = datetime.fromtimestamp(ts, tz)
s = dt.strftime('%Y-%m-%d %H:%M:%S')
py 时间差(秒)转timezone
  • py 中修改本地时区
import os
import time

import pytz

cst_off = time.timezone # -28800
os.environ['TZ'] = 'UTC'
time.tzset()
off = time.timezone
print(cst_off, off) # 0

写在最后

再强调下最佳实践:

  • 所有处理都在 UTC 下, 只在需要 fmt 时转成对应时区
  • ts 即 UTC, 需要 tz 信息进行 fmt
  • 不建议使用不带时区信息的日期时间表示格式(st dt str)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,386评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,142评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,704评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,702评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,716评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,573评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,314评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,230评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,680评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,873评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,991评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,706评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,329评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,910评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,038评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,158评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,941评论 2 355

推荐阅读更多精彩内容