8.1. datetime — 基本日期和时间类型

源代码: Lib/datetime.py

datetime模块提供处理日期和时间的类,既有简单的方式又有复杂的方式。虽然支持日期和时间算法,但实现的重点是为输出格式化和操作提供高效的属性提取。有关相关功能,另请参阅timecalendar模块。

有两种日期和时间对象:“naive”和“aware”。

aware 对象具有关于应用规则和时间调整的充分的信息,例如时区和夏令时信息,来定位相对其他aware 对象的位置。aware 对象用于表示时间的一个特定的时刻,它是明确无二的。 [1].

Naive对象不包含足够的信息来明确地确定其本身相对于其它日期/时间对象的偏移。一个naive对象表示的是协调世界时(UTC)、本地时间还是某些其它时区的时间,完全取决于程序,就像某个特定数字对程序是代表米、英里还是质量一样。Naive对象很容易理解和使用,代价是忽视某些现实因素。

对于需要aware对象的应用程序,datetimetime对象具有可选的时区信息属性tzinfo,可以设置为抽象tzinfo类的子类的一个实例。这些tzinfo对象从UTC时间,时区名称和夏令时是否生效获得偏移量信息。请注意,datetime模块只提供一个具体的tzinfo类叫timezone类。timezone类可以用与UTC固定的偏移表示简单的时区,例如UTC本身或北美EST和EDT时区。支持更深层细节的时区取决于应用程序。世界各地的时间调整规则更加具有政治色彩而不是合乎理性,且经常变化,除了UTC之外,没有适合于每个应用的标准。

datetime模块导出以下常量:

datetime.MINYEAR

datedatetime对象中允许的最小年份。MINYEAR1

datetime.MAXYEAR

datedatetime对象中允许的最大年份数。MAXYEAR9999

也可以看看

模块calendar
日历相关的一般函数。
模块time
时间访问和转化。

8.1.1. 可用类型

class datetime. date

一个理想化的naive日期,假设当前的公历总是,并将永远是有效的。属性:yearmonthday

class datetime. time

一个理想化的时间,独立于任何特定的日子,假设每天有24 * 60 * 60秒(这里没有“闰秒”的概念)。属性:hourminutesecondmicrosecondtzinfo

class datetime. datetime

日期和时间的组合。属性:yearmonthdayhourminutesecondmicrosecondtzinfo

class datetime. timedelta

表示两个datetimedatetime实例之间相差的时间,分辨率达到微秒。

class datetime. tzinfo

时区信息对象的抽象基类。它们由datetimetime类使用,以提供自定义时间的调整(例如,计算时区和/或夏令时)。

class datetime. timezone

实现tzinfo抽象基类的类,表示与UTC的固定偏移量。

版本3.2中的新功能。

这些类型的对象是不可变的。

date类型的对象总是naive的。

timedatetime类型的对象可能是naive的或aware的。如果d.tzinfo不为Noned.tzinfo.utcoffset(d)不返回None,则datetime对象d是aware的。如果d.tzinfoNone或者d.tzinfo不为None但是d.tzinfo .utcoffset(d)返回None,则d是naive的。如果t.tzinfo不为Nonet.tzinfo.utcoffset(None)不返回None,则time对象t是aware的。否则,t是naive的。

Naive和aware之间的区别不适用于timedelta对象。

子类关系:

object
    timedelta
    tzinfo
        timezone
    time
    date
        datetime

8.1.2. timedelta对象

timedelta对象表示时间的间隔,即两个日期或时间之间的差值。

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

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

只有days(天)seconds(秒)microseconds(微秒)存储在内部。参数被转换为这些单位:

  • 1毫秒转换为1000微秒。
  • 1分钟转换为60秒。
  • 1小时转换为3600秒。
  • 1周被转换为7天。

然后对天,秒和微秒进行归一化,以便表示是唯一的

  • 0 <= microseconds < 1000000
  • 0 <= seconds < 3600*24(一天中的秒数)
  • -999999999 <= days <= 999999999

如果有任何一个参数是浮点数并且有微秒数,则将所有参数剩余的小数微秒相加,并使用round-half-to-even规则将它们的和舍入到最接近的微秒。如果没有参数是浮点数,则转换和规范化过程是精确的(不会丢失任何信息)。

如果days的归一化值超出表示的范围,则会引发OverflowError

请注意,负值的标准化起初可能令人惊讶。例如,

>>> from datetime import timedelta
>>> d = timedelta(microseconds=-1)
>>> (d.days, d.seconds, d.microseconds)
(-1, 86399, 999999)

类属性有:

timedelta.min

最小的timedelta对象,timedelta(-999999999)

timedelta.max

最大的timedelta对象,timedelta(days=999999999, hours=23, minutes=59, seconds=59, microseconds=999999)

timedelta.resolution

不相等的timedelta对象之间的最小可能差值,timedelta(microseconds=1)

注意,由于归一化,timedelta.max > -timedelta.min-timedelta.max不能表示成一个timedelta对象。

实例属性(只读):

属性
days介于-999999999和999999999之间(包括-999999999和999999999)
seconds介于0和86399之间(包括0和86399)
microseconds介于0和999999之间(包括0和999999)

支持的操作:

操作结果
t1 = t2 + t3t2t3的和。之后,t1-t2 == t3 and t1-t3 == t2为真。(1)
t1 = t2 - t3t2t3的差。之后t1 == t2 - t3 and t2 == t1 + t3为真。(1)
t1 = t2 * i t1 = i * t2Delta乘以一个整数。之后,如果i != 0,则t1 // i == t2为真。
通常,t1 * i == t1 * (i-1) + t1为真。(1)
t1 = t2 * f t1 = f * t2Delta乘以一个浮点数。结果使用round-half-to-even舍入到timedelta.resolution最近的倍数。
f = t2 / t3t2除以t3(3)。返回一个float对象。
t1 = t2 / f t1 = t2 / iDelta除以一个浮点数或整数。结果使用round-half-to-even舍入到timedelta.resolution最近的倍数。
t1 = t2 // it1 = t2 // t3计算商,余数(如果有的话)被丢弃。在第二种情况下,返回一个整数。(3)
t1 = t2 % t3计算余数,为一个timedelta对象。(3)
q, r = divmod(t1, t2)计算商和余数:q = t1 // t2 (3)且r = t1 % t2q一个是整数,r是一个timedelta对象。
+t1返回具有相同值的timedelta对象。(2)
-t1等效于timedelta(-t1.days, -t1.seconds, -t1.microseconds),和t1* -1。(1)(4)
abs(t)t.days >= 0时等效于+t,当t.days < 0时等效于-t(2)
str(t)[D day[s], ][H]H:MM:SS[.UUUUUU]形式返回一个字符串,其中对于负tD为负数。(5)
repr(t)datetime.timedelta(D[, S[, U]])形式返回一个字符串,其中对于负tD为负数。(5)

注:

  1. 虽然相等,但可能会溢出。

  2. 相等且不会溢出。

  3. 除0引发ZeroDivisionError

  4. - timedelta.max不能表示成一个timedelta对象。

  5. timedelta对象的字符串表示形式与其内部表示形式相似。这导致负面timedeltas有点不寻常的结果。例如:

    >>> timedelta(hours=-5)
    datetime.timedelta(-1, 68400)
    >>> print(_)
    -1 day, 19:00:00
    

除了上面列出的操作,timedelta对象支持与datedatetime对象相加和相减(见下文)。

在版本3.2中更改:现在支持一个timedelta对象和另一个timedelta对象的整除和真除,以及余数操作和divmod()函数。现在支持timedelta对象与float对象的真除和乘法。

支持timedelta对象的比较,表示较小时间差的timedelta对象被认为是较小的timedelta。为了阻止混合类型之间的比较回退到默认的以对象地址进行的比较,当将timedelta对象与不同类型的对象进行比较时,会引发TypeError除非比较是==!=后一种情况分别返回FalseTrue

