datetime模块

简单的日期时间操作用time模块里面的一些函数即可,datetime模块是用类的方式来处理的,适合大量处理日期时间的任务。然后值得一提的是mongodb的python接口 pymongo 里面(连接mongodb的python第三方模块),日期时间的输入输出都是datetime 对象的,这很是方便。

下面简要介绍之,更多内容请参看 官方文档

timedelta对象

通过timedelta函数返回一个timedelta对象,也就是一个表示时间间隔的对象。函数参数情况如下所示:

class datetime.timedelta([days[, seconds[, microseconds[, milliseconds[, minutes[, hours[, weeks]]]]]]])

其没有必填参数,简单控制的话第一个整数就是多少天的间隔的意思:

datetime.timedelta(10)

两个时间间隔对象可以彼此之间相加或相减,返回的仍是一个时间间隔对象。而更方便的是一个datetime对象如果减去一个时间间隔对象,那么返回的对应减去之后的datetime对象,然后两个datetime对象如果相减返回的是一个时间间隔对象。这很是方便。

datetime对象

通过datetime函数可以创建一个datetime对象:

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

其中year,month和day是必填参数。下面是一个简单的例子:

>>> db_t = {
...  "date": datetime.datetime(1777,07,07)
... }
>>> db_t
{'date': datetime.datetime(1777, 7, 7, 0, 0)}

其通过pymongo存入mongodb之后是这样的形式:

ISODate("1777-07-07T00:00:00.000Z")

now和utcnow方法

datetime对象有 nowutcnow 这两个类方法(classmethod)来返回当前日期时间的datetime对象。utcnow不可以接受参数,now方法可以接受一个tz指定时区的参数,我们可以通过 pytz 模块(一个处理时区推荐的第三方模块)来具体指明某个时区。

查看pytz的所有时区

参看这个网页

