日期文本互转,时间戳,时间差 以及 时区变换

时光怂恿深爱的人放手 提交于 2020-04-29 13:14:43

2019-05-25 重新编辑了一下

以下基本我在日常写代码中,最常用的一些日期相关部分。

1、当前时间转文本strftime()

无论是timedatetime,哪个模块都可以,具体怎么输出,自行调整格式参数'%Y-%m-%d %H:%M:%S'

%字符 表意 数值范围
%y 年(2位) 00, 01, …, 99
%Y 年(4位) 0001, 0002, …, 2013, 2014, …, 9998, 9999
%m 01, 02, …, 12
%d 01, 02, …, 31
%H 时(24小时制) 00, 01, …, 23
%M 00, 01, …, 59
%S 00, 01, …, 59
%f 毫秒 000000, 000001, …, 999999
%z 时区 (empty), +0000, -0400, +1030, +063415, -030712.345216
%a 工作日作为语言环境的缩写名称。
太阳,周一,......,周六(en_US);
所以,Mo,...,Sa(de_DE)
 
%A 平日作为语言环境的全名。
星期日,星期一,......,星期六(en_US);
Sonntag,Montag,......,Samstag(de_DE)
 
%w 工作日为十进制数,其中0表示星期日,6表示星期六。 0,1,...,6  
%d 作为零填充十进制数的月中的某一天。 01,02,...,31  
%b 月份为区域设置的缩写名称。
Jan,Feb,...,Dec(en_US);
Jan,Feb,...,Dez(de_DE)
 
%B 月份为区域设置的全名。
1月,2月,...,12月(en_US);
Januar,Februar,...,Dezember(de_DE)
 
%m 月份为零填充十进制数。 01,02,...,12  
%y 没有世纪的年份为零填充十进制数。 00,01,...,99  
%Y 年份以世纪为十进制数。 1970年,1988年,2001年,2013年  
%H 小时(24小时制)作为零填充十进制数。 00,01,...,23  
%I 小时(12小时制)作为零填充十进制数。 01,02,...,12  
%p Locale相当于AM或PM。
AM,PM(en_US);
上午,下午(de_DE)
 
%M 分钟为零填充十进制数。 00,01,...,59  
%S 其次是零填充十进制数。 00,01,...,59  
%f Microsecond为十进制数,左侧为零填充。 000000,000001,...,999999  
%z UTC偏移量,格式为+ HHMM或-HHMM(如果对象是天真的,则为空字符串)。 (空),+ 0000,-0400,+ 1030  
%Z 时区名称(如果对象是天真的,则为空字符串)。 (空),UTC,EST,CST  
%j 一年中的一天作为零填充十进制数。 001,002,...,366  
%U 作为零填充十进制数的一年中的周数(星期日作为一周的第一天)。在第一个星期日之前的新年中的所有日子都被认为是在第0周。 00,01,...,53  
%W 一年中的周数(星期一作为一周的第一天)作为十进制数。在第一个星期一之前的新年中的所有日子被认为是在第0周。 00,01,...,53  
%c Locale的适当日期和时间表示。
1988年8月16日星期二21:30:00(en_US);
Di 16 Aug 21:30:00 1988(de_DE)
 
%x Locale的适当日期表示。
08/16/88(无);
1988年8月16日(en_US);
19.08.1988(de_DE)
 
%X Locale的适当时间表示。
21:30:00(zh_);
21:30:00(de_DE)
 
%% 文字'%'字符。  

这里只列一下我用到的,更多可以看官方文档:
https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior

【注意】:
time、datetime两种时间模块虽然都有strftime,但是(格式,时间)参数位置正好相反。

time模块(格式在前,时间在后)

import time
t = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime())
print(type(t),t)

# 输出结果
<class 'str'> 2019-05-25 08:56:45
 

datetime模块(格式在后,时间在前)

import datetime
dt = datetime.datetime.strftime(datetime.datetime.now(),'%Y-%m-%d %H:%M:%S')
print(type(dt),dt)

# 输出结果
<class 'str'> 2019-05-25 08:56:45

2、文本转日期

(1)常规方法strptime("日期时间文本","文本格式")

制定时间格式,进行解析

import datetime
dt = datetime.datetime.strptime('2019-05-25T07:46:45.743+0000','%Y-%m-%dT%H:%M:%S.%f%z')
print(type(dt),dt)

# 输出结果
<class 'datetime.datetime'> 2019-05-25 07:46:45.743000+00:00
 

(2)万能方法parse("日期时间文本")

自动解析

easy_install python-dateutil

pip install python-dateutil

from dateutil.parser import parse
dt = parse('2019-05-25 07:46:45')
print(type(dt),dt)

# 输出结果
<class 'datetime.datetime'> 2019-05-25 07:46:45
 

该方法适用于很多类型时间格式,建议使用前自行测试

dt = ["2001.07.04 AD at 12:08:56 PDT",
"Wed, 4 Jul 2001 12:08:56 -0700",
"190525","2018-08-06T10:00:00.000Z",
"Wed, Jul 4",
"12:08 PM",
"02001.July.04 AD 12:08 PM",
"20190525083855-0700",
"2001-07-04T12:08:56.235-0700",
"Thu Oct 16 07:13:48 GMT 2014"]

for i in dt:
	print(parse(i))

# 输出结果
2001-07-04 12:08:56
2001-07-04 12:08:56-07:00
2025-05-19 00:00:00
2018-08-06 10:00:00+00:00
2019-07-04 00:00:00
2019-05-25 12:08:00
2001-07-04 12:08:00
2019-05-25 08:38:55-07:00
2001-07-04 12:08:56.235000-07:00
2014-10-16 07:13:48+00:00
 

