惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Cybersecurity and Infrastructure Security Agency CISA
D
Darknet – Hacking Tools, Hacker News & Cyber Security
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
S
Schneier on Security
L
Lohrmann on Cybersecurity
S
Securelist
P
Palo Alto Networks Blog
SecWiki News
SecWiki News
T
Troy Hunt's Blog
H
Hacker News: Front Page
AWS News Blog
AWS News Blog
Latest news
Latest news
Hacker News - Newest:
Hacker News - Newest: "LLM"
NISL@THU
NISL@THU
The Hacker News
The Hacker News
F
Full Disclosure
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
大猫的无限游戏
大猫的无限游戏
O
OpenAI News
P
Proofpoint News Feed
Know Your Adversary
Know Your Adversary
G
GRAHAM CLULEY
博客园_首页
Attack and Defense Labs
Attack and Defense Labs
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Security Latest
Security Latest
云风的 BLOG
云风的 BLOG
K
Kaspersky official blog
WordPress大学
WordPress大学
www.infosecurity-magazine.com
www.infosecurity-magazine.com
宝玉的分享
宝玉的分享
L
LINUX DO - 热门话题
博客园 - 叶小钗
L
LINUX DO - 最新话题
Martin Fowler
Martin Fowler
N
News | PayPal Newsroom
Project Zero
Project Zero
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
PCI Perspectives
PCI Perspectives
月光博客
月光博客
IT之家
IT之家
Recent Announcements
Recent Announcements
T
The Exploit Database - CXSecurity.com
D
DataBreaches.Net
J
Java Code Geeks
酷 壳 – CoolShell
酷 壳 – CoolShell
Last Week in AI
Last Week in AI
Google Online Security Blog
Google Online Security Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知

Dvel's Blog

Rime 全拼双拼混输 CHD 油猴脚本:每日签到自动答题 Rime 配置:雾凇拼音 Hammerspoon 自动切换输入法 修复 Hugo 本地图片的累计布局偏移(CLS)问题 macOS 利用 Karabiner 修改 Emacs 键位为 Vim 键位 macOS 修改 Emacs 键位为 Vim 键位 Surge 配置 汉字的混乱 Netflix 中英双语字幕的好办法 优化 Rime 英文输入体验 判断字符是否为简体字或繁体字 Cloudflare 转入域名提示「出现了问题。请重试转移此域。尚未向您收费。」 图片压缩:Squoosh、TinyPNG、ImageOptim、WebP macOS grep + sed 批量替换多个文件的内容 在 macOS 根目录创建文件夹 博客图床小妙招 折腾 Hugo & PaperMod 主题 利用 Cloudflare Workers 进行批量 301 重定向 将博客部署在 Cloudflare Pages Alfred File Navigation(文件导航器)详解 在 Hugo Goldmark Markdown 中设置以新标签打开链接 让 Alfred 以新标签的方式打开 Finder 用 git filter-branch 给 Git 仓库瘦身 qBittorrent 设置教程 联通光猫破解+桥接记录 配置 Mac 终端走代理 Steam for Mac 中文游戏推荐 我的 Mac 软件/工具列表 《Flask Web 开发》笔记 用 sleepwatcher 让 Mac 在睡眠及唤醒时自动执行一些脚本 解决 pyenv 导致的 brew warning 《SQL 必知必会》笔记 Git 自总结 Python 异步 IO 笔记 再见,双点医院! 用 CloudXNS 解决 CNAME 与 MX 记录冲突 你好,Hugo! 为 Mac 打造 zsh command line 环境 新 Mac 新装修 秦皇岛暑期自驾的烦恼 苹果公司开发者账号申请流程 UIScrollView 中使用 Masonry 解决 CocoaPods 的类库 import 没有提示 iOS 使用 CocoaPods 的快速回顾 GitBook 简单生成本地静态 HTML 的方法 你好, Hexo! About
日期与时间(UTC、GMT、时间戳、时区)
Dvel · 2021-05-29 · via Dvel's Blog

总是记错弄乱,自己整理一份。

基本概念

格林尼治标准时间(GMT)

英语:Greenwich Mean Time,简称 GMT

是指位于英国伦敦郊区的皇家格林尼治天文台当地的平太阳时,因为本初子午线被定义为通过那里的经线。