timedelta对象是可哈希的(可用作字典键),支持高效的pickling,在布尔上下文中,timedelta当且仅当它不等于timedelta(0)时才为真。

实例方法:

timedelta.total_seconds()

返回持续时间中包含的总秒数。等同于td / timedelta(seconds=1)

请注意,对于非常大的时间间隔(在大多数平台上超过270年),此方法将失去微秒精度。

版本3.2中的新功能。

用法示例:

>>> from datetime import timedelta
>>> year = timedelta(days=365)
>>> another_year = timedelta(weeks=40, days=84, hours=23,
...                          minutes=50, seconds=600)  # adds up to 365 days
>>> year.total_seconds()
31536000.0
>>> year == another_year
True
>>> ten_years = 10 * year
>>> ten_years, ten_years.days // 365
(datetime.timedelta(3650), 10)
>>> nine_years = ten_years - year
>>> nine_years, nine_years.days // 365
(datetime.timedelta(3285), 9)
>>> three_years = nine_years // 3;
>>> three_years, three_years.days // 365
(datetime.timedelta(1095), 3)
>>> abs(three_years - ten_years) == 2 * three_years + year
True

8.1.3. date对象

date对象表示理想化日历中的日期(年、月和日),即当前公历日历在两个方向上无限延伸。第1年的1月1日被称为第1日,第1年的1月2日被称为第2日,依此类推。这与Dershowitz和Reingold的书Calendrical Calculations中的“预测格里历”日历的定义相匹配,它是所有计算的基准日历。请参阅本书,了解在格雷戈里公会和许多其他日历系统之间进行转换的算法。

class datetime.date(year, month, day)

所有参数都是必需的。参数可以是以下范围内的整数:

  • MINYEAR <= year <= MAXYEAR
  • 1 <= month <= 12
  • 1 <= day <= number of days in the given month and year

如果给出了这些范围之外的参数,则会引发ValueError

其他构造函数,所有类方法:

classmethod date.today()

返回当前的本地日期。这相当于date.fromtimestamp(time.time())

classmethod date.fromtimestamp(timestamp)

返回与POSIX时间戳对应的本地日期,例如time.time()返回的时间戳。如果时间戳超出平台C localtime()函数支持的值的范围则引发OverflowError,如果localtime()失败则引发OSError从1970年到2038年这种情况很常见。请注意,在时间戳中包含闰秒的非POSIX系统上,fromtimestamp()会忽略闰秒。

在版本3.3中更改:如果时间戳超出平台C localtime ()函数支持的值范围,则引发OverflowError而不是ValueErrorlocaltime()失败时引发OSError而不是ValueError

classmethod date.fromordinal(ordinal)

返回对应于格雷高尔顺序的日期,其中第1年的1月1有序号1。如果不满足1 <= ordinal <= date.max.toordinal(),则引发ValueError对于任何日期ddate.fromordinal(d.toordinal()) == d

类属性:

date.min

可表示的最早日期,date(MINYEAR, 1, 1)

date.max

可表示最晚的日期,date(MAXYEAR, 12, 31)

date.resolution

不相等的日期对象之间的最小可能差异,timedelta(days=1)

实例属性(只读):

date.year

MINYEARMAXYEAR之间,包括这两个值。

date.month

1至12之间。

date.day

在1和给定年的给定月份中的天数之间。

支持的操作:

操作结果
date2 = date1 + timedeltadate2为从date1中移除timedelta.days天。(1)
date2 = date1 - timedelta计算date2,以便date2 + timedelta == date1(2)
timedelta = date1 - date2(3)
date1 date2date1在时间上位于date2之前,则date1小于date2(4)

注:

  1. 如果timedelta.days > 0,则date2在时间上向前移,如果timedelta.days < 0,则向后移。之后,date2 - date1 == timedelta.daystimedelta.secondstimedelta.microseconds被忽略。如果date2.year小于MINYEAR或大于MAXYEAR,则引发OverflowError
  2. 这不完全等同于date1 + (-timedelta),因为-timedelta在单独的情况下可能会溢出,而date1 - timedelta不会。timedelta.secondstimedelta.microseconds被忽略。
  3. 相等且不会溢出。timedelta.seconds和timedelta.microseconds为0,并且之后date2 + timedelta == date1。
  4. 换句话说,date1 < date2当且仅当date1.toordinal() < date2.toordinal()为了停止比较回退到默认的比较对象地址的方式,如果另一比较对象不是date对象,日期比较通常引发TypeError但是,如果另一个比较对象具有timetuple()属性,则会返回NotImplemented这个钩子给其他种类的日期对象实现混合型比较的机会。如果不是,当将date对象与不同类型的对象进行比较时,则会引发TypeError,除非比较为==!=后一种情况分别返回FalseTrue

日期可以用作字典键。在布尔上下文中,所有date对象都被视为真。

实例方法:

date.replace(year, month, day)

使用相同的值返回一个日期,除了那些由指定的关键字参数给定新值的参数。例如,如果d == date(2002, 12, 31),那么d.replace(day=26) == date(2002, 12, 26)

date.timetuple()

返回一个time.struct_time,类似time.localtime()的返回值。Hours、minutes和seconds为0,DST标记为-1。d.timetuple()等同于time.struct_time((d.year, d.month, d.day, 0, 0, 0, d.weekday(), yday, -1)),其中yday = d.toordinal() - date(d.year, 1, 1).toordinal() + 1当前年份中的天数,1月1日为开始的第1天。

date.toordinal()

返回该日期的预测格里历序号,其中第一年的1月1号具有序数1。对于任何date对象ddate.fromordinal(d.toordinal()) == d

date.weekday()

将星期几作为整数返回,其中星期一为0,星期日为6。例如,date(2002, 12, 4).weekday() == 2,是星期三。另请参见isoweekday()

date.isoweekday()

将星期几作为整数返回,其中星期一为1,星期日为7。例如,date(2002, 12, 4).isoweekday() == 3,是星期三。另请参见weekday()isocalendar()

date.isocalendar()

返回3元组(ISO年,ISO周编号,ISO工作日)。

ISO日历是公历日历的广泛使用的变体。有关详细说明,请参阅https://www.staff.science.uu.nl/~gent0113/calendar/isocalendar.htm

ISO年包括52或53个整周,其中一周从星期一开始并在星期日结束。ISO年的第一周是一年的第一个包含星期四的(公历)日历周。这称为周数1,该周四的ISO年与其公历年相同。

例如,2004年从星期四开始,因此ISO 2004年的第一周从2003年12月29日星期一开始,2004年1月4日星期日结束,因此date(2003, 12, 29).isocalendar() == (2004, 1, 1)以及date(2004, 1, 4).isocalendar() == (2004, 1, 7)

date.isoformat()

以ISO 8601格式返回表示日期的字符串'YYYY-MM-DD'。例如,date(2002, 12, 4).isoformat() == '2002-12-04'

date.__str__()

对于日期dstr(d)等同于d.isoformat()

date.ctime()

返回表示日期的字符串,例如date(2002, 12, 4).ctime() == 'Wed Dec 4 00:00:00 2002'在原生的C函数ctime()time.ctime()调用它,但是date.ctime() 不调用它)遵守C标准的平台上,d.ctime()等效于time.ctime(time.mktime(d.timetuple()))

date.strftime(format)

返回一个表示日期的字符串,由一个明确的格式字符串控制。指代小时,分钟或秒的格式代码将会看到0个值。有关格式化指令的完整列表,请参阅strftime()和strptime()行为。

date.__format__(format)

date.strftime()相同。这使得可以在使用str.format()时为date对象指定格式字符串。有关格式化指令的完整列表,请参见strftime()和strptime()的行为

计算事件日期的示例:

>>> import time
>>> from datetime import date
>>> today = date.today()
>>> today
datetime.date(2007, 12, 5)
>>> today == date.fromtimestamp(time.time())
True
>>> my_birthday = date(today.year, 6, 24)
>>> if my_birthday < today:
...     my_birthday = my_birthday.replace(year=today.year + 1)
>>> my_birthday
datetime.date(2008, 6, 24)
>>> time_to_birthday = abs(my_birthday - today)
>>> time_to_birthday.days
202

使用date的示例:

>>> from datetime import date
>>> d = date.fromordinal(730920) # 730920th day after 1. 1. 0001
>>> d
datetime.date(2002, 3, 11)
>>> t = d.timetuple()
>>> for i in t:     
...     print(i)
2002                # year
3                   # month
11                  # day
0
0
0
0                   # weekday (0 = Monday)
70                  # 70th day in the year
-1
>>> ic = d.isocalendar()
>>> for i in ic:    
...     print(i)
2002                # ISO year
11                  # ISO week number
1                   # ISO day number ( 1 = Monday )
>>> d.isoformat()
'2002-03-11'
>>> d.strftime("%d/%m/%y")
'11/03/02'
>>> d.strftime("%A %d. %B %Y")
'Monday 11. March 2002'
>>> 'The {1} is {0:%d}, the {2} is {0:%B}.'.format(d, "day", "month")
'The day is 11, the month is March.'

8.1.4. datetime对象

datetime对象是一个包含date对象和time对象所有信息的单个对象。类似date对象,datetime假定当前公历日历在两个方向上延伸;类似time对象,datetime假设每天有精确的3600*24秒。

构造函数:

class datetime.datetime(year, month, day, hour=0, minute=0, second=0, microsecond=0, tzinfo=None)

年,月和日的参数是必需的。tzinfo可以是Nonetzinfo子类的实例。其余的参数可以是以下范围内的整数:

  • MINYEAR <= year <= MAXYEAR
  • 1 <= month <= 12
  • 1 <= day <= number of days in the given month and year
  • 0 <= hour < 24
  • 0 <= minute < 60
  • 0 <= second < 60
  • 0 <= microsecond < 1000000

如果给出了这些范围之外的参数,则会引发ValueError

其他构造函数,所有类方法:

classmethod datetime.today()

返回当前本地日期时间,其中tzinfoNone这相当于datetime.fromtimestamp(time.time())另请参见now()fromtimestamp()

classmethod datetime.now(tz=None)

返回当前的本地日期和时间。如果可选参数tzNone或未指定,则这类似于today(),但如果可能,通过time.time()时间戳提供更高的精度(例如,这在提供C gettimeofday()函数的平台上是可能的)。

如果tz不为None,则必须是tzinfo子类的实例,当前日期和时间将转换为tz的时区。在这种情况下,结果等效于tz.fromutc(datetime.utcnow().replace(tzinfo=tz))另请参见today()utcnow()

classmethod datetime.utcnow()

返回当前UTC日期和时间,其中tzinfoNone这类似now(),但返回当前UTC日期和时间,作为一个naive的datetime对象。可以通过调用datetime.now(timezone.utc)来得到aware的当前UTC datetime。另请参见now()

classmethod datetime.fromtimestamp(timestamp, tz=None)

返回与POSIX时间戳对应的本地日期和时间,例如time.time()返回的时间戳。如果可选参数tzNone或未指定,则时间戳将转换为平台的本地日期和时间,返回的datetime对象是naive的。

如果tz不是None,则必须是tzinfo子类的实例,此时时间戳将转换为tz的时区。在这种情况下,结果等效于tz.fromutc(datetime.utcfromtimestamp(timestamp).replace(tzinfo=tz))

如果时间戳超出平台C localtime()gmtime()函数支持的值的范围,则fromtimestamp()可能引发OverflowError;如果localtime()gmtime()函数失败,则引发OSError常见的做法是限制年份在1970和2038之间。请注意,在时间戳中包含闰秒的非POSIX系统上,fromtimestamp()会忽略闰秒,这可能使得两个相差1秒的时间戳产生相同的datetime对象。另请参见utcfromtimestamp()

在版本3.3中更改:如果时间戳超出平台C localtime ()gmtime()函数支持的值范围,则引发OverflowError而不是ValueErrorlocaltime()gmtime()失败时引发OSError而不是ValueError

classmethod datetime.utcfromtimestamp(timestamp)

返回与POSIX时间戳对应的UTC datetime,其中tzinfoNone如果时间戳超出平台C gmtime()函数支持的值的范围,则它可能引发OverflowError;如果gmtime()函数失败,则引发OSError常见的做法是限制年份在1970和2038之间。

要获取aware的datetime对象,请调用fromtimestamp()

datetime.fromtimestamp(timestamp, timezone.utc)

在POSIX兼容平台上,它等效于以下表达式:

datetime(1970, 1, 1, tzinfo=timezone.utc) + timedelta(seconds=timestamp)

但后者公式始终支持全部的年份范围:MINYEARMAXYEAR之间。

在版本3.3中更改:如果时间戳超出平台C gmtime()函数支持的值范围,则引发OverflowError而不是ValueErrorgmtime()失败时引发OSError而不是ValueError

classmethod datetime.fromordinal(ordinal)

返回对应于普通公历的序数的datetime,其中第1年的1月1日为序数1。如果不满足1 <= ordinal <= datetime.max.toordinal(),则引发ValueError结果的hour、minute、second和microsecond都是0,并且tzinfoNone

classmethod datetime.combine(date, time)

返回一个新的datetime对象,其日期部分等于给定的date对象,其时间部分和tzinfo属性等于给定time对象。对于任何datetime对象dd == datetime.combine(d.date(), d.timetz())如果date是一个datetime对象,则会忽略其时间部分和tzinfo属性。

classmethod datetime.strptime(date_string, format)

返回对应于date_stringdatetime,根据format进行解析。这相当于datetime(*(time.strptime(date_string, format)[0:6]))如果time.strptime()无法解析date_string和format,或者如果返回的值不是时间元组,则会引发ValueError有关格式化指令的完整列表,请参见strftime()和strptime()的行为

类属性:

datetime.min

可表示的最早datetimedatetime(MINYEAR, 1, 1, tzinfo=None)

datetime.max

可表示的最晚datetimedatetime(MAXYEAR, 12, 31, 23, 59, 59, 999999, tzinfo=None)

datetime.resolution

不相等的datetime对象之间的最小可能差值,timedelta(microseconds=1)

实例属性(只读):

datetime.year

MINYEARMAXYEAR之间,包括这两个值。

datetime.month

1至12之间。

datetime.day

在1和给定年的给定月份中的天数之间。

datetime.hour

range(24)之间。

datetime.minute

range(60)之间。

datetime.second

range(60)之间。

datetime.microsecond

range(1000000)之间。

datetime.tzinfo

作为tzinfo参数传递给datetime构造函数的对象,如果没有传递则为None

支持的操作:

