time_datetime常用总结

因为这周在工作上处理时间戳和datetime转换时发了一些时间,所以,现在就整理下python的三个模块:time,datetime,calendar,以及时间之间的一些转换

目录

time

首先,这个模块表示时间的格式是: struct_time, 是一种时间值序列,可以通过索引和属性名访问,具体有以下几个值:

Index Attribute Values
0 tm_year (for example, 1993)
1 tm_mon range [1, 12]
2 tm_mday range [1, 31]
3 tm_hour range [0, 23]
4 tm_min range [0, 59]
5 tm_sec range [0, 61]; see (2) in strftime() description
6 tm_wday range [0, 6], Monday is 0
7 tm_yday range [1, 366]
8 tm_isdst 0, 1 or -1; see below
In [41]: struct_time = time.localtime()

In [42]: struct_time
Out[42]: time.struct_time(tm_year=2016, tm_mon=4, tm_mday=24, tm_hour=15, tm_min=6, tm_sec=11, tm_wday=6, tm_yday=115, tm_isdst=0)

In [43]: struct_time.tm_year
Out[43]: 2016

In [44]: struct_time[0]
Out[44]: 2016

struct_time -> 24个字符的字符串

In [50]: time.asctime()
Out[50]: 'Sun Apr 24 15:27:22 2016'

In [51]: time.asctime(struct_time)
Out[51]: 'Sun Apr 24 15:06:11 2016'

time.asctime 没有使用区域信息

时间戳 -> UTC 的struct_time

In [52]: time.gmtime()
Out[52]: time.struct_time(tm_year=2016, tm_mon=4, tm_mday=24, tm_hour=7, tm_min=30, tm_sec=9, tm_wday=6, tm_yday=115, tm_isdst=0)

In [53]: time_epoch = time.time()

In [54]: time_epoch
Out[54]: 1461483076.695493

In [55]: time.gmtime(time_epoch)
Out[55]: time.struct_time(tm_year=2016, tm_mon=4, tm_mday=24, tm_hour=7, tm_min=31, tm_sec=16, tm_wday=6, tm_yday=115, tm_isdst=0)

注意这个是返回UTC的struct_time

时间戳 -> 本地的struct_time

In [56]: time.localtime()
Out[56]: time.struct_time(tm_year=2016, tm_mon=4, tm_mday=24, tm_hour=15, tm_min=33, tm_sec=26, tm_wday=6, tm_yday=115, tm_isdst=0)

In [57]: time.localtime(time_epoch)
Out[57]: time.struct_time(tm_year=2016, tm_mon=4, tm_mday=24, tm_hour=15, tm_min=31, tm_sec=16, tm_wday=6, tm_yday=115, tm_isdst=0)

本地的struct_time -> 时间戳

In [60]: struct_time
Out[60]: time.struct_time(tm_year=2016, tm_mon=4, tm_mday=24, tm_hour=15, tm_min=6, tm_sec=11, tm_wday=6, tm_yday=115, tm_isdst=0)

In [61]: time.mktime(struct_time)
Out[61]: 1461481571.0

这个和time.localtime相反,而且这个参数是必填的

struct_time -> 由参数format指定的字符串

In [64]: time.strftime("%y-%m-%d %H:%M:%S %Z", struct_time)
Out[64]: '16-04-24 15:06:11 CST'

In [65]: time.strftime("%y-%m-%d %H:%M:%S %Z")
Out[65]: '16-04-24 15:51:23 CST'

如果没有提供t,则使用localtime() 返回的当前时间。具体format格式,参考文档

由参数format指定的字符串 -> struct_time

In [67]: time.strptime("16-04-24 15:51:23 CST", "%y-%m-%d %H:%M:%S %Z")
Out[67]: time.struct_time(tm_year=2016, tm_mon=4, tm_mday=24, tm_hour=15, tm_min=51, tm_sec=23, tm_wday=6, tm_yday=115, tm_isdst=0)

获取当前时间戳,struct_time

In [69]: time.time()
Out[69]: 1461484592.934382

In [70]: time.localtime()
Out[70]: time.struct_time(tm_year=2016, tm_mon=4, tm_mday=24, tm_hour=15, tm_min=56, tm_sec=36, tm_wday=6, tm_yday=115, tm_isdst=0)

