在python编程中我们常常需要处理时间和日期信息,例如需要获取当前时间、生成特定字符串格式的时间信息等等。python为我们提供了一个现成的标准库——datetime,内置了许多有用的类和函数,现整理如下。

1 datetime标准库

datetime库中有一个同名的类——datetime类,采用该类可以做很多工作。

  • timestamp时间戳。首先我们要了解日期和时间在计算机中是如何表示的。我们看到的日期都是像xxxx年xx月xx日的形式,但在计算机中并不是以这种字符串的形式来存储时间的。而是以一种非常简单粗暴的方式来存储——浮点数。这也是所谓的时间戳,我们将1970年1月1日 00:00:00 UTC+00:00时区的时刻的时间戳记为0,在此之前的为负数;在此之后的为正数。其整数部分表示秒(Java的整数部分表示毫秒,原理一样)。用这种方式存储的时间简单高效没有二义性,全世界都适用。
from datetime import datetime
	d = datetime.now()      # 当前时间(东八区)
	t = d.timestamp()       # 时间戳
	print(d, t)
	# 将时间戳转换为当前时间和当前utc时间
	print(datetime.fromtimestamp(t), datetime.utcfromtimestamp(t))		

	2021-02-05 10:52:06.093800 1612493526.0938
	2021-02-05 10:52:06.093800 2021-02-05 02:52:06.093800
  • 获取标准日期和时间。这里包含获取当前的时间和获取指定的时间。获取指定时间的方法就是向datetime类传入对应参数,包括年月日时分秒毫秒时区等,其中年月日是必须的,其他可选,参考源码datetime如下。
"""datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])

    The year, month and day arguments are required. tzinfo may be None, or an
    instance of a tzinfo subclass. The remaining arguments may be ints.
    """

    def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
                microsecond=0, tzinfo=None, *, fold=0):
# 获取当前时间
	from datetime import datetime
	d = datetime.now()
	print(d)
	
	2021-02-05 10:53:08.753610
# 获取指定时间
	from datetime import datetime
	d = datetime(2019, 12, 18, 18, 20)
	print(d)
	
	2019-12-18 18:20:00
  • 日期/时间转换。这里的转换形式非常多,包括时间戳(timestamp)与标准时间(datetime)之间的转换、datetime与字符串之间的转换、timestamp与字符串之间的转换等等。但我认为这里只需要抓住一个准则就可以应对多种情形——所有的转换都以标准时间(datetime)为中心展开。例如timestamp转为字符串,那么就先将timestamp转为datetime,再将datetime转为字符串。
# 这里需要掌握四个函数即可
	d.timestamp()					# datetime->timestamp
	datetime.fromtimestamp(t)		# timestamp->datetime
	datetime.strptime(s, f)			# string->datetime
	d.strftime(f)					# datetime->string
  • 上面介绍了timestamp和datetime的转换,这里只介绍字符串和datetime之间的转换实例。
# 字符串转datetime
	from datetime import datetime
	time_str = '2019-12-18 18:20:10'		# 指定需要转换的字符串
	str_format = '%Y-%m-%d %H:%M:%S'		# 指定转换格式
	d = datetime.strptime(time_str, str_format)
	print(d)
	
	2019-12-18 18:20:10
# datetime转字符串
	from datetime import datetime
	d = datetime(2019, 12, 18, 18, 20, 10)		# datetime对象
	str_format = '%Y year %m month %d day %H hour %M min %S sec'
	time_str = d.strftime(str_format)
	print(time_str)

	2019 year 12 month 18 day 18 hour 20 min 10 sec
  • 有一些常用的时间Format的记号,这里整理如下:

%y 两位数的年份表示(00-99)
%Y 四位数的年份表示(000-9999)
%m 月份(01-12)
%d 月内中的一天(0-31)
%H 24小时制小时数(0-23)
%I 12小时制小时数(01-12)
%M 分钟数(00=59)
%S 秒(00-59)
%a 本地简化星期名称
%A 本地完整星期名称
%b 本地简化的月份名称
%B 本地完整的月份名称
%c 本地相应的日期表示和时间表示
%j 年内的一天(001-366)
%p 本地A.M.或P.M.的等价符
%U 一年中的星期数(00-53)星期天为星期的开始
%w 星期(0-6),星期天为星期的开始
%W 一年中的星期数(00-53)星期一为星期的开始
%x 本地相应的日期表示
%X 本地相应的时间表示
%Z 当前时区的名称
%% %号本身

  • datetime时间推移。有时候我们想要获取当前时间之前2小时的时间,此时应该如何做呢?有两种方式,1)是获取当前时间的timestamp,然后通过对timestamp做加减运算,得到想要时间的时间戳,再将其转换为标准时间;2)是datetime模块中有一个timedelta类,可以直接对datetime对象做加减运算。
# 第一种方式
	from datetime import datetime
	d = datetime(2021, 1, 1)
	t = d.timestamp()
	t += 60 * 60 * 12       # 12小时
	d1 = datetime.fromtimestamp(t)
	print(d1)

	2021-01-01 12:00:00
from datetime import datetime, timedelta
	d = datetime(2021, 1, 1)
	d += timedelta(hours=12)        # 12小时
	print(d)

	2021-01-01 12:00:00
  • 时区问题。从上面datetime源码可以看到,其中有一个tzinfo的选项默认为None,其用来表示时区。可以通过以下方式强制设置某个datetime的时区。
from datetime import datetime, timedelta, timezone
	tz_utc_8 = timezone(timedelta(hours=8)) # 创建时区UTC+8:00
	now = datetime.now()
	dt = now.replace(tzinfo=tz_utc_8) # 强制设置为UTC+8:00

2 小试牛刀

例1:编写一个函数能够将输入的一个MM/DD/YYYY格式的字符串日期转换为YYYYDDMM。
format_date(“11/12/2019”) ➞ “20191211”
format_date(“12/31/2019”) ➞ “20193112”
format_date(“01/15/2019”) ➞ “20191501”

# 用datetime库实现
from datetime import datetime
def format_date(date):
    d = datetime.strptime(date, '%m/%d/%Y')
    return d.strftime('%Y%d%m')
# 当然有更简单的方式
def format_date(date):
	m, d, y = date.split('/')
	return ''.join((y, d, m))

例2:假设你获取了用户输入的日期和时间如2015-1-21 9:01:30,以及一个时区信息如UTC+5:00,均是str,请编写一个函数将其转换为timestamp。

import re
from datetime import datetime, timezone, timedelta

def to_timestamp(dt_str, tz_str):
    dt = datetime.strptime(dt_str, '%Y-%m-%d %H:%M:%S')
    tz_r = re.match(r'^UTC([+|-]\d{1,2}):00$', tz_str)  # UTC中获取时区信息
    # 利用tzinfo属性将datetime强制设置成指定时区
    dt = dt.replace(tzinfo=timezone(timedelta(hours=int(tz_r.group(1)))))
    return dt.timestamp()

# 测试:
t1 = to_timestamp('2015-6-1 08:10:30', 'UTC+7:00')
assert t1 == 1433121030.0, t1

t2 = to_timestamp('2015-5-31 16:10:30', 'UTC-09:00')
assert t2 == 1433121030.0, t2

print('ok')