操作结果
datetime2 = datetime1 + timedelta(1)
datetime2 = datetime1 - timedelta(2)
timedelta = datetime1 - datetime2(3)
datetime1 < datetime2比较datetimedatetime(4)
  1. datetime2是从datetime1移除timedelta的时间,如果timedelta.days > 0则向前移动,如果timedelta.days < 0则向后移动。结果具有与输入datetime相同的tzinfo属性,并且之后datetime2 - datetime1 == timedelta。如果datetime2.year小于MINYEAR或大于MAXYEAR,则会引发OverflowError请注意,即使输入是aware对象,也不会执行时区调整。

  2. 计算datetime2,使datetime2 + timedelta == datetime1。与加法一样,结果具有与输入日期时间相同的tzinfo属性,即使输入是aware的,也不执行时区调整。这不完全等同于 datetime1 + (-timedelta),因为单独的-timedelta可能会溢出,而在此情况下datetime1 - timedelta不会。

  3. 只有当两个操作数都是naive的或者两者都是aware的时,才定义从datetime减去一个datetime如果一个是aware的而另一个是naive的,则会引发TypeError

    如果两者都是naive的,或者两者都是aware的且具有相同的tzinfo属性,则会忽略tzinfo属性,结果是一个timedelta对象t,使得datetime2 + t == datetime1在这种情况下不进行时区调整。

    如果两者都是aware的且具有不同的tzinfo属性,则a-b表现得好像ab被首先转换成naive的UTC时间。结果是(a.replace(tzinfo=None) - a.utcoffset()) - (b.replace(tzinfo=None) - b.utcoffset()),除非具体的实现永远不会溢出。

  4. datetime1在时间上位于datetime2 之前,则认为datetime1小于datetime2

    如果一个比较数据是naive的,而另一个是aware的,则尝试进行顺序比较时会产生TypeError对于相等性比较,naive实例永远不等于aware实例。

    如果两个比较数都是aware的并且具有相同的tzinfo属性,则忽略共同的tzinfo属性,并比较基本的时间数据。如果两个比较数都是aware并且具有不同的tzinfo属性,则首先通过减去它们的UTC偏移(从self.utcoffset()获得)来调整比较数。

    在版本3.3中已更改:naive的和aware的datetime实例之间的相等性比较不引发TypeError

    注意

    为了停止比较回退到默认的比较对象地址的方式,如果另一比较对象不是datetime对象,datetime比较通常引发TypeError但是,如果另一个比较对象具有timetuple()属性,则会返回NotImplemented这个钩子给其他种类的日期对象实现混合型比较的机会。如果不是,当将datetime对象与不同类型的对象进行比较时,则会引发TypeError,除非比较为==!=后一种情况分别返回FalseTrue

datetime对象可以用作字典的键。在布尔上下文中,所有datetime对象都被视为真。

实例方法:

datetime.date()

返回具有相同年、月和日的date对象。

datetime.time()

返回具有相同小时、分钟、秒和微秒的time对象。tzinfoNone另请参见方法timetz()

datetime.timetz()

返回具有相同小时、分钟、秒、微秒和tzinfo属性的time对象。另请参见方法time()

datetime.replace([year[, month[, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]]]]])

使用相同的属性返回一个日期时间,除了那些通过指定任何关键字参数给出新值的属性。请注意,可以指定tzinfo=None来从aware的datetime创建一个naive的datetime,而不需对date和time数据进行转换。

datetime.astimezone(tz=None)

返回带有新tzinfo属性tzdatetime对象,调整日期和时间数据使结果与self 的UTC时间相同,但为tz的本地时间。

如果提供,tz必须是tzinfo子类的实例,并且其utcoffset()dst()方法不得返回Noneself必须是aware的(self.tzinfo不能是None,以及self.utcoffset()不能返回None)。

如果不带参数调用(或tz=None),则假定使用系统本地时区。转换后的datetime实例的.tzinfo属性将设置为timezone的实例,其带有从操作系统获取的时区名称和偏移量。

如果self.tzinfotz,则self.astimezone(tz)等于self:日期调整和时间数据不会调整。否则结果是时区tz中的本地时间,表示与self相同的UTC时间:astz = dt.astimezone(tz)之后,astz - astz.utcoffset()通常具有与dt - dt.utcoffset()相同的日期和时间数据。tzinfo的讨论解释了无法实现的在夏令时转换边界的情况(仅当tz同时建模标准时和夏令时的时候才出现问题)。

如果你只想在不调整日期和时间数据的情况下将时区对象tz附加到datetimedt,请使用dt.replace(tzinfo=tz)如果你只想从aware的datetime dt中删除时区对象而不转换日期和时间数据,请使用dt.replace(tzinfo=None)

请注意,可以在tzinfo子类中覆盖默认的tzinfo.fromutc()方法,以影响astimezone()返回的结果。忽略错误情况,astimezone()的行为如下:

def astimezone(self, tz):
    if self.tzinfo is tz:
        return self
    # Convert self to UTC, and attach the new time zone object.
    utc = (self - self.utcoffset()).replace(tzinfo=tz)
    # Convert from UTC to tz's local time.
    return tz.fromutc(utc)

在版本3.3中更改: tz现在可以省略。

datetime.utcoffset()

如果tzinfoNone,则返回None,否则返回self.tzinfo.utcoffset(self);如果后者未返回None或表示小于一天的整数分钟的timedelta对象,则引发一个异常。

datetime.dst()

如果tzinfoNone,则返回None,否则返回self.tzinfo.dst(self);如果后者未返回None或表示小于一天的整数分钟的timedelta对象,则引发一个异常。

datetime.tzname()

如果tzinfoNone,则返回None,否则返回self.tzinfo.tzname(self);如果后者不返回None或字符串对象,则引发一个异常。

datetime.timetuple()

返回一个time.struct_time,类似time.localtime()的返回值。d.timetuple()等同于time.struct_time((d.year, d.month, d.day, d.hour, d.minute, d.second, d.weekday(), yday, dst)),其中yday = d.toordinal() - date(d.year, 1, 1).toordinal() + 1当前年份中的天数,1月1日为开始的第1天。根据dst()方法设置结果的tm_isdst标志:如果tzinfoNonedst()返回None,则tm_isdst设置为-1;如果dst()返回非零值,tm_isdst设置为1;否则tm_isdst设置为0

datetime.utctimetuple()

如果datetime实例d是naive的,它等同于d.timetuple(),但是无论d.dst()返回什么,tm_isdst都被强制设置为0。对于UTC时间DST始终不会生效。

如果d是aware的,则通过减去d.utcoffset()归一化d,并返回归一化的时间time.struct_timetm_isdst被强制为0。请注意,如果d.year是MINYEARMAXYEAR且UTC调整溢出超过一年的边界,则可能会引发OverflowError

datetime.toordinal()

返回日期的公历序数。等同于self.date().toordinal()

datetime.timestamp()

返回对应于datetime实例的POSIX时间戳。返回值类似于time.time()返回的float

Naive的datetime实例假设表示本地时间,并且此方法依赖于平台C mktime()函数来执行转换。由于在许多平台上,datetime支持的值范围比mktime()的范围更广,因此此方法可能会在很远的过去或很远的未来时间引发OverflowError

对于aware的datetime实例,返回值计算为:

(dt - datetime(1970, 1, 1, tzinfo=timezone.utc)).total_seconds()

版本3.3中的新功能。

注意

没有任何方法直接从表示UTC时间的一个naive的datetime实例获取POSIX时间戳。如果你的应用程序使用此约定,并且你的系统时区未设置为UTC,你可以通过提供tzinfo=timezone.utc来获取POSIX时间戳:

timestamp = dt.replace(tzinfo=timezone.utc).timestamp()

或直接计算时间戳:

timestamp = (dt - datetime(1970, 1, 1)) / timedelta(seconds=1)
datetime.weekday()

将星期几作为整数返回,其中星期一为0,星期日为6。等同于self.date().weekday()另请参见isoweekday()

datetime.isoweekday()

将星期几作为整数返回,其中星期一为1,星期日为7。等同于self.date().isoweekday()另请参阅weekday()isocalendar()

datetime.isocalendar()

返回3元组(ISO年,ISO周编号,ISO工作日)。等同于self.date().isocalendar()

datetime.isoformat(sep='T')

返回以ISO 8601 格式YYYY-MM-DDTHH:MM:SS.mmmmmm表示日期和时间的字符串,如果microsecond为0,则以YYYY-MM-DDTHH:MM:SS的格式。

如果utcoffset()不返回None,则会附加一个6个字符的字符串,以(带符号)的小时和分钟为单位提供UTC偏移量:YYYY-MM-DDTHH:MM:SS.mmmmmm+HH:MM,如果microsecond为0,则为YYYY-MM-DDTHH:MM:SS+HH:MM。