由于地球每天的自转是有些不规则的,而且正在缓慢减速,GMT 已经被原子钟报时的 UTC 顶替

协调世界时(UTC)

英语:Coordinated Universal Time,法语:Temps Universel Coordonné,简称 UTC

其以原子时秒长为基础,是最主要的世界时间标准。

关于缩写:

国际电信联盟希望协调世界时能够在所有语言有单一的缩写。英语和法语区的人同时希望各自的语言缩写-CUT 和 TUC 能够成为国际标准,结果最后妥协使用 UTC。

GMT 与 UTC

目前能看到 GMT 字眼的,常见于 JavaScript 的 Date() 和谷歌搜索「伦敦时间」时展示的。

我也不是很理解为什么显示 GMT,但是即便显示的是 GMT,也是经过校准的,与正确时间相差不到一秒。

网络时间协议(NTP)

英语:Network Time Protocol,缩写:NTP

NTP 是一个在电脑系统之间进行时钟同步的网络协议,意图将所有参与电脑的协调世界时(UTC)时间同步到几毫秒的误差内。

自1985年以来,NTP是目前仍在使用的最古老的互联网协议之一。

时区与本地时间

一般说 UTC 时间也就是指零时区 +00:00(或写成 UTC+0、UTC±00:00) 时间,比北京时间早八个小时。

2021-01-01 08:00:00 +08:00 也就是北京时间的上午八点钟,而这时 UTC 时间为 2021-01-01 00:00:00 +00:00,英国伦敦的午夜,这是同一个时刻。

时间戳

这里指的时间戳是指代码中的 timestamp 那一串长数字。

编程中大家讨论和使用的皆是 Unix 时间戳(Unix timestamp 或 POSIX timestamp),是从 1970 年 1 月 1 日 0 时 0 分 0 秒到现在的秒数,有的语言也支持了毫秒、微秒等等。

  • 1 秒 = 1000 毫秒
  • 1 毫秒 = 1000 微秒

很多编程语言都有生成当前时间戳的方法,目前的时间戳长度:

  • 10 位长度,精确到秒
  • 13 位长度,精确到毫秒
  • 16 位长度,精确到微秒

在 2286 年 11 月 21 日 1 时 46 分 39 秒之后,时间戳会加长一位数。

时间戳有时区吗?

当我们讨论时间戳的时候,也就是前后端交换数据,数据库存储日期时间时,皆是 Unix 时间戳,时间戳是没有时区概念的。

或者可以理解为,时间戳是固定死零时区的。

2021-01-01 00:00:00+00:002021-01-01 08:00:00+08:00 的时间戳都是 1609459200

所以建议在数据库或数据传输时使用 Unix 时间戳,时间戳可以被简单地解析为 UTC 时间或任何时区的时间,不会被时区概念束缚和混淆。

ISO 8601

国际标准 ISO 8601,是国际标准化组织的日期和时间的表示方法,全称为《数据存储和交换形式·信息交换·日期和时间的表示方法》。

简单来说,日期与时间的规定写法是这样的:

2000-01-23                # 年使用四位数,月、日、时、分、秒皆使用两位数,不够的前面补零。
2000-01-23T04:05:06       # 用 T 分割日期与时间。
2000-01-23T04:05:06Z      # 用 Z 代表 UTC+0(零时区)
2000-01-23T04:05:06+00:00 # 也可以使用 +00:00 表示零时区
2000-01-23T04:05:06+08:00 # 东八区
2000-01-23T04:05:06.123456  # Python 中 datetime.now().isoformat() 的默认格式

实际上 ISO 8601 也允许了一些其他的写法。

RFC 3339 与 ISO 8601

Python 用的是 ISO 8601:

datetime.now().isoformat()
datetime.utcnow().isoformat()

Golang 用的是 RFC 3339:

time.Now().Format(time.RFC3339)
time.Now().UTC().Format(time.RFC3339)

What’s the difference between ISO 8601 and RFC 3339 Date Formats?

RFC 3339 被列为 ISO 8601 的配置文件。有一些很小的差异,比如 RFC 3339 不允许两位数的年份,RFC 3339 允许用空格代替 T

