【Python练习cookbook】时间、日期操作

本文详细介绍了Python中处理时间的三大模块:time、calendar和datetime。涵盖了时间戳转换、日期时间对象创建、时间间隔计算及格式化输出等内容,展示了如何利用Python进行高效的时间日期处理。
部署运行你感兴趣的模型镜像

时间相关三模块:

timecalendar 、datetime

1. time 模块

官方:time --- 时间的访问和转换 — Python 3.9.7 文档

尽管此模块始终可用,但并非所有平台上都提供所有功能。 此模块中定义的大多数函数是调用了所在平台 C 语言库的同名函数。 因为这些函数的语义因平台而异,所以使用时最好查阅平台相关文档

  • epoch 是时间开始的点,并且取决于平台。对于Unix, epoch 是1970年1月1日00:00:00(UTC)。要找出给定平台上的 epoch ,请查看 time.gmtime(0) 。

  • 术语 Unix 纪元秒数 是指自国际标准时间 1970 年 1 月 1 日零时以来经过的总秒数,通常不包括 闰秒。 在所有符合 POSIX 标准的平台上,闰秒都会从总秒数中被扣除。

  • 此模块中的功能可能无法处理纪元之前或将来的远期日期和时间。未来的截止点由C库决定;对于32位系统,它通常在2038年

time.time() → float

返回以浮点数表示的从 epoch 开始的秒数的时间值。 epoch 的具体日期和 leap seconds 的处理取决于平台。 在 Windows 和大多数 Unix 系统中, epoch 是 1970 年 1 月 1 日 00:00:00 (UTC),并且闰秒将不计入从 epoch 开始的秒数。 这通常被称为 Unix 时间。 要了解给定平台上 epoch 的具体定义,请查看 gmtime(0)

返回的数字 time() 可以通过将其传递给 gmtime() 函数或转换为UTC中更常见的时间格式(即年、月、日、小时等)或通过将它传递给 localtime() 函数获得本地时间。在这两种情况下都返回一个 struct_time 对象,日历日期组件可以从中作为属性访问。

time.gmtime([secs])

将以自 epoch 开始的秒数表示的时间转换为 UTC 的 struct_time ,其中 dst 标志始终为零。 如果未提供 secs 或为 None ,则使用 time() 所返回的当前时间。 一秒以内的小数将被忽略。 有关 struct_time 对象的说明请参见上文。 有关此函数的逆操作请参阅 calendar.timegm()

time.localtime([secs])

与 gmtime() 相似但转换为当地时间。如果未提供 secs 或为 None ,则使用由 time() 返回的当前时间。当 DST 适用于给定时间时,dst标志设置为 1 。

time.mktime(t)

这是 localtime() 的反函数。它的参数是 struct_time 或者完整的 9 元组(因为需要 dst 标志;如果它是未知的则使用 -1 作为dst标志),它表示 local 的时间,而不是 UTC 。它返回一个浮点数,以便与 time() 兼容。如果输入值不能表示为有效时间,则 OverflowError 或 ValueError 将被引发(这取决于Python或底层C库是否捕获到无效值)。它可以生成时间的最早日期取决于平台。

2.datetime模块

官方:datetime --- 基本日期和时间类型 — Python 3.9.7 文档

2.1 timedelta 类对象

官方:datetime --- 基本日期和时间类型 — Python 3.9.7 文档

class datetime.timedelta(days=0seconds=0microseconds=0milliseconds=0minutes=0hours=0weeks=0)

所有参数都是可选的并且默认为 0。 这些参数可以是整数或者浮点数,也可以是正数或者负数。

只有 daysseconds 和 microseconds 会存储在内部。 参数单位的换算规则如下:

  • 1毫秒会转换成1000微秒。

  • 1分钟会转换成60秒。

  • 1小时会转换成3600秒。

  • 1星期会转换成7天。

并且 days, seconds, microseconds 会经标准化处理以保证表达方式的唯一性,即:

  • 0 <= microseconds < 1000000

  • 0 <= seconds < 3600*24 (一天的秒数)

  • -999999999 <= days <= 999999999