时区

In [72]: time.timezone
Out[72]: -28800

In [73]: time.tzname
Out[73]: ('CST', 'CST')

In [74]: time.altzone
Out[74]: -28800

当前时区是根据环境变量TZ获得的,如果没有这个变量,则根据系统的时区信息

这里的-28800是UTC时间到当地时区相差的秒数,格林威治时间以东为负,西为正,英国为零

altzone是夏令时的相关的偏移:

如果被定义,在UTC西部的地区,当地的DST时区在短时间内会有所偏差。如果当地的DST时区在UTC的东部(例如西欧,包括英国),该值为负数。只有在daylight 非零时才使用。 我这里的地方没有夏令时,所以这个值和timezone一样

tips

time.accept2dyear接受两个数字的年份,还是别装逼吧,写4个字的年份很清晰

The functions in this module do not handle dates and times before the epoch or far in the future. The cut-off point in the future is determined by the C library; for Unix, it is typically in 2038. 这个模块处理的时间只能是:1970 ~ 2038

time.clock()的使用

Python time clock() 函数以浮点数计算的秒数返回当前的CPU时间。用来衡量不同程序的耗时,比time.time()更有用。 这个需要注意,在不同的系统上含义不同。在UNIX系统上,它返回的是"进程时间",它是用秒表示的浮点数(时间戳)。而在WINDOWS中,第一次调用,返回的是进程运行的实际时间。而第二次之后的调用是自第一次调用以后到现在的运行时间。(实际上是以WIN32上QueryPerformanceCounter()为基础,它比毫秒表示更为精确)

datetime

首先说明一下,datetime表示时间有两种类型:naive和aware。aware类型包含时区信息,它确定的时间是独一无二的;而naive没有明确的时区信息,它确定时间完全取决于程序。

获取当前时间(本地、UTC)

In [166]: berlin_tz = pytz.timezone("Europe/Berlin")

In [169]: datetime.now()
Out[169]: datetime.datetime(2016, 4, 24, 21, 38, 51, 52918)

In [170]: datetime.now(berlin_tz)
Out[170]: datetime.datetime(2016, 4, 24, 15, 38, 55, 209865, tzinfo=<DstTzInfo 'Europe/Berlin' CEST+2:00:00 DST>)

In [171]: datetime.utcnow()
Out[171]: datetime.datetime(2016, 4, 24, 13, 39, 29, 931381)

时间戳 -> datetime

In [172]: cur_time = time.time()

In [173]: cur_time
Out[173]: 1461505226.052115

In [174]: datetime.fromtimestamp(cur_time)
Out[174]: datetime.datetime(2016, 4, 24, 21, 40, 26, 52115)

In [175]: datetime.fromtimestamp(cur_time, berlin_tz)
Out[175]: datetime.datetime(2016, 4, 24, 15, 40, 26, 52115, tzinfo=<DstTzInfo 'Europe/Berlin' CEST+2:00:00 DST>)

In [176]: datetime.fromtimestamp(cur_time, pytz.utc)
Out[176]: datetime.datetime(2016, 4, 24, 13, 40, 26, 52115, tzinfo=<UTC>)

In [177]: datetime.utcfromtimestamp(cur_time)
Out[177]: datetime.datetime(2016, 4, 24, 13, 40, 26, 52115)

如果fromtimestamp不带时区参数的话,转换成本地时间一个naive类型的datetime对象

datetime -> 由参数format指定的字符串

In [185]: dt
Out[185]: datetime.datetime(2016, 4, 24, 17, 50, 46, 204551, tzinfo=<DstTzInfo 'Asia/Shanghai' CST+8:00:00 STD>)

In [186]: dt.st
dt.strftime  dt.strptime

In [186]: dt.strftime("%Y-%m-%dT%H:%M:%SZ%Z")
Out[186]: '2016-04-24T17:50:46ZCST'

由参数format指定的字符串 -> datetime

In [187]: datetime.strptime('2016-04-24T17:50:46ZCST', '%Y-%m-%dT%H:%M:%SZ%Z')
Out[187]: datetime.datetime(2016, 4, 24, 17, 50, 46)

返回的datetime是一个naive类型,没有时区信息,最好设置时区信息