可选参数sep(默认为'T')是一个单字符分隔符,位于结果的日期和时间部分之间。例如,

>>> from datetime import tzinfo, timedelta, datetime
>>> class TZ(tzinfo):
...     def utcoffset(self, dt): return timedelta(minutes=-399)
...
>>> datetime(2002, 12, 25, tzinfo=TZ()).isoformat(' ')
'2002-12-25 00:00:00-06:39'
datetime.__str__()

对于datetime实例dstr(d)等效于d.isoformat(' ')

datetime.ctime()

返回一个表示日期和时间的字符串,例如datetime(2002, 12, 4, 20, 30, 40).ctime() == 'Wed Dec 4 20:30:40 2002'在原生的C函数ctime()time.ctime()调用它,但是datetime.ctime() 不调用它)遵守C标准的平台上,d.ctime()等效于time.ctime(time.mktime(d.timetuple()))

datetime.strftime(format)

返回一个表示日期和时间的字符串,由显式的格式字符串控制。有关格式化指令的完整列表,请参见strftime()和strptime()的行为

datetime.__format__(format)

datetime.strftime()相同。这使得可以在使用str.format()时为datetime对象指定格式字符串。有关格式化指令的完整列表,请参见strftime()和strptime()的行为

使用日期时间对象的示例:

>>> from datetime import datetime, date, time
>>> # Using datetime.combine()
>>> d = date(2005, 7, 14)
>>> t = time(12, 30)
>>> datetime.combine(d, t)
datetime.datetime(2005, 7, 14, 12, 30)
>>> # Using datetime.now() or datetime.utcnow()
>>> datetime.now()   
datetime.datetime(2007, 12, 6, 16, 29, 43, 79043)   # GMT +1
>>> datetime.utcnow()   
datetime.datetime(2007, 12, 6, 15, 29, 43, 79060)
>>> # Using datetime.strptime()
>>> dt = datetime.strptime("21/11/06 16:30", "%d/%m/%y %H:%M")
>>> dt
datetime.datetime(2006, 11, 21, 16, 30)
>>> # Using datetime.timetuple() to get tuple of all attributes
>>> tt = dt.timetuple()
>>> for it in tt:   
...     print(it)
...
2006    # year
11      # month
21      # day
16      # hour
30      # minute
0       # second
1       # weekday (0 = Monday)
325     # number of days since 1st January
-1      # dst - method tzinfo.dst() returned None
>>> # Date in ISO format
>>> ic = dt.isocalendar()
>>> for it in ic:   
...     print(it)
...
2006    # ISO year
47      # ISO week
2       # ISO weekday
>>> # Formatting datetime
>>> dt.strftime("%A, %d. %B %Y %I:%M%p")
'Tuesday, 21. November 2006 04:30PM'
>>> 'The {1} is {0:%d}, the {2} is {0:%B}, the {3} is {0:%I:%M%p}.'.format(dt, "day", "month", "time")
'The day is 21, the month is November, the time is 04:30PM.'

在tzinfo中使用datetime:

>>> from datetime import timedelta, datetime, tzinfo
>>> class GMT1(tzinfo):
...     def utcoffset(self, dt):
...         return timedelta(hours=1) + self.dst(dt)
...     def dst(self, dt):
...         # DST starts last Sunday in March
...         d = datetime(dt.year, 4, 1)   # ends last Sunday in October
...         self.dston = d - timedelta(days=d.weekday() + 1)
...         d = datetime(dt.year, 11, 1)
...         self.dstoff = d - timedelta(days=d.weekday() + 1)
...         if self.dston <=  dt.replace(tzinfo=None) < self.dstoff:
...             return timedelta(hours=1)
...         else:
...             return timedelta(0)
...     def tzname(self,dt):
...          return "GMT +1"
...
>>> class GMT2(tzinfo):
...     def utcoffset(self, dt):
...         return timedelta(hours=2) + self.dst(dt)
...     def dst(self, dt):
...         d = datetime(dt.year, 4, 1)
...         self.dston = d - timedelta(days=d.weekday() + 1)
...         d = datetime(dt.year, 11, 1)
...         self.dstoff = d - timedelta(days=d.weekday() + 1)
...         if self.dston <=  dt.replace(tzinfo=None) < self.dstoff:
...             return timedelta(hours=1)
...         else:
...             return timedelta(0)
...     def tzname(self,dt):
...         return "GMT +2"
...
>>> gmt1 = GMT1()
>>> # Daylight Saving Time
>>> dt1 = datetime(2006, 11, 21, 16, 30, tzinfo=gmt1)
>>> dt1.dst()
datetime.timedelta(0)
>>> dt1.utcoffset()
datetime.timedelta(0, 3600)
>>> dt2 = datetime(2006, 6, 14, 13, 0, tzinfo=gmt1)
>>> dt2.dst()
datetime.timedelta(0, 3600)
>>> dt2.utcoffset()
datetime.timedelta(0, 7200)
>>> # Convert datetime to another time zone
>>> dt3 = dt2.astimezone(GMT2())
>>> dt3     
datetime.datetime(2006, 6, 14, 14, 0, tzinfo=<GMT2 object at 0x...>)
>>> dt2     
datetime.datetime(2006, 6, 14, 13, 0, tzinfo=<GMT1 object at 0x...>)
>>> dt2.utctimetuple() == dt3.utctimetuple()
True

8.1.5. time对象

Time对象表示一天中的(本地)时间,独立于任何特定的日子,并且可以通过tzinfo对象进行调整。

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

所有参数都是可选的。tzinfo可以是Nonetzinfo子类的实例。其余的参数可以是以下范围内的整数:

  • 0 <= hour < 24
  • 0 <= minute < 60
  • 0 <= second < 60
  • 0 <= microsecond < 1000000.

如果给出了这些范围之外的参数,则会引发ValueError所有默认值为0,除了tzinfo默认为None

类属性:

time.min

可表示的最早的timetime(0, 0, 0, 0)

time.max

可表示的最晚的timetime(23, 59, 59, 999999)

time.resolution

不相等的time对象之间的最小可能差,即timedelta(microseconds=1),还要注意time不支持算术操作。

实例属性(只读):

time.hour

range(24)之间。

time.minute

range(60)之间。

time.second

range(60)之间。

time.microsecond

range(1000000)之间。

time.tzinfo

作为tzinfo参数传递给time构造函数的对象,如果没有传递则为None

支持的操作:

  • timetime比较,其中如果a在时间上位于b之前,则认为a小于b如果一个比较数据是naive的,而另一个是aware的,则尝试进行顺序比较时会产生TypeError对于相等性比较,naive实例永远不等于aware实例。

    如果两个比较数都是aware的并且具有相同的tzinfo属性,则忽略共同的tzinfo属性,并比较基本的times数据。如果两个比较数都是aware并且具有不同的tzinfo属性,则首先通过减去它们的UTC偏移(从self.utcoffset()获得)来调整比较数。为了阻止混合类型之间的比较回退到默认的以对象地址进行的比较,当将time对象与不同类型的对象进行比较时,会引发TypeError除非比较是==!=后一种情况分别返回FalseTrue

    在版本3.3中已更改:naive的和aware的time实例之间的相等性比较不引发TypeError

  • 哈希,用作字典的键

  • 高效的pickling

在布尔上下文中,time对象始终被视为真。

在3.5版本中已更改:在Python 3.5之前,如果某个time对象表示UTC的午夜,则将其视为假。这个行为被认为是晦涩的且容易出错的,已在Python 3.5中删除。有关详细信息,请参见issue 13936

实例方法:

time.replace([hour[, minute[, second[, microsecond[, tzinfo]]]]])

返回具有相同值的time,但通过任何关键字参数指定新值的那些属性除外。请注意,可以指定tzinfo=None来从aware的time创建一个naive的time,而不需对time数据进行转换。