>>> from datetime import timedelta
>>> delta = timedelta(
...     days=50,
...     seconds=27,
...     microseconds=10,
...     milliseconds=29000,
...     minutes=5,
...     hours=8,
...     weeks=2
... )
>>> # Only days, seconds, and microseconds remain
>>> delta
datetime.timedelta(days=64, seconds=29156, microseconds=10)


>>> a = timedelta(days=2, hours=6)
>>> b = timedelta(hours=4.5)
>>> c = a + b
>>> c.days
2
>>> c.seconds
37800
>>> c.seconds / 3600
10.5
>>> c.total_seconds() / 3600
58.5

2.2 datetime 对象

官方:datetime --- 基本日期和时间类型 — Python 3.9.7 文档

datetime 对象是包含来自 datetime.date 对象和 datetime.time 对象的所有信息的单一对象。

与 date 对象一样,datetime 假定当前的格列高利历向前后两个方向无限延伸;与 time 对象一样,datetime 假定每一天恰好有 3600*24 秒。

构造器 :

class datetime.datetime(yearmonthdayhour=0minute=0second=0microsecond=0tzinfo=None*fold=0)

yearmonth 和 day 参数是必须的。 tzinfo 可以是 None 或者是一个 tzinfo 子类的实例。 其余的参数必须是在下面范围内的整数:

  • MINYEAR <= year <= MAXYEAR,

  • 1 <= month <= 12,

  • 1 <= day <= 指定年月的天数,

  • 0 <= hour < 24,

  • 0 <= minute < 60,

  • 0 <= second < 60,

  • 0 <= microsecond < 1000000,

  • fold in [0, 1]

time 对象

一个 time 对象代表某日的(本地)时间,它独立于任何特定日期,并可通过 tzinfo 对象来调整。

class datetime.time(hour=0minute=0second=0microsecond=0tzinfo=None*fold=0)

所有参数都是可选的。 tzinfo 可以是 None,或者是一个 tzinfo 子类的实例。 其余的参数必须是在下面范围内的整数:

  • 0 <= hour < 24,

  • 0 <= minute < 60,

  • 0 <= second < 60,

  • 0 <= microsecond < 1000000,

  • fold in [0, 1].

>>> from datetime import datetime
>>> a = datetime(2012, 9, 23)
>>> print(a + timedelta(days=10))
2012-10-03 00:00:00
>>>
>>> b = datetime(2012, 12, 21)
>>> d = b - a
>>> d.days
89
>>> now = datetime.today()
>>> print(now)
2012-12-21 14:54:43.094063
>>> print(now + timedelta(minutes=10))
2012-12-21 15:04:43.094063
#支持date类的运算
>>> a = datetime(2012, 3, 1)
>>> b = datetime(2012, 2, 28)
>>> a - b
datetime.timedelta(2)
>>> (a - b).days
2
>>> c = datetime(2013, 3, 1)
>>> d = datetime(2013, 2, 28)
>>> (c - d).days

 2.3 第三方库 relativedelta 能提供timedelta类似的能力,并且有对month的支持:

>>> a = datetime(2012, 9, 23)
>>> a + timedelta(months=1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'months' is an invalid keyword argument for this function
>>>
>>> from dateutil.relativedelta import relativedelta
>>> a + relativedelta(months=+1)
datetime.datetime(2012, 10, 23, 0, 0)
>>> a + relativedelta(months=+4)
datetime.datetime(2013, 1, 23, 0, 0)
>>>
>>> # Time between two dates
>>> b = datetime(2012, 12, 21)
>>> d = b - a
>>> d
datetime.timedelta(89)
>>> d = relativedelta(b, a)
>>> d
relativedelta(months=+2, days=+28)
>>> d.months
2
>>> d.days
28
>>>

 应用1:找到上一个星期五:

from datetime import datetime, timedelta
weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday',
'Friday', 'Saturday', 'Sunday']
def get_previous_byday(dayname, start_date=None):
if start_date is None:
start_date = datetime.today()
day_num = start_date.weekday()
day_num_target = weekdays.index(dayname)
days_ago = (7 + day_num - day_num_target) % 7
if days_ago == 0:
days_ago = 7
target_date = start_date

