目录
- 一、datetime模块
- 1、date 类
- 2、time 类
- 3、datetime 类
- 4、strftime 方法
- 5、strptime 方法
- 6、replace 方法
- 7、timedelta 类
- 8、tzinfo 和 timezone
- 二、dateutil 模块
- 1、relativedelta 类
- 2、paser 类
- 三、pytz 模块
- 1、查看时区,给时间添加时区属性
- 2、localize和astimezone 给时间增加时区属性和时间的时区转换
一、datetime模块
datetime模块提供用于处理日期和时间的类。支持日期时间数学运算,更着重于有效地解析其属性用于格式化输出和数据操作。
官方文档 datetime模块中常用的和方法有:date、time、datetime、strtime、strftime、strptime、replace
导入模块:
import datetime
1、date 类
datetime模块中的一个类,用于创建一个包含年月日的日期
d = datetime.date(2020, 3, 23) # date的参数必须是int,需要注意的是1月就是1不是01
print(d)
print(d.year) # 获取时间变量的年份,月份:d.month 日期: d.day
print(datetime.date.today()) # 今天的日期
print(d.weekday()) # 返回日期是周几,周一是0
print(d.isoweekday()) # 返回日期是周几,周一是1, isoweekday = weekday()+1
2、time 类
datetime模块中的一个类,用于创建一个包含时分秒的时间(每天24x60x60秒)
d = datetime.time(8, 3, 15, 30) # default: tzinfo=None
print(d)
print(d.hour) # 提取时间的小时数
print(d.minute) # 分
print(d.second) # 秒
print(d.microsecond) # 微秒
print(d.tzinfo) # 时区, 源数据参数 tzinfo=None 时,这里也返回None
3、datetime 类
datatime模块中的datetime类,可以看作是上面date和time的组合。Attributes: year, month, day, hour, minute, second, microsecond(微秒)
d = datetime.datetime(2020, 3, 18, 20, 15, 20, 300)
print(d) # -->2020-03-18 20:15:20.000300
print(d.month) # 获取时间变量的月份
print(d.timestamp()) # 把易读时间转换为时间戳格式,方式一
time = datetime.datetime.timestamp(d) # 把易读时间转换为时间戳格式 方式二
print(time)
time = datetime.datetime.fromtimestamp(time) # 把时间戳转换为易读时间格式
print(time)
print(datetime.date(2020, 4, 10) - datetime.date(2020, 4, 9)) # 时间差
d = datetime.datetime.now(tz=pytz.utc)
print(d)
print(d.date())
print(d.time()) # 17:29:19.824968 提取时间,不包括 tzinfo 属性
print(d.timetz()) # 17:29:19.824968 提取时间,包括 tzinfo 属性
print(d.astimezone()) # 返回带有本地时区的时间 2020-03-28 17:29:19.824968+08:00
print(d.utcoffset()) # 返回时间变量的时区,如果原数据参数的tz=None 那么这里也返回None
print(d.dst()) # 夏令时
print(d.timetuple()) # 返回一个元组格式的时间,可以用[index] 提取对应内容,比如 d.timetuple() -- year 返回值格式:
# time.struct_time(tm_year=2020, tm_mon=3, tm_mday=28, tm_hour=9, tm_min=41, tm_sec=28, tm_wday=5, tm_yday=88,
# tm_isdst=0)
# 其实datetime 就是 date + time,属性也是覆盖date 和 time
# 需要注意的时,date 没有 tzinfo属性,而time和datetime都有
4、strftime 方法
datatime 类中的一个方法,用于把时间格式化,返回一个字符串
d = datetime.datetime.now() # 当前的电脑时间
print(d.strftime('%Y-%m-%d %H:%M:%S')) # 返回2020-03-28 10:20:20
print(d.strftime('%y-%m-%d %H:%M:%S')) # 返回20-03-28 10:20:20 注意年的大写Y和小写y的区别
print(d.strftime('%D %H:%M:%S')) # 返回03/28/20 10:21:57 注意D的用法
print(d.strftime('%b-%d-%y %H:%M:%S')) # Mar-28-20 10:20:20
print(d.strftime('%B-%d-%y %H:%M:%S')) # March-28-20 10:23:39 注意B和b的区别,分别是月份的全拼和简写
5、strptime 方法
datatime 类中的一个类方法,用于把字符串格式的时间转换为datetime.datetime格式,
需要注意的是date类 和 time类都没有这个方法
d = datetime.datetime.now()
print(datetime.datetime.strptime('March-28-20 10:23:39', '%B-%d-%y %H:%M:%S'))
print(datetime.datetime.strptime('2020-03-28', '%Y-%m-%d')) # 2020-03-28 00:00:00 如果只有日期,自动填充时间0
print(datetime.datetime.strptime('10:34:22', '%H:%M:%S')) # 1900-01-01 10:34:22 如果只有时间,那么年份将是 1900-01-01
# 返回数据类型 <class 'datetime.datetime'>
print(type(datetime.datetime.strptime('2020-03-24 10:27:29', '%Y-%m-%d %H:%M:%S')))
6、replace 方法
返回一个带相同属性的datetime,除了指定关键字参数的新值之外,还可以指定tzinfo新值
d = datetime.datetime.now() # --> 2020-03-28 11:00:41.296596
print(d.replace(year=2022, day=23)) # --> 2022-03-23 11:00:41.296596
# replace 的全部参数:
# replace(year=self.year, month=self.month, day=self.day, hour=self.hour, minute=self.minute, second=self.second, microsecond=self.microsecond, tzinfo=self.tzinfo)
# 其中tzinfo是修改时区
print(d.replace(tzinfo=pytz.timezone('Asia/Shanghai'))) # 把原时间的时区替换为参数的时区
单纯看上面的用法貌似基本用不到,一般我们不会去强行改变一个时间的某个值。有一种情况就是如果我们要获取这个月的最后一天是几号,有的月份是30天有的有31日,二月还是28/29天,你当然可以使用字典,但是太死板,使用replace就非常方便,下面自定义函数,可以获取月份的最后一天:
def last_day_month(date_time: datetime.datetime):
"""
返回月份的最后一天
:return:
"""
next_month = date_time.replace(day=28) + datetime.timedelta(days=4) # 把天数替换为28日,因为月份中最少的天数就是28了,+4天肯定到下一个月了
delta = datetime.timedelta(days=next_month.day) # next_month.day 下个月的天数,
date = (next_month - delta).replace(hour=23, minute=59, second=59, microsecond=0)
return date
7、timedelta 类
datetime模块中的一个类,表示两个日期或时间的差
class datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)
所有参数都是可选的,默认为0。参数可以是整数或浮点数,也可以是正数或负数。
d = datetime.date(2020, 3, 23)
later = datetime.timedelta(days=9) # 创建一个时间间隔(9天)
print(later)
t = d + later
print(t) # 返回结果:2020-04-01; 源数据是3月23日,加9天,超过了31天了,程序会自动计入4月份,时分秒同理
print(later.total_seconds()) # 把时间间隔转换为秒数
通过参数可以注意到,timedelta 只能在日及以下级别偏移,如果要偏移一个月或一年的?那就要用到 dateutil 模块的 relativedelta(下面会介绍)。
8、tzinfo 和 timezone
tzinfo 也是datetime下的类,但是这个类不会用来实例化,只是捕获关于特定时区的信息,一般在datetime和time传参时使用。上面已经多次用到,这里不再举例。
timezone 是 tzinfo 的子类,它的每个实例都表示一个由UTC的固定偏移量定义的时区
二、dateutil 模块
官方文档 dateutil 是不同于datetime模块的一个第三方时间处理模块,其实常用的时间处理模块还是datetime,但是datetime有些不足的地方,比如 timedelta 偏移月份和年不方便,再比如把一个 ‘20200325082532’ 这样的字符串之间转换为时间类型或易读的字符串格式。那么这里就介绍这两个功能的补充:
导入模块:
from dateutil.relativedelta import *
from dateutil.parser import parse
1、relativedelta 类
从导入的方式可以推测,这是在 dateutil 模块中 relativedelta子模块中的一个类
类的定义:
relativedelta(self, dt1=None, dt2=None,
years=0, months=0, days=0, leapdays=0, weeks=0,
hours=0, minutes=0, seconds=0, microseconds=0,
year=None, month=None, day=None, weekday=None,
yearday=None, nlyearday=None,
hour=None, minute=None, second=None, microsecond=None)
所有参数都有默认值,参数很多,通过观察可以发现大部分参数可以分为两类,比如year/years,month/months…等,其实这里是datetime类中replace和timedelta的结合体
year,month,…参数就是把变量的时间替换为关键字参数的新值,而years,months,…参数其实就是timedelta的功能,即时间间隔,可以为负数,但是不能为小数,这是与timedelta的区别,从参数就可以看到很明显,增加了years,months的偏移,弥补了 timedelta 短板。例如:
d = datetime.datetime(2020, 3, 31, 8, 3, 15, 30)
print(d)
later = relativedelta(months=2) # 返回relativedelta(months=+2),两个月的间隔,会按月天数自动计入
print(d+later) # --> 2020-05-31 08:03:15.000030
later = relativedelta(month=2) # 注意 months 和 month的区别,month是把月份改成2月,months是两个月间隔,累加2个月。返回日期2月份没有31日,会自动转换到2月的最后一天
print(d + later) # --> 2020-02-29 08:03:15.000030
relativedelta 除了补充timedelta的月和年偏移意外,还有一些很方便的扩展功能:
dt1和dt2,直接看案例:
c = relativedelta(dt1=d, dt2=datetime.date(2001, 1, 1)) # dt1-dt2 两个日期之间差,返回一个relativedelta类的元祖
print(c) # 返回 relativedelta(years=+19, months=+2, days=+30, hours=+8, minutes=+3, seconds=+15, microseconds=+30)
print(c.years) # relativedelta 使用参数dt1和dt2返回的结果,只能使用类似属性的方式获取
参数 weekday=None,其实也非常方便:
print(datetime.date.today()+relativedelta(weekday=FR)) # 获取下一个周五的日期,也可用datetime,获取下一个周五的相同时间
print(datetime.date.today()+relativedelta(day=31, weekday=FR(-1))) # 获取这个月最后一个周五,MO, TU, WE, TH, FR, SA, SU
print(datetime.date.today() + relativedelta(day=1, weekday=FR)) # 获取这个月第一个周五
print(datetime.date.today() + relativedelta(weekday=WE(+1))) # 从今天开始算的下一个周三
print(datetime.date.today() + relativedelta(days=+5, weekday=WE(+1))) # 从5天后开始算的下一个周三
print(datetime.date.today() + relativedelta(months=+1, day=1, weekday=FR)) # 下个月的第一个周五
参数yearday=None, nlyearday=None,个人感觉就有些鸡肋了
print(datetime.datetime.now() + relativedelta(yearday=260)) # 260天后的日期,但是不能大于366天,而且最终结果不能跨年,如果跨年返回的结果就是今年最后一天的日期,不能跨年在作用上就有些受限了,敝人经历中很少用到,到时 weekday 比较常用,比如在期货交易中计算交割日
print(datetime.date(2000, 1, 1) + relativedelta(yearday=260))
print(datetime.date(2000, 1, 1) + relativedelta(nlyearday=260)) # nlyearday 主要区别与 yearday 是否忽略闰年
2、paser 类
是 dateutil 模块中子模块,这个模块提供了一个通用的日期/时间字符串解析器,它能够解析大多数已知的格式来表示日期和/或时间。据官方文档介绍,即使有一些时间日期是模糊的,这个模块也可以处理。其实主要用的是模块中的 parse 函数,函数的定义:
parse(timestr, parserinfo=None, **kwargs):
解析非标准格式字符串时间方法:
d = '20200325082532'
print(parse(d)) # 返回 2020-03-25 08:25:32 <class 'datetime.datetime'>
print(parse(d).strftime('%Y-%m-%d %H:%M:%S')) # 返回 2020-03-25 08:25:32 <class 'str'>
至于他的模糊处理还是比较麻烦的,其实也比较少用,这里列举一个官方的简单例子
m = parse("Today is January 1, 2047 at 8:21:00AM", fuzzy_with_tokens=True)
print(m) # --> 返回一个元祖(datetime.datetime(2047, 1, 1, 8, 21), ('Today is ', ' ', ' ', 'at '))
print(m[0]) # 元祖的第一个值是处理后的时间,第二个值是一些干扰字符
三、pytz 模块
官方文档 官方文档介绍简述:pytz模块可以实现精确的跨平台时区计算,并且解决了夏令时结束时的模糊时间问题。
1、查看时区,给时间添加时区属性
print(pytz.common_timezones_set) # 返回结果-->LazySet({'Asia/Muscat', 'America/Tortola', 'Antarctica/Troll', 'Europe/Monaco', ...})
for n in pytz.common_timezones_set: # 查看pytz中常见哪些时区,中国只有上海
print(n)
for n in pytz.all_timezones: # 查看全部时区,返回值是列表格式的可迭代对象:<class 'pytz.lazy.LazyList.__new__.<locals>.LazyList'>
print(n)
for n in pytz.all_timezones_set: # 查看全部时区 与 pytz.all_timezones 结果相同,只是返回值是一个集合格式的可迭代对象 <class 'pytz.lazy.LazySet.__new__.<locals>.LazySet'>
print(n)
print(pytz.country_names['CN']) # 查看国家的全称
print(pytz.country_timezones['CN']) # 查看对应国家的时区代表城市
tz = pytz.timezone('America/New_York') # 纽约时区
print(datetime.datetime.now(tz)) # 对应时区的当前时间
print(datetime.datetime(2020, 3, 30, 16, 20, tzinfo=tz)) # 这里需要注意的是,now(tz=pytz.timezone)是直接获得了对应时区的当前时间,但是datetime(int,int,...,tzinfo=pytz.timezone)并不是把时间转换的对应时区,而是给前面的时间增加了时区属性,时间数值并没有改变,所以不能用这个方式进行时区换算。对于没有夏令时转换的时区这样创建跨时区时间是没有问题的。如果涉及跨时区和夏令时的转换,可以使用下面的localize和astimezone
2、localize和astimezone 给时间增加时区属性和时间的时区转换
localize 是pytz模块下UTC类内的一个方法。定义:localize(dt, is_dst=False);
但是astimezone并不是pytz模块下的类或方法,而是datetime模块下的一个方法,之所以放到这里介绍,主要是因为这个方法下的唯一参数就是时区,需要用到pytz模块的属性,定义:astimezone(self, tz=None):
eastern = pytz.timezone('US/Eastern') #
print(eastern.zone)
amsterdam = pytz.timezone('Europe/Amsterdam') # 欧洲--阿姆斯特丹
print(amsterdam)
fmt = '%Y-%m-%d %H:%M:%S %Z%z'
# localize给一个没有设置时区的时间设置时区,另外可以增加是否夏令时参数,但是这里并不如直接使用后面的astimezone更加方便。这里注意的是,要增加时区的变量时间必须是之前没有timezone属性,否则会报错!
loc_dt = eastern.localize(datetime.datetime(2020, 3, 28, 1, 0, 0), is_dst=True)
print(loc_dt)
print(loc_dt.strftime(fmt))
# astimezone 把变量时间转换为指定时区的时间,前面变量时间不管有是否有timezone属性,都会按标准转换为参数的时区时间
ams_dt = loc_dt.astimezone(amsterdam) # 把已经设置timezone属性的loc_dt转换为amsterdam时区时间
print(ams_dt.strftime(fmt))
ams_dt = datetime.datetime.now().astimezone(amsterdam) # 把本地化的当前时间转换为指定时区的时间,这里的效果其实与datetime.datetime.now(tz=amsterdam)相同
print(ams_dt)
感叹:整理这篇博文用了将近一天时间,但是感觉这并不浪费,可能年龄大了脑子不好用了,很多东西记不牢,用的时候一时想不起来,与其网上搜索不如整理一下记在自己博客里面。
补充:
1、获取几天前、几个月前和几年前的日期和时间
2、获取当前或指定时间季度初和季度末的时间
# 获取1天前的当下时间
date_r = datetime.now() - timedelta(days=1)
print(date_r)
# 获取1天前开始时间(一天前的0点0分0秒)
today = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
date_ra = today - timedelta(days=1)
print(date_ra)
# 获取几个月几年前的日期时间
def get_date_month(now, mon=0):
"""
:param now: 当前时间或指定时间
:param mon: 获取当前时间X月之前的时间
:return: YYYY-MM
"""
# 当前时间X个月前
last_m = (int(now.year) * 12 + int(now.month) - mon) % 12
last_y = int((int(now.year) * 12 + int(now.month) - mon) / 12)
if last_m == 0:
last_m = 12
last_y -= 1
last_m = str(last_m).zfill(2)
last_d = str(now.day).zfill(2)
last_h = str(now.hour).zfill(2)
last_M = str(now.minute).zfill(2)
last_s = str(now.second).zfill(2)
last_time = f'{last_y}-{last_m}-{last_d} {last_h}:{last_M}:{last_s}'
last_time = datetime.strptime(last_time, '%Y-%m-%d %H:%M:%S')
# print(last_time)
return last_time
# 例如:
# 获取一个月前的当前时间
get_date_month(datetime.now(), 1)
# 获取一年前的当前时间
get_date_month(datetime.now(), 1 * 12)
# 获取一个月前数据月初时间
month = datetime.now().replace(day=1, hour=0, minute=0, second=0, microsecond=0) # 当月开始的时间
get_date_month(month, 1)
# 获取一年前年初时间
year = datetime.now().replace(month=1, day=1, hour=0, minute=0,
second=0, microsecond=0) # 当前年份
get_date_month(year, 1*12)
# 获取当前季度初和季度末的时间
import calendar
def get_season_start_and_end(now):
"""
获取当前季度初和季度末的时间
:param now: 当前时间或指定时间
:return:
"""
season = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
month = now.month
season_min = season_max = month
for value in season:
if month in value:
# 季度初时间
season_min = now.replace(month=value[0],
day=1, hour=0, minute=0, second=0, microsecond=0)
# 季度末时间
# 1、获取季度末月份的最后一天日期,calendar 返回元组 (周几,月底日期)
end = calendar.monthrange(now.year, value[2])[1]
season_max = now.replace(month=value[2],
day=end, hour=23, minute=59, second=59, microsecond=0)
return season_min, season_max
# 获取一年四个季度中某个季度开始和结束的时间
def get_four_season_start_and_end(season_index: int):
"""
获取四个季度初和季度末的时间
:param now: 当前时间或指定时间
:return:
"""
if season_index not in [1, 2, 3, 4]: # 如果输入的数据不是1-4默认显示第一季度
season_index = 1
season_index -= 1
season = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
month = season[season_index]
now = datetime.datetime.now()
# 季度初时间
season_min = now.replace(month=month[0],
day=1, hour=0, minute=0, second=0, microsecond=0)
# 季度末时间
# 1、获取季度末月份的最后一天日期,calendar 返回元组 (周几,月底日期)
end = calendar.monthrange(now.year, month[2])[1]
season_max = now.replace(month=month[2],
day=end, hour=23, minute=59, second=59, microsecond=0)
return season_min, season_max
# 获取指定季度或者指定时间所在季度初和季度末的时间
def get_season_start_and_end(season_index=0, time=None):
"""
获取四个季度初和季度末的时间
:param season_index: 当前第几季度
:param time: 查询某个时间(datetime),通过时间自动获取是第几季度。填写time后season_index失效
:return:
"""
if season_index not in [1, 2, 3, 4]: # 如果输入的数据不是1-4默认显示第一季度
season_index = 1
season_index -= 1
season = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
if time:
# print(time.month, '------', type(time.month))
for index, month in enumerate(season):
if time.month in month:
season_index = index
# print(season_index, '=============')
month = season[season_index]
now = datetime.datetime.now()
# 季度初时间
season_min = now.replace(month=month[0],
day=1, hour=0, minute=0, second=0, microsecond=0)
# 季度末时间
# 1、获取季度末月份的最后一天日期,calendar 返回元组 (周几,月底日期)
end = calendar.monthrange(now.year, month[2])[1]
season_max = now.replace(month=month[2],
day=end, hour=23, minute=59, second=59, microsecond=0)
return season_min, season_max
# 获取几周前周开始和结束时间
def last_first_date_and_last_date(ween_n):
"""
获取前n周开始时间和结束时间,参数n:代表前ween_n周
"""
now = datetime.datetime.now()
# 上周第一天和最后一天
before_week_start = now - datetime.timedelta(days=now.weekday() + 7 * ween_n,
hours=now.hour,
minutes=now.minute,
seconds=now.second,
microseconds=now.microsecond)
# last_week_end = now - timedelta(days=now.weekday() + 1)
before_week_end = before_week_start + datetime.timedelta(days=6,
hours=23,
minutes=59,
seconds=59)
return before_week_start, before_week_end