time.isoformat()

返回以ISO 8601 格式HH:MM:SS.mmmmmm表示间的字符串,如果self.microsecond为0,则以HH:MM:SS的格式。如果utcoffset()不返回None,则会附加一个6个字符的字符串,以(带符号)的小时和分钟为单位提供UTC偏移量:HH:MM:SS.mmmmmm+HH:MM,如果self.microsecond为0,则为HH:MM:SS+HH:MM。

time.__str__()

对于时间tstr(t)等同于t.isoformat()

time.strftime(format)

返回一个表示time的字符串,由显式的格式字符串控制。有关格式化指令的完整列表,请参见strftime()和strptime()的行为

time.__format__(format)

time.strftime()相同。这使得可以在使用str.format()时为time对象指定格式字符串。有关格式化指令的完整列表,请参见strftime()和strptime()的行为

time.utcoffset()

如果tzinfoNone,则返回None,否则返回self.tzinfo.utcoffset(None);如果后者未返回None或表示小于一天的整数分钟的timedelta对象,则引发一个异常。

time.dst()

如果tzinfoNone,则返回None,否则返回self.tzinfo.utcoffset(None);如果后者未返回None或表示小于一天的整数分钟的timedelta对象,则引发一个异常。

time.tzname()

如果tzinfoNone,则返回None,否则返回self.tzinfo.tzname(None);如果后者不返回None或字符串对象,则引发一个异常。

例:

>>> from datetime import time, tzinfo
>>> class GMT1(tzinfo):
...     def utcoffset(self, dt):
...         return timedelta(hours=1)
...     def dst(self, dt):
...         return timedelta(0)
...     def tzname(self,dt):
...         return "Europe/Prague"
...
>>> t = time(12, 10, 30, tzinfo=GMT1())
>>> t                               
datetime.time(12, 10, 30, tzinfo=<GMT1 object at 0x...>)
>>> gmt = GMT1()
>>> t.isoformat()
'12:10:30+01:00'
>>> t.dst()
datetime.timedelta(0)
>>> t.tzname()
'Europe/Prague'
>>> t.strftime("%H:%M:%S %Z")
'12:10:30 Europe/Prague'
>>> 'The {} is {:%H:%M}.'.format("time", t)
'The time is 12:10.'

8.1.6. tzinfo对象

class datetime.tzinfo

这是一个抽象的基类,意味着这个类不应该直接实例化。你需要派生一个具体的子类,并且(至少)提供你使用的datetime方法所需的标准tzinfo方法的实现。datetime模块提供tzinfo的一个简单的具体子类timezone,它可以表示与UTC有固定偏移的时区,如UTC本身或北美EST和EDT。

可以将tzinfo(的具体子类)的实例传递给datetimetime对象的构造函数。后面的对象将它们的属性视为在本地时间,并且tzinfo对象支持显示本地时间与UTC的偏移量、时区的名称和DST偏移量,所有这些都相对于传递给它们的日期或时间对象。

用于pickling的特殊要求:tzinfo子类必须有一个可以无参数调用的__init__()方法,否则它可以被pickled,但可能不能再次unpickled。这是一个在将来可能放松的技术要求。

tzinfo的具体子类可能需要实现以下方法。需要哪些方法取决于对aware的datetime对象的使用。如果有疑问,请实施所有这些。

tzinfo.utcoffset(dt)

返回本地时间与UTC的偏移量,以UTC东部分钟数为单位。如果本地时间在UTC的西边,它应该是负的。注意,这是UTC的总偏移量;例如,如果tzinfo对象同时表示时区和DST调整,则utcoffset()应返回它们的和。如果UTC偏移未知,则返回None否则返回的值必须是timedelta对象,指定-1439到1439范围内的整数分钟(1440 = 24*60;偏移量必须小于一天)。大多数utcoffset()的实现可能看起来像这两个:

return CONSTANT                 # fixed-offset class
return CONSTANT + self.dst(dt)  # daylight-aware class

如果utcoffset()不返回None,则dst()也不应返回None

默认实现的utcoffset()引发NotImplementedError

tzinfo.dst(dt)

如果DST信息未知,则返回夏令时(DST)调整(以UTC以东为单位),或者None如果DST不起作用,则返回timedelta(0)如果DST有效,则将偏移返回为timedelta对象(有关详细信息,请参阅utcoffset())。请注意,DST偏移(如果适用)已添加到utcoffset()返回的UTC偏移,因此除非你感兴趣,否则不需要单独查阅dst()获得DST信息。例如,datetime.timetuple()调用其tzinfo属性的dst()方法来确定tm_isdst应如何设置,并且tzinfo.fromutc()调用dst()来计算跨越时区的DST更改。

对标准时和夏令时同时进行建模的tzinfo子类的实例tz必须在此意义上保持一致:

tz.utcoffset(dt) - tz.dst(dt)

必须对每个datetime dt返回相同的结果dt.tzinfo == tz。对于正确的tzinfo子类,此表达式生成时区的“标准偏移量”,不应取决于日期或时间,而只取决于地理位置。datetime.astimezone()的实现依赖于此,但不能检测不符合规则的;它是程序员的责任来确保它。如果tzinfo子类不能保证这一点,它可以覆盖tzinfo.fromutc()的默认实现以与astimezone()正确工作。

大多数dst()的实现可能看起来像这两个:

def dst(self, dt):
    # a fixed-offset class:  doesn't account for DST
    return timedelta(0)

或者

def dst(self, dt):
    # Code to set dston and dstoff to the time zone's DST
    # transition times based on the input dt.year, and expressed
    # in standard local time.  Then

    if dston <= dt.replace(tzinfo=None) < dstoff:
        return timedelta(hours=1)
    else:
        return timedelta(0)

默认实现的dst()引发NotImplementedError

tzinfo.tzname(dt)

将与datetime对象dt对应的时区名称作为字符串返回。datetime模块没有定义有关字符串名称的内容,并且没有要求它有任何特别的意思。例如,“GMT”、“UTC”、“-500”、“-5:00”、“EDT”、“US/Eastern”、“America/New York”都是有效的返回。如果字符串名称未知,则返回None注意,这是一种方法而不是固定字符串,主要是因为一些tzinfo子类希望根据传递的dt的具体值返回不同的名称,特别是如果tzinfo类正在考虑夏令时。

默认实现的tzname()引发NotImplementedError

这些方法由datetimetime对象调用,以对应其相同名称的方法。datetime对象传递自身作为参数,time对象传递None作为参数。因此,tzinfo子类的方法应该准备接受一个为None或类datetimedt参数。

当传递的是None时,由类设计器决定最佳响应。例如,如果类想要说time对象不参与tzinfo协议,则返回None是适当的。对于utcoffset(None)返回标准UTC偏移可能更有用,因为没有发现标准偏移的其他约定。

datetime对象传递给datetime方法时,dt.tzinfoself是同一个对象 。tzinfo方法可以依赖于此,除非用户代码直接调用tzinfo方法。目的是tzinfo方法将dt解释为在本地时间,并且不需要担心其他时区中的对象。

还有一个子类可能希望覆盖的另一个tzinfo方法:

tzinfo.fromutc(dt)

这是从默认的datetime.astimezone()实现中调用的。当从中调用时,dt.tzinfoself,并且dt的日期和时间数据被视为表示UTC时间。fromutc()的目的是调整日期和时间数据,在self的本地时间返回等效的日期时间。

大多数tzinfo子类应该能够继承默认的fromutc()实现,而不会有问题。它足够强大以处理固定偏移的时区和既考虑标准时又考虑夏令时的时区,后者即使DST转换时间在不同年份有所不同。在所有情况下,默认fromutc()实现可能无法正确处理的时区示例是标准偏移量(来自UTC)取决于特定的日期和时间的时区,这可能发生于政治原因。如果结果是跨越标准偏移变化的时间之一,则astimezone()fromutc()的默认实现可能无法产生所需的结果。