>>> datetime.today() # For reference
datetime.datetime(2012, 8, 28, 22, 4, 30, 263076)
>>> get_previous_byday('Monday')
datetime.datetime(2012, 8, 27, 22, 3, 57, 29045)
>>> get_previous_byday('Tuesday') # Previous week, not today
datetime.datetime(2012, 8, 21, 22, 4, 12, 629771)

#三方库
>>> from datetime import datetime
>>> from dateutil.relativedelta import relativedelta
>>> from dateutil.rrule import *
>>> d = datetime.now()
>>> print(d)
2012-12-23 16:31:52.718111
>>> # Next Friday
>>> print(d + relativedelta(weekday=FR))
2012-12-28 16:31:52.718111
>>>
>>> # Last Friday
>>> print(d + relativedelta(weekday=FR(-1)))
2012-12-21 16:31:52.718111

应用2:遍历某一个月、遍历某时间范围

from datetime import datetime, date, timedelta
import calendar
def get_month_range(start_date=None):
    if start_date is None
        start_date = date.today().replace(day=1)
        _, days_in_month = calendar.monthrange(start_date.year, start_date.month)
        end_date = start_date + timedelta(days=days_in_month)
    return (start_date, end_date)

>>> a_day = timedelta(days=1)
>>> first_day, last_day = get_month_range()
>>> while first_day < last_day:
... print(first_day)
... first_day += a_day
...
2012-08-01
2012-08-02
2012-08-03
2012-08-04
2012-08-05
...

#某范围step递增
def date_range(start, stop, step):
    while start < stop:
        yield start
        start += step

>>> for d in date_range(datetime(2012, 9, 1), datetime(2012,10,1),
timedelta(hours=6)):
... print(d)
...
2012-09-01 00:00:00
2012-09-01 06:00:00
2012-09-01 12:00:00
2012-09-01 18:00:00
2012-09-02 00:00:00

classmethod datetime.strptime(date_stringformat)

返回一个对应于 date_string,根据 format 进行解析得到的 datetime 对象。

这相当于:

datetime(*(time.strptime(date_string, format)[0:6]))

如果 date_string 和 format 无法被 time.strptime() 解析或它返回一个不是时间元组的值,则将引发 ValueError。 要获取格式化指令的完整列表,请参阅 strftime() 和 strptime() 的行为

#解析
>>> from datetime import datetime
>>> text = '2012-09-20'
>>> y = datetime.strptime(text, '%Y-%m-%d')
>>> z = datetime.now()
>>> diff = z - y
>>> diff
datetime.timedelta(3, 77824, 177393)
#反解析
>>> 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的解析因为要遍历多种平台尝试,所以非常耗时,若已知确切格式,不如自己解析,如下代码要快7倍

#解析“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))

引用:

Python标准库笔记(3) — datetime模块

目录

正文

datetime模块提供了简单和复杂的方式用于操纵日期和时间的类。虽然支持日期和时间运算,但实现的重点是为了输出格式化和操作高效地提取属性。

回到顶部

1. 模块内容

内容描述
常量
datetime.MINYEARdate和datetime对象允许的最小年份
datetime.MAXYEARdate和datetime对象允许的最大年份
datetime.date日期对象,属性(year, month, day)
datetime.time时间对象,属性(hour, minute, second, microsecond, tzinfo)
datetime.datetime日期时间对象,属性(date和time属性组合)
datetime.timedeltaDifference between two datetime values(原文)
datetime.tzinfo时区信息对象的抽象基类, datetime和time类使用它定制化时间调节

回到顶部

2. datetime.date类

  date对象表示理想化日历中的日期(年、月和日), 公历1年1月1日被称为第一天,依次往后推。

  • 类方法
from datetime import date

print 'today():', date.today()  # 返回当前日期对象