但是注意,国外日期时间的常用格式和国内不一样。单写19-05-25会被解析成2025年5月19日

print(parse("19-05-25"))

# 输出结果
2025-05-19 00:00:00
 

 

如果是2019-05-25就不会错了

print(parse("2019-05-25"))

# 输出结果
2019-05-25 00:00:00
 

3、时间戳相关

生成10或13位时间戳(做一些网页爬虫或构造提交时候可能用到)

import time
t = time.time()
print(type(t),t)
print('10位时间戳:',str(int(t)))
print('13位时间戳:',str(int(t*1000)))

# 输出结果
<class 'float'> 1558750679.0872486
10位时间戳: 1558750679
13位时间戳: 1558750679087
 

 

时间戳转日期时间

import datetime
ts = '1517302458364'
dt1 = datetime.datetime.fromtimestamp(float(ts)/10**(len(ts)-10))
print(type(dt1),dt1)

# 输出结果
<class 'datetime.datetime'> 2018-01-30 16:54:18.364000

 

4、时间差计算

定义两个日期时间dt1dt2,计算一下差值

import datetime
dt1 = datetime.datetime.fromtimestamp(1517302458)
dt2 = datetime.datetime.now()
td = '相差%d天零%.1f个小时'%((dt2-dt1).days,(dt2-dt1).seconds/60/60)
print('%s\n%s\n%s'%(dt1,dt2,td))

# 输出结果
2018-01-30 16:54:18
2019-05-25 09:31:11.750390
相差479天零16.6个小时

5、时区转换

时区并非东八区的时间,比如2018-12-10T07:46:45.743+0000

from datetime import datetime,timezone,timedelta
dt1 = datetime.utcnow().replace(tzinfo=timezone.utc)
dt2 = dt1.astimezone(timezone(timedelta(hours=8))) # 转换时区到东八区
print('UTC协调世界时 \t%s\nUTC+8北京时间\t%s'%(dt1,dt2))

# 输出结果
UTC协调世界时 	2019-05-25 02:48:54.281741+00:00
UTC+8北京时间	2019-05-25 10:48:54.281741+08:00
 

Python 时间戳的坑

 

在使用 datetimetimestamp() 方法获取时间戳时遇到一点问题

1
2
3
4
5
6
7
#!/usr/bin/env python
# -*- coding:utf-8 -*-


from datetime import datetime
print(datetime.now().timestamp() # ==> 1512393482.510263
print(datetime.utcnow().timestamp()) # ==> 1512364682.510288

理论上两个输出应该都返回当前时间戳,但是 utcnow() 方法的时间戳并不正确,网上查找资料没一个能说明白的,后来查看官方文档发现这么一句话

There is no method to obtain the POSIX timestamp directly from a naive datetime instance representing UTC time. If your application uses this convention and your system timezone is not set to UTC, you can obtain the POSIX timestamp by supplying tzinfo=timezone.utc:

我们不能通过 UTC 得到的 datetime 实例直接获取时间戳,如果系统的时区不是 UTC 则需要 timezone.utc 来帮忙转换。我晕,我们不提供,但是给你指条路。好吧,先试试

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python
# -*- coding:utf-8 -*-


from datetime import datetime
from datetime import timezone

dt = datetime.utcnow()
print(dt.replace(tzinfo=timezone.utc).timestamp()) # ==> 1512454062.906826
print(datetime.now().timestamp()) # ==> 1512454062.906826

 

OK,这次可以了,但是呢,难道每次获取一次时间戳都这样麻烦或者修改系统时区吗?当然不是,我们还可以通过 time 模块来轻松搞定

1
2
3
4
5
6
7
#!/usr/bin/env python
# -*- coding:utf-8 -*-


import time

print(time.time()) # ==> 1512454270.614852

 

时间戳转为地区时间

如果想要将时间戳转为某个地区的时间,比如北京时间,需要引入 pytz 模块,首先下载 pip install pytz

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env python
# -*- coding:utf-8 -*-


import time
from datetime import datetime
import pytz

tz = pytz.timezone('Asia/Shanghai') #东八区
t = datetime.fromtimestamp(int(time.time()),
pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S %Z%z')
print(t) # ==> 2017-12-05 18:39:45 CST+0800

 

讨论

datetime.strptime() 方法支持很多的格式化代码, 比如 %Y 代表4位数年份, %m 代表两位数月份。 还有一点值得注意的是这些格式化占位符也可以反过来使用,将日期输出为指定的格式字符串形式。

比如,假设你的代码中生成了一个 datetime 对象, 你想将它格式化为漂亮易读形式后放在自动生成的信件或者报告的顶部:

>>> z
datetime.datetime(2012, 9, 23, 21, 37, 4, 177393)
>>> nice_z = datetime.strftime(z, '%A %B %d, %Y')
>>> nice_z
'Sunday September 23, 2012'
>>>

还有一点需要注意的是, strptime() 的性能要比你想象中的差很多, 因为它是使用纯Python实现,并且必须处理所有的系统本地设置。 如果你要在代码中需要解析大量的日期并且已经知道了日期字符串的确切格式,可以自己实现一套解析方案来获取更好的性能。 比如,如果你已经知道所以日期格式是 YYYY-MM-DD ,你可以像下面这样实现一个解析函数:

from datetime import datetime
def parse_ymd(s):
    year_s, mon_s, day_s = s.split('-')
    return datetime(int(year_s), int(mon_s), int(day_s))

实际测试中,这个函数比 datetime.strptime() 快7倍多。 如果你要处理大量的涉及到日期的数据的话,那么最好考虑下这个方案!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!