跳过错误情况的代码,默认的fromutc()实现如下:

def fromutc(self, dt):
    # raise ValueError error if dt.tzinfo is not self
    dtoff = dt.utcoffset()
    dtdst = dt.dst()
    # raise ValueError if dtoff is None or dtdst is None
    delta = dtoff - dtdst  # this is self's standard offset
    if delta:
        dt += delta   # convert to standard local time
        dtdst = dt.dst()
        # raise ValueError if dtdst is None
    if dtdst:
        return dt + dtdst
    else:
        return dt

tzinfo类的示例:

from datetime import tzinfo, timedelta, datetime

ZERO = timedelta(0)
HOUR = timedelta(hours=1)

# A UTC class.

class UTC(tzinfo):
    """UTC"""

    def utcoffset(self, dt):
        return ZERO

    def tzname(self, dt):
        return "UTC"

    def dst(self, dt):
        return ZERO

utc = UTC()

# A class building tzinfo objects for fixed-offset time zones.
# Note that FixedOffset(0, "UTC") is a different way to build a
# UTC tzinfo object.

class FixedOffset(tzinfo):
    """Fixed offset in minutes east from UTC."""

    def __init__(self, offset, name):
        self.__offset = timedelta(minutes=offset)
        self.__name = name

    def utcoffset(self, dt):
        return self.__offset

    def tzname(self, dt):
        return self.__name

    def dst(self, dt):
        return ZERO

# A class capturing the platform's idea of local time.

import time as _time

STDOFFSET = timedelta(seconds = -_time.timezone)
if _time.daylight:
    DSTOFFSET = timedelta(seconds = -_time.altzone)
else:
    DSTOFFSET = STDOFFSET

DSTDIFF = DSTOFFSET - STDOFFSET

class LocalTimezone(tzinfo):

    def utcoffset(self, dt):
        if self._isdst(dt):
            return DSTOFFSET
        else:
            return STDOFFSET

    def dst(self, dt):
        if self._isdst(dt):
            return DSTDIFF
        else:
            return ZERO

    def tzname(self, dt):
        return _time.tzname[self._isdst(dt)]

    def _isdst(self, dt):
        tt = (dt.year, dt.month, dt.day,
              dt.hour, dt.minute, dt.second,
              dt.weekday(), 0, 0)
        stamp = _time.mktime(tt)
        tt = _time.localtime(stamp)
        return tt.tm_isdst > 0

Local = LocalTimezone()


# A complete implementation of current DST rules for major US time zones.

def first_sunday_on_or_after(dt):
    days_to_go = 6 - dt.weekday()
    if days_to_go:
        dt += timedelta(days_to_go)
    return dt


# US DST Rules
#
# This is a simplified (i.e., wrong for a few cases) set of rules for US
# DST start and end times. For a complete and up-to-date set of DST rules
# and timezone definitions, visit the Olson Database (or try pytz):
# http://www.twinsun.com/tz/tz-link.htm
# http://sourceforge.net/projects/pytz/ (might not be up-to-date)
#
# In the US, since 2007, DST starts at 2am (standard time) on the second
# Sunday in March, which is the first Sunday on or after Mar 8.
DSTSTART_2007 = datetime(1, 3, 8, 2)
# and ends at 2am (DST time; 1am standard time) on the first Sunday of Nov.
DSTEND_2007 = datetime(1, 11, 1, 1)
# From 1987 to 2006, DST used to start at 2am (standard time) on the first
# Sunday in April and to end at 2am (DST time; 1am standard time) on the last
# Sunday of October, which is the first Sunday on or after Oct 25.
DSTSTART_1987_2006 = datetime(1, 4, 1, 2)
DSTEND_1987_2006 = datetime(1, 10, 25, 1)
# From 1967 to 1986, DST used to start at 2am (standard time) on the last
# Sunday in April (the one on or after April 24) and to end at 2am (DST time;
# 1am standard time) on the last Sunday of October, which is the first Sunday
# on or after Oct 25.
DSTSTART_1967_1986 = datetime(1, 4, 24, 2)
DSTEND_1967_1986 = DSTEND_1987_2006

class USTimeZone(tzinfo):

    def __init__(self, hours, reprname, stdname, dstname):
        self.stdoffset = timedelta(hours=hours)
        self.reprname = reprname
        self.stdname = stdname
        self.dstname = dstname

    def __repr__(self):
        return self.reprname

    def tzname(self, dt):
        if self.dst(dt):
            return self.dstname
        else:
            return self.stdname

    def utcoffset(self, dt):
        return self.stdoffset + self.dst(dt)

    def dst(self, dt):
        if dt is None or dt.tzinfo is None:
            # An exception may be sensible here, in one or both cases.
            # It depends on how you want to treat them.  The default
            # fromutc() implementation (called by the default astimezone()
            # implementation) passes a datetime with dt.tzinfo is self.
            return ZERO
        assert dt.tzinfo is self

        # Find start and end times for US DST. For years before 1967, return
        # ZERO for no DST.
        if 2006 < dt.year:
            dststart, dstend = DSTSTART_2007, DSTEND_2007
        elif 1986 < dt.year < 2007:
            dststart, dstend = DSTSTART_1987_2006, DSTEND_1987_2006
        elif 1966 < dt.year < 1987:
            dststart, dstend = DSTSTART_1967_1986, DSTEND_1967_1986
        else:
            return ZERO

        start = first_sunday_on_or_after(dststart.replace(year=dt.year))
        end = first_sunday_on_or_after(dstend.replace(year=dt.year))

        # Can't compare naive to aware objects, so strip the timezone from
        # dt first.
        if start <= dt.replace(tzinfo=None) < end:
            return HOUR
        else:
            return ZERO

Eastern  = USTimeZone(-5, "Eastern",  "EST", "EDT")
Central  = USTimeZone(-6, "Central",  "CST", "CDT")
Mountain = USTimeZone(-7, "Mountain", "MST", "MDT")
Pacific  = USTimeZone(-8, "Pacific",  "PST", "PDT")

请注意,在DST转换点,在标准时和夏令时都考虑的tzinfo子类中,每年有两次不可避免的微妙。具体来说,考虑美国东部(UTC-0500),其中EDT在3月第二个星期日1:59(EST)之后开始,并在11月第一个星期日1:59(EDT)后结束。

  UTC   3:MM  4:MM  5:MM  6:MM  7:MM  8:MM
  EST  22:MM 23:MM  0:MM  1:MM  2:MM  3:MM
  EDT  23:MM  0:MM  1:MM  2:MM  3:MM  4:MM

start  22:MM 23:MM  0:MM  1:MM  3:MM  4:MM

  end  23:MM  0:MM  1:MM  1:MM  2:MM  3:MM

当DST开始(“start行)时,本地挂钟从1:59走到3:00。格式2:MM的挂钟时间在当天没有任何意义,因此在DST开始的时候,astimezone(Eastern)不会产生结果hour == 2为了使astimezone()作出此保证,tzinfo.dst()方法必须考虑在夏令时“缺少的小时”(东部时间2:MM)。

当DST结束(“end”行)时,有一个可能更糟糕的问题:有一个小时不能在本地墙上时间明确拼写:白天的最后一个小时。在东部,这是在日间时间结束时5:MM UTC形式的间。本地挂钟再次从1:59(白昼时间)回到1:00(标准时间)。表格1:MM的当地时间不明确。astimezone()模拟本地时钟的行为,通过将两个相邻的UTC小时映射到相同的当地小时。在Eastern这个示例中,5:MM形式和6:MM形式的UTC时间在转换到Eastern时都映射到1:MM。为了使astimezone()作出此保证,tzinfo.dst()方法必须将“重复小时”中的时间考虑为标准时间。通过在时区的标准本地时间中表示DST切换时间,这可以容易地做到,如在该示例中。