print 'fromtimestamp(1491448600):', date.fromtimestamp(1491448600)  # 返回时间戳的日期对象

print 'date.fromordinal(1):', date.fromordinal(1)  # 返回对应公历序数的日期对象

# 输出
today():2017-04-06
fromtimestamp(1491448600):2017-04-06
date.fromordinal(1): 0001-01-01
  • 对象方法和属性
from datetime import date

d = date(2017, 04, 06)

print 'd.year:', d.year    # 返回date对象的年份

print 'd.month:', d.month  # 返回date对象的月份

print 'd.day:', d.day     # 返回date对象的日

print 'd.timetuple():', d.timetuple()  # 返回date对象的struct_time结构

print 'd.toordinal():', d.toordinal()  # 返回公历日期的序数

print 'd.weekday():', d.weekday()      # 返回一星期中的第几天,星期一是0

print 'd.isoweekday():', d.isoweekday()  # 返回一星期中的第几天, 星期一1

print 'd.isocalendar():', d.isocalendar()  # 返回一个元组(年份, 这一年的第几周, 周几)

print 'd.isoformat():', d.isoformat()  # 以ISO 8601格式‘YYYY-MM-DD’返回date的字符串形式

print 'd.ctime():', d.ctime()  # 返回一个表示日期的字符串

print 'd.strftime("%Y-%m-%d"):', d.strftime("%Y-%m-%d")  # 返回指定格式的日期字符串

print 'd.replace(year=2012, month=12) :', d.replace(year=2012, month=12)  # 替换



# 输出

d.year: 2017
d.month: 4
d.day: 6
d.timetuple(): time.struct_time(tm_year=2017, tm_mon=4, tm_mday=6, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=96, tm_isdst=-1)
d.toordinal(): 736425
d.weekday(): 3
d.isoweekday(): 4
d.isocalendar(): (2017, 14, 4)
d.isoformat(): 2017-04-06
d.ctime(): Thu Apr  6 00:00:00 2017
d.strftime("%Y-%m-%d"): 2017-04-06
d.replace(year=2012, month=12) : 2012-12-06

回到顶部

3. datetime.time类

  表示一个(当地)时间对象,与任何特定的日期无关,并且可以通过tzinfo(时区)对象进行调整。

from datetime import time

t = time(12, 10, 30, 50)

print 't.hour:', t.hour      # time对象小时数

print 't.minute:', t.minute  # time对象分钟数

print 't.second:', t.second  # time对象秒数

print 't.microsecond:', t.microsecond  # time对象微秒数

print 't.isoformat():', t.isoformat()  # 返回ISO 8601格式的时间字符串

print 't.strftime("%H:%M:%S:%f"):', t.strftime("%H:%M:%S:%f")  # 返回指定格式的时间格式

print 't.replace(hour=23, minute=0):', t.replace(hour=23, minute=0)  # 替换

# 输出

t.hour: 12
t.minute: 10
t.second: 30
t.microsecond: 50
t.isoformat(): 12:10:30.000050
t.strftime("%H:%M:%S:%f"): 12:10:30:000050
t.replace(hour=23, minute=0): 23:00:30.000050

回到顶部

4. datetime.datetime类

  datetime对象包含date对象和time对象的所有信息

  • 类方法
from datetime import datetime, time, date

print 'datetime.today():', datetime.today()  # 返回本地当前的时间datetime对象

print 'datetime.now():', datetime.now()  # 返回本地当前的日期和时间的datetime对象

print 'datetime.utcnow():', datetime.utcnow()  # 返回当前UTC日期和时间的datetime对象

print 'datetime.fromtimestamp(1491468000):', datetime.fromtimestamp(1491468000)  # 返回对应时间戳的datetime对象

print 'datetime.fromordinal(699000):', datetime.fromordinal(699000)  # 同date.fromordinal类似

print 'datetime.combine(date(2012,12,12), time(12,12,12)):', datetime.combine(date(2012, 12, 12), time(23, 59, 59))  # 拼接date和time

print 'datetime.strptime("2012-12-10", "%Y-%m-%d"):', datetime.strptime("2012-12-10", "%Y-%m-%d")  # 将特定格式的日期时间字符串解析成datetime对象

# 输出
datetime.today(): 2017-04-06 16:53:12.080000
datetime.now(): 2017-04-06 16:53:12.080000
datetime.utcnow(): 2017-04-06 08:53:12.080000
datetime.fromtimestamp(1491468000): 2017-04-06 16:40:00
datetime.fromordinal(699000): 1914-10-19 00:00:00
datetime.combine(date(2012,12,12), time(12,12,12)): 2012-12-12 23:59:59
datetime.strptime("2012-12-10", "%Y-%m-%d"): 2012-12-10 00:00:00
  • 对象方法和属性
from datetime import datetime
d = datetime(2017, 04, 06, 12, 10, 30)

print 'd.date():', d.date()  # 从datetime中拆分出date

print 'd.time():', d.time()  # 从datetime中拆分出time

print 'd.timetz()', d.timetz()  # 从datetime中拆分出具体时区属性的time

print 'd.replace(year=2016):', d.replace(year=2016)  # 替换

print 'd.timetuple():', d.timetuple()  # 时间数组,即struct_time结构

print 'd.toordinal():', d.toordinal()  # 和date.toordinal一样

print 'd.weekday():', d.weekday()      # 和date.weekday一样

print 'd.isoweekday():', d.isoweekday()  # 和date.isoweekday一样

print 'd.isocalendar():', d.isocalendar()  # 和date.isocalendar一样

print 'd.isoformat():', d.isoformat()  # 同上

print 'd.ctime():', d.ctime()  # 同上

print 'd.strftime("%Y/%m/%d %H:%M:%S"):', d.strftime('%Y/%m/%d %H:%M:%S')  # 同上

# 输出
d.date(): 2017-04-06
d.time(): 12:10:30
d.timetz() 12:10:30
d.replace(year=2016): 2016-04-06 12:10:30
d.timetuple(): time.struct_time(tm_year=2017, tm_mon=4, tm_mday=6, tm_hour=12, tm_min=10, tm_sec=30, tm_wday=3, tm_yday=96, tm_isdst=-1)
d.toordinal(): 736425
d.weekday(): 3
d.isoweekday(): 4
d.isocalendar(): (2017, 14, 4)
d.isoformat(): 2017-04-06T12:10:30
d.ctime(): Thu Apr  6 12:10:30 2017
d.strftime("%Y/%m/%d %H:%M:%S"): 2017/04/06 12:10:30

回到顶部

5. datetime.timedelta类

  timedelta对象表示一个时间段,即两个日期 (date) 或日期时间 (datetime) 之间的差。支持参数:weeks、days、hours、minutes、seconds、milliseconds、microseconds。但是据官方文档说其内部只存储days、seconds 和 microseconds,其他单位会做对应的时间转换。

>>>from datetime import timedelta, date, datetime
>>>d = date.today()
>>>print d
2017-04-06
>>>print d - timedelta(days=5)  # 计算前5天
2017-04-01

>>>dt = datetime.now()
>>>print dt
2017-04-06 17:51:03.568000
>>>print dt - timedelta(days=1, hours=5)  # 计算前1天5小时
2017-04-05 12:51:03.568000

回到顶部

6. 格式字符串

  datetime、date、time 都提供了 strftime() 方法,该方法接收一个格式字符串,输出日期时间的字符串表示。支持的转换格式如下:

字符 含义  例子 
%a英文星期的简写Sun, Mon, …, Sat
%A英文星期的全拼Sunday, Monday, …, Saturday
%w星期几,星期天为0,星期六为60, 1, …, 6
%d这个月的第几天,以0填充的10进制01, 02, …, 31
%b月份英文简写Jan, Feb, …, Dec
%B月份英文全拼January, February, …, December
%m月份数,以0填充的10进制01, 02, …, 12
%y不带世纪的年份00, 01, …, 99
%Y带有世纪的年份1970, 1988, 2001, 2013
%H24小时制的小时数00, 01, …, 23
%I12小时制的小时数01, 02, …, 12
%pAM或者PMAM, PM
%M分钟00, 01, …, 59
%S秒数00, 01, …, 59
%f微秒000000, 000001, …, 999999
%z与utc时间的间隔(), +0000, -0400, +1030
%Z时区(), UTC, EST, CST
%j当年的第几天001, 002, …, 366
%U当年的第几周(星期天作为周的第一天)00, 01, …, 53
%W当年的第几周(星期一作为周的第一天)00, 01, …, 53
%c日期时间的字符串表示Tue Aug 16 21:30:00 1988
%X时间字符串表示21:30:00
%x日期字符串表示08/16/88
%%相当于转意等于一个%%

回到顶部

7. 常见应用

  • 时间戳转日期
>>>from datetime import datetime
>>>timestamp = 1491550000
>>>dt = datetime.fromtimestamp(timestamp)
>>>print dt
2017-04-07 15:26:40
>>>print dt.strftime('%Y-%m-%d')
2017-04-07
  • 字符串转日期
>>>from datetime import datetime
>>>str = '2012-12-10'
>>>dt =datetime.strptime(str, '%Y-%m-%d')
>>>print dt.strftime('%Y/%m/%d')
>>>2012/12/10
  • 计算前几天日期
>>>from datetime import datetime, timedelta
>>>td = datetime.today()
>>>print td
2017-04-07 16:27:52.111000
>>>print dt.strftime('%Y/%m/%d')
2017-04-06 16:27:52.111000

引用2:

Python 使用 datetime isoformat 的正確姿勢 | My.APOLLO

近來查閱 Python 關於 datetime 的標準日期格式(datetime.isoformat)的時候,發現一個奇妙的行為,該行為可能造成日期格式不一致。

本文環境

  • Python 3.7

isoformat

Python 的 isoformat() 預設有 2 個參數,其中 1 個是 timespec , timespec 預設是 auto ,當設定為 auto 時, isoformat 會根據 datetime.utcoffset() 以及 microsecond 的不一樣,而自動產生 4 種不同格式的字串:

  • YYYY-MM-DDTHH:MM:SS.ffffff
  • YYYY-MM-DDTHH:MM:SS
  • YYYY-MM-DDTHH:MM:SS.ffffff+HH:MM[:SS[.ffffff]]
  • YYYY-MM-DDTHH:MM:SS+HH:MM[:SS[.ffffff]]

例如當 microseconds 為 0 與不為 0 的時候,就會產生 2 種格式:

>>> from datetime import datetime, timezone
>>> datetime(2019, 5, 18, 20, 17, 8, 0).isoformat()
'2019-05-18T20:17:08'
>>> datetime(2019, 5, 18, 20, 17, 8, 1).isoformat()
'2019-05-18T20:17:08.000001'

以及當 datetime 有時區資訊時,也會有 2 種不同的格式:

>>> from datetime import datetime, timezone
>>> datetime.now().isoformat()
'2019-05-18T20:17:08.513482'
>>> datetime.now(timezone.utc).isoformat()
'2019-05-18T20:17:08.827410+00:00'

上述 2 種情況就會產生 4 種排列組合。

雖然大部分的使用情況並不會讓人感覺到使用上的問題,但如果是對於有嚴格要求日期格式必須一致的系統,預設的 timespec='auto' 就會有機會產生非預期的格式,進而導致系統發生問題。

如果要解決這問題的話,就必須檢查 datetime object 是否有時區資訊,以及視時間的精準度需求將 timespec 改為以下的選項之一:

  • hours
  • minutes
  • seconds
  • milliseconds
  • microseconds

例如,以下是確保所有的字串都符合 YYYY-MM-DDTHH:MM:SS 格式的範例:

def get_isoformat(dt: datetime):
    if dt.utcoffset() is not None:
        raise ValueError('system does not support timezone')
    return dt.isoformat(timespec='seconds')

您可能感兴趣的与本文相关的镜像

Python3.11

Python3.11

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值