>>> pytz.all_timezones
['Africa/Abidjan', 'Africa/Accra', 'Africa/Addis_Ababa', 'Africa/Algiers', ......
具体给now方法指定一个时区

参看这个网页

import pytz
datetime.datetime.now(tz = pytz.timezone("Asia/Hong_Kong"))
now方法和utcnow方法区别

我们看下面这个例子:

>>> datetime.now(tz = pytz.timezone("UTC")),datetime.utcnow()
(datetime.datetime(2015, 7, 11, 9, 25, 20, 266863, tzinfo=<UTC>), datetime.datetime(2015, 7, 11, 9, 25, 20, 266888))

如果我们给now方法指定默认的时区是\"UTC\",那么我们看到其返回的datetime对象和utcnow返回的datetime对象基本上没什么区别,后面的微秒($10^{-6}$秒)有点区别完全可以理解。然后我们再看now方法如果不加任何参数会如何:

>>> now
datetime.datetime(2015, 7, 11, 16, 34, 43, 144018)
>>> utcnow
datetime.datetime(2015, 7, 11, 8, 34, 56, 319108)

这里now显示的时间和本地的时间是一致的,说明now默认的时区是本地的时区参数。谈到这里大家应该就明白了,如果是后台数据库有日期时间输入需求,为了保持时间戳的一致性,推荐都使用utcnow方法来生成时间戳,也就是实际上都以UTC格林威治时区为准。如果到前端需要显示给用户具体的日期时间了,如果要引用前端数据库的日期时间,才需要引入时区的考虑进行必要的转换。然后如果前端需要用python生成实时的时间,那么就用now方法再引入pytz的时区控制。

datetime对象的属性

>>> from datetime import datetime
>>> d = datetime.now()
>>> d.year
2015
>>> d.month
11
>>> d.day
3
>>> d.hour
18
>>> d.minute
42
>>> d.second
57
>>> d.tzinfo
>>> d
datetime.datetime(2015, 11, 3, 18, 42, 57, 919613)

具体含义如下所示:

year

month

day

hour

minute

second

microsecond

微秒

strftime方法

datetime对象可以如下调用 strftime 方法或者 __format__ 方法来得到一个好看的你想要的日期时间字符串格式:

    >>> from datetime import datetime
    >>> d = datetime.now()
    >>> d.strftime('%T')
    '18:52:39'
    >>> d.__format__('%F')
    '2015-11-03'

这里的格式符号python官方文档有所述及,而更实际上是和linux系统下的 date 命令的格式符一致的,读者可以用 date --help 来看一下,就可以看到如下信息:

    %%      一个文字的 %
    %a      当前locale 的星期名缩写(例如: 日,代表星期日)
    %A      当前locale 的星期名全称 (如:星期日)
    %b      当前locale 的月名缩写 (如:一,代表一月)
    %B      当前locale 的月名全称 (如:一月)
    %c      当前locale 的日期和时间 (如:2005年3月3日 星期四 23:05:25)
    %C      世纪;比如 %Y,通常为省略当前年份的后两位数字(例如:20)
    %d      按月计的日期(例如:01)
    %D      按月计的日期;等于%m/%d/%y
    %e      按月计的日期,添加空格,等于%_d
    %F      完整日期格式,等价于 %Y-%m-%d
    %g      ISO-8601 格式年份的最后两位 (参见%G)
    %G      ISO-8601 格式年份 (参见%V),一般只和 %V 结合使用
    %h      等于%b
    %H      小时(00-23)
    %I      小时(00-12)
    %j      按年计的日期(001-366)
    %k   hour, space padded ( 0..23); same as %_H
    %l   hour, space padded ( 1..12); same as %_I
    %m   month (01..12)
    %M   minute (00..59)
    %n      换行
    %N      纳秒(000000000-999999999)
    %p      当前locale 下的"上午"或者"下午",未知时输出为空
    %P      与%p 类似,但是输出小写字母
    %r      当前locale 下的 12 小时时钟时间 (如:11:11:04 下午)
    %R      24 小时时间的时和分,等价于 %H:%M
    %s      自UTC 时间 1970-01-01 00:00:00 以来所经过的秒数
    %S      秒(00-60)
    %t      输出制表符 Tab
    %T      时间,等于%H:%M:%S
    %u      星期,1 代表星期一
    %U      一年中的第几周,以周日为每星期第一天(00-53)
    %V      ISO-8601 格式规范下的一年中第几周,以周一为每星期第一天(01-53)
    %w      一星期中的第几日(0-6),0 代表周一
    %W      一年中的第几周,以周一为每星期第一天(00-53)
    %x      当前locale 下的日期描述 (如:12/31/99)
    %X      当前locale 下的时间描述 (如:23:13:48)
    %y      年份最后两位数位 (00-99)
    %Y      年份
    %z +hhmm                数字时区(例如,-0400)
    %:z +hh:mm              数字时区(例如,-04:00)
    %::z +hh:mm:ss  数字时区(例如,-04:00:00)
    %:::z                   数字时区带有必要的精度 (例如,-04,+05:30)
    %Z                      按字母表排序的时区缩写 (例如,EDT)

其中的 %F%T 在python官方文档中并无说明,可见其内部API是和这个 date 命令一致的。

支持的时间间隔运算

前面提到了一个datetime对象减去一个timedelta对象返回一个datetime对象,然后一个datetime对象减去一个datetime对象返回一个时间间隔对象。比如此时之前一年的时间可以这样表达 datetime.datetime.utcnow() - datetime.timedelta(365) 。然后此时和爱因斯坦的生日时间间隔可以这样表达:

datetime.datetime.utcnow() - datetime.datetime(1879,03,14)

然后我们可以利用这个时间间隔来进行一些操作和判断。

    >>> delta = datetime.datetime.utcnow() - datetime.datetime(1879,03,14)
    >>> delta
    datetime.timedelta(49792, 35970, 903285)
    >>> delta > datetime.timedelta(120*365)
    True
    >>> delta.days // 365
    136

`struct_time`` 对象转化成为 datetime 对象

参看这个网页

from time import mktime

mktime函数接受time模块的 struct_time object,其可以来自time模块的 gmtimelocaltimestrptime 这些函数,mktime函数将返回一个时间戳,然后用datetime模块的 fromtimestamp 函数可以接受这个时间戳。

总的过程即:

from time import mktime
from datetime import datetime

dt = datetime.fromtimestamp(mktime(struct))

datetime 对象转化为 `time_struct`` 对象

参考了 这个网页

>>> t = datetime.datetime.now()
>>> t
datetime.datetime(2011, 11, 5, 11, 26, 15, 37496)

>>> time.mktime(t.timetuple()) + t.microsecond / 1E6
1320517575.037496

获取一个月最后的一天

首先要说的是利用python的datetime和timedelta对于 days 的加减操作是能够很好地支持跨月问题的:

    >>> from datetime import datetime
    >>> d = datetime.now()
    >>> d
    datetime.datetime(2016, 5, 29, 8, 50, 20, 337204)
    >>> from datetime import timedelta
    >>> d - timedelta(days = 29)
    datetime.datetime(2016, 4, 30, 8, 50, 20, 337204)
    >>> d - timedelta(days = 28)
    datetime.datetime(2016, 5, 1, 8, 50, 20, 337204)

但是有的时候你就是需要直接获知某个月份的最后一天是30还是31等等,然后利用replace来获得一个月的最后一天。这个时候你需要利用 calendar 的 monthrange 函数。参考了 这个网页

    >>> d.replace(year = 2016,month=4,day = monthrange(2016,4)[-1])
    datetime.datetime(2016, 4, 30, 8, 50, 20, 337204)