不能承受这种歧义的应用程序应避免使用混合tzinfo子类;使用timezone或任何其他固定偏移的tzinfo子类(例如只表示EST(固定偏移-5小时)或只表示ED(T固定偏移-4小时)的类)。

也可以看看

pytz

标准库有timezone类来处理UTC任意固定偏移和timezone.utc作为UTC时区实例。

pytz库将IANA时区数据库(也称为Olson数据库)带到Python,建议使用它。

IANA timezone database
时区数据库(通常称为tz或zoneinfo)包含代表世界各地许多代表性位置的本地时间历史的代码和数据。它定期更新,以反映政治机构对时区边界、UTC偏移和夏令时规则所做的更改。

8.1.7. timezone对象

timezone类是tzinfo的子类,其每个实例表示由与UTC的固定偏移量定义的时区。请注意,此类的对象不能用于在一年中不同日期使用不同偏移量的位置,或者对民用时间进行历史更改的位置来表示时区信息。

class datetime.timezone(offset[, name])

offset参数必须指定为表示本地时间和UTC之间差异的timedelta对象。它必须严格在-timedelta(hours=24)timedelta(hours=24)之间并表示整分钟数,否则引发ValueError

name参数是可选的。如果指定,它必须是用作tzname(dt)方法返回的值的字符串。否则,tzname(dt)返回字符串'UTCsHH:MM',其中s是offset的符号,HH和MM分别是offset.hoursoffset.minutes

版本3.2中的新功能。

timezone.utcoffset(dt)

返回构建timezone实例时指定的固定值。忽略dt参数。返回值是等于本地时间和UTC之差的timedelta实例。

timezone.tzname(dt)

返回在构建timezone实例时指定的固定值或字符串'UTCsHH:MM',其中s是offset的符号,HH和MM分别是offset.hoursoffset.minutes

timezone.dst(dt)

始终返回None

timezone.fromutc(dt)

返回dt + offsetdt参数必须是一个aware的datetime实例,其中tzinfo设置为self

类属性:

timezone.utc

UTC时区,timezone(timedelta(0))

8.1.8. strftime()strptime()的行为

datedatetimetime对象都支持strftime(format)方法,在显式格式字符串的控制下创建一个表示时间的字符串。广义上,d.strftime(fmt)的行为类似于time模块的time.strftime(fmt, d.timetuple()),但并非所有对象都支持timetuple()方法。

相反,datetime.strptime()类方法从表示日期和时间的字符串和相应的格式字符串创建一个datetime对象。datetime.strptime(date_string, format)等同于datetime(*(time.strptime(date_string, format)[0:6]))

对于time对象,不应使用年、月和日的格式代码,因为时间对象没有此类值。如果仍然使用它们,则用1900代替年份,1代替月份和日期。

对于date对象,不应使用小时、分钟、秒和微秒的格式代码,因为date对象没有此类值。如果仍然使用它们,则用0代替它们。

支持的全套格式代码因平台而异,因为Python调用平台C库的strftime()函数,平台的变化是常见的。要查看平台上支持的全套格式代码,请参阅strftime(3)文档。

以下是C标准(1989版本)要求的所有格式代码的列表,并且这些代码可以在所有平台上使用标准的C实现。请注意,1999版本的C标准添加了额外的格式代码。

指示含义笔记
%a星期几作为区域设置的缩写名称。
Sun, Mon, ..., Sat (en_US);
So, Mo, ..., Sa (de_DE)
(1)
%a星期几作为区域的全名。
Sunday, Monday, ..., Saturday (en_US);
Sonntag, Montag, ..., Samstag (de_DE)
(1)
%w星期几为十进制数字,其中0表示星期日,6表示星期六。0, 1, ..., 6
%d一个月中的一天作为零填充的十进制数字。01, 02, ..., 31
%b月为区域设置的缩写名称。
Jan,Feb,...,Dec(en_US);
Jan,Feb,...,Dez(de_DE)
(1)
%b月作为区域的全名。
January, February, ..., December (en_US);
Januar,Februar,...,Dezember(de_DE)
(1)
%m月份作为零填充十进制数字。01, 02, ..., 12
%y没有世纪的一年是一个零填充的十进制数。00, 01, ..., 99
%y年份以世纪为十进制数。0001, 0002, ..., 2013, 2014, ..., 9998, 9999(2)
%H小时(24小时制)作为零填充十进制数字。00, 01, ..., 23
%I小时(12小时制)作为零填充的十进制数字。01, 02, ..., 12
%pLocale相当于AM或PM。
AM, PM (en_US);
am, pm (de_DE)
(1),(3)
%m分为零填充十进制数字。00,01,...,59
%S其次作为零填充十进制数。00,01,...,59(4)
%f微秒为十进制数字,左侧为零填充。000000,000001,...,999999(5)
%z+HHMM或-HHMM形式的UTC偏移(如果对象是naive的,则为空字符串)。(empty), +0000, -0400, +1030(6)
%z时区名称(如果对象天真,则为空字符串)。(empty), UTC, EST, CST
%j一年中的一天为零填充的十进制数字。001,002,...,366
%U一年中的星期数(星期日为一周的第一天)作为零填充十进制数。在第一个星期日之前的新的一年的所有天被认为是在第0周。00,01,...,53(7)
%w一年中的星期数(星期一作为一周中的第一天)作为十进制数。在第一个星期一之前的新的一年中的所有天被认为是在第0周。00,01,...,53(7)
%c语言环境的适当日期和时间表示。
星期二8月16日21:30:00 1988(en_US);
Di 8月16日21:30:00 1988(de_DE)
(1)
%x语言环境的适当日期表示。
08/16/88(None);
08/16/1988(en_US);
16.08.1988(de_DE)
(1)
%x语言环境的适当时间表示。
21:30:00(en_US);
21:30:00(de_DE)
(1)
%%字面值'%'字符。%

笔记:

  1. 因为格式取决于当前的区域设置,在做出关于输出值的假设时应该小心。字段顺序将有所不同(例如,“月/日/年”和“日/月/年”),输出可能包含使用区域设置的默认编码进行编码的Unicode字符(例如,如果当前区域设置为ja_JP,默认编码可以是eucJPSJISutf-8中的任何一个;使用locale.getlocale()以确定当前区域设置的编码)。

  2. strptime()方法可以解析完整稍微[1,9999]范围内的年份,但 < 1000的年份必须使用0填充到4位数。

    在版本3.2中更改:在以前的版本中,strftime()方法仅限于>= 1900的年份。

    在版本3.3中更改:在版本3.2中,strftime()方法仅限于>= 1000的年份。

  3. 当与strptime()方法一起使用时,只有在使用%I指令解析小时的时候,%p指令才会影响输出。

  4. time模块不同,datetime模块不支持闰秒。

  5. 当与strptime()方法一起使用时,%f指令接受一到六个数字,并在右边以零填充。%f是C标准中的一组格式字符的扩展(但是在datetime对象中单独实现,因此始终可用)。

  6. 对于naive对象,%z%Z格式代码将替换为空字符串。

    对于aware对象:

    %z

    utcoffset()被转换为+HHMM或-HHMM形式的5个字符的字符串,其中HH是给出UTC偏移小时数的2位字符串,MM是给出UTC偏移分钟数的2位字符串。例如,如果utcoffset()返回timedelta(hours=-3, minutes=-30),那么%z 替换为字符串'-0330'

    %z

    如果tzname()返回None,则以空字符串替换%Z否则,%Z被替换为返回值,它必须是字符串。

    在版本3.2中更改:当向strptime()方法提供%z指令时,将产生aware的datetime对象。结果的tzinfo将设置为一个timezone实例。

  7. strptime()方法一起使用时,%U%W仅在指定星期和年份时使用。

脚注

[1]如果,也就是说,我们忽略相对论的影响