就一般的使用情况来说,两者之间可视为没有差异。

获取时间戳

Python:

import time
from datetime import datetime

# 正确的
print(time.time())
print(datetime.now().timestamp())

# 错误的
print(datetime.utcnow().timestamp())

timestamp() 经过了 Python 内部处理的,将当前的系统时间(无论你在哪个时区)转换为正确的标准的 Unix 时间戳。

而最下面的那个为什么错了,因为 timestamp() 默认你给的 datetime 是当前系统的时区,如果你在零时区,那的确没有问题;如果不在零时区,timestamp() 会认为我给的是东八区,所以最后返回了错误的时间戳。

可以解决这个错误,只需要在 timestamp() 之前将 datetime 的时区确定即可。

from datetime import datetime, timedelta, timezone

d1 = datetime.now()
d1 = d1.replace(tzinfo=timezone(timedelta(hours=8))) # 绑定时区为东八区
ts1 = d1.timestamp()
print(ts1)

d2 = datetime.utcnow()
d2 = d2.replace(tzinfo=timezone.utc) # 绑定时区为零时区
ts2 = d2.timestamp()
print(ts2)

# ts1 和 ts2 基本相等,只有程序运行顺序的微秒级差距。

Golang:

Golang 中是一样的:

time.Now().Unix()
time.Now().UTC().Unix()

因为 Golang 的 time.Now() 中默认就带有时区信息。

Python 常用的日期与时间方法

datetime 转 str

import datetime

d = datetime.datetime.now()
s = d.strftime('%Y-%m-%d %H:%M:%S')

str 转 datetime

from datetime import datetime, timedelta, timezone, time

s = "2001-02-03 04:05:06"
d = datetime.strptime(s, '%Y-%m-%d %H:%M:%S')
# 为得到的 datetime 增加时区
d_with_timezone = d.replace(tzinfo=timezone(timedelta(hours=8)))

获取当前 UTC 时间(带时区)

不加后面的 replace 就不带时区信息了,下同。

from datetime import datetime, timezone

datetime.utcnow().replace(tzinfo=timezone.utc) 
# 2021-05-29 15:28:10.913530+00:00

获取当前系统时间(带时区)

from datetime import datetime, timezone

# 在中国时区电脑上运行:
datetime.now().replace(tzinfo=timezone(timedelta(hours=8)))
# 2021-05-29 23:38:21.006309+08:00

datetime 转 时间戳

from datetime import datetime, timezone, timedelta

dt = datetime.now()
print(dt, 'datetime.now() 当前系统时间(不含时区)')
print(dt.timestamp(), '不含时区的时间,会认为是系统时间,会自动转换为正确的 UTC 时间戳')
print(dt.replace(tzinfo=timezone(timedelta(hours=8))).timestamp(), '包含东八区时区信息的,同上')
# 2021-07-16 00:15:02.730997 datetime.now() 当前系统时间(不含时区)
# 1626365702.730997 不含时区的时间,会认为是系统时间,会自动转换为正确的 Unix 时间戳
# 1626365702.730997 包含东八区时区信息的,同上

时间戳 转 datetime

from datetime import datetime

datetime.utcfromtimestamp(1609459200)
# 2021-01-01 00:00:00

datetime.fromtimestamp(1609459200, timezone.utc)
# 2021-01-01 00:00:00+00:00

datetime.fromtimestamp(1609459200)
# 2021-01-01 08:00:00

datetime.fromtimestamp(1609459200, timezone(timedelta(hours=8)))
# 2021-01-01 08:00:00+08:00

datetime 转换时区

转换前需要先确定被转换的 datetime 对象的时区,拥有时区属性的 datetime 对象可以转换为任意一个时区的日期时间。

from datetime import datetime, timedelta, timezone

utc_dt = datetime.utcnow().replace(tzinfo=timezone.utc)
print(utc_dt)   # 2021-01-01 00:00:00+00:00
bj_dt = utc_dt.astimezone(timezone(timedelta(hours=8)))
print(bj_dt)    # 2021-01-01 08:00:00+08:00
tokyo_dt = bj_dt.astimezone(timezone(timedelta(hours=9)))
print(tokyo_dt) # 2021-01-01 09:00:00+09:00