设置datetime,返回新的datetime

In [189]: dt.day
Out[189]: 24

In [190]: dt.replace(day=23)
Out[190]: datetime.datetime(2016, 4, 23, 17, 50, 46, 204551, tzinfo=<DstTzInfo 'Asia/Shanghai' CST+8:00:00 STD>)

时区相关

In [192]: dt.utcoffset()  # utc时间差
Out[192]: datetime.timedelta(0, 28800)

In [193]: datetime.now().utcoffset()

In [194]: datetime.now().dst()  # 夏令时和标准时间时差

In [195]: datetime.now(berlin_tz).dst()
Out[195]: datetime.timedelta(0, 3600)

In [196]: datetime.now(berlin_tz).tzname()
Out[196]: 'CEST'

datetime -> struct_time

Out[199]: time.struct_time(tm_year=2016, tm_mon=4, tm_mday=24, tm_hour=9, tm_min=50, tm_sec=46, tm_wday=6, tm_yday=115, tm_isdst=0)

In [200]: datetime.now(berlin_tz).timetuple()
Out[200]: time.struct_time(tm_year=2016, tm_mon=4, tm_mday=24, tm_hour=16, tm_min=3, tm_sec=9, tm_wday=6, tm_yday=115, tm_isdst=1)

In [201]: datetime.now(berlin_tz).utctimetuple()
Out[201]: time.struct_time(tm_year=2016, tm_mon=4, tm_mday=24, tm_hour=14, tm_min=3, tm_sec=14, tm_wday=6, tm_yday=115, tm_isdst=0)

In [202]: datetime.now(berlin_tz)
Out[202]: datetime.datetime(2016, 4, 24, 16, 3, 22, 698077, tzinfo=<DstTzInfo 'Europe/Berlin' CEST+2:00:00 DST>)

一个是本地时间的struct_time, 一个是utc时间的sturct_time

datetime获取星期几

In [203]: dt.weekday()
Out[203]: 6

In [204]: dt.isoweekday()
Out[204]: 7

isoweekday()是从1-7的值,分别代表星期一 ~ 星期日

datetime -> ISO 8601 格式的时间字符串

In [205]: dt.isoformat()
Out[205]: '2016-04-24T17:50:46.204551+08:00'

tips

datetime 由 date 和 time 组成

date 类型的对象永远是 naive 的。 # 因为时区信息在time中

time 或datetime 类型的对象既可能是 naive 的也可能是 aware 的。取决于tzinfo的值是否为None

calendar

calendar模块目前也没怎么用过,所以先简单说说下面有用的部分吧。

struct_time -> 时间戳

In [208]: timegm((2016,4,24,14,3,14,6,115,0))
Out[208]: 1461506594

In [209]: datetime.fromtimestamp(1461506594)
Out[209]: datetime.datetime(2016, 4, 24, 22, 3, 14)

In [210]: comments.utcfromtimestamp(1461506594)
Out[210]: datetime.datetime(2016, 4, 24, 14, 3, 14)

由于struct_time本身是没有时区特性的,转换成时间戳的时候,把那个struct_time时间元组序列的值都当成utc时间转换。

所以,使用时间戳转换成对应的datetime的时候,必须使用utcfromtimestamp(),而不是fromtimestamp。

时间转换

From To Use
时间戳 utc struct_time gmtime()
时间戳 local struct_time localtime()
utc struct_time 时间戳 calendar.timegm()
local struct_time 时间戳 mktime()
datetime 时间戳 utctimetuple() -> calendar.timegm()
时间戳 datetime fromtimestamp(), utcfromtimestamp()
2016-07-28修正

以上的时间戳和datetime转换time_struct等都没考虑毫秒的情况,因为time_struct本身没有毫秒字段,所以在转换的过程中,肯定是忽略毫秒部分的

如果需要保留,则需要自己手动操作:

  • datetime -> timestamp

    1. 先记下microsecond字段值
    2. 转换成小数(如65 -> 0.65)
    3. 将结果时间戳加上这个小数
  • timestamp -> datetime

    1. 先转成整数时间和小数时间
    2. 整数直接转换,小数乘以对应位数获得整数值
    3. 结果replace microsecond字段值