数字日期和时间

标签: python


5.12 基本的日期与时间转换

5.12.1 问题

你需要执行简单的时间转换,比如天到秒,小时到分钟等的转换。

5.12.2 解决方案

为了执行不同时间单位的转换和计算,请使用 datetime 模块。比如,为了表示一个时间段,可以创建一个 timedelta 实例,就像下面这样:

>>> from datetime import timedelta
>>> 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
>>>

如果你想表示指定的日期和时间,先创建一个 datetime 实例然后使用标准的数学运算来操作它们。比如:

>>> 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
>>>

在计算的时候,需要注意的是 datetime 会自动处理闰年。比如:

>>> 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
1
>>>

5.12.3 讨论

对大多数基本的日期和时间处理问题, datetime 模块以及足够了。如果你需要执行更加复杂的日期操作,比如处理时区,模糊时间范围,节假日计算等等,可以考虑使用 dateutil 模块
许多类似的时间计算可以使用 dateutil.relativedelta() 函数代替。但是,有一点需要注意的就是,它会在处理月份 (还有它们的天数差距) 的时候填充间隙。看例子最清楚

>>> 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
>>>

5.13 计算最后一个周五的日期

5.13.1 问题

你需要查找星期中某一天最后出现的日期,比如星期五。

5.13.2 解决方案

Python 的 datetime 模块中有工具函数和类可以帮助你执行这样的计算。下面是对类似这样的问题的一个通用解决方案:

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
Topic: 最后的周五
Desc :
"""

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 - timedelta(days=days_ago)
return target_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)
>>> get_previous_byday('Friday')
datetime.datetime(2012, 8, 24, 22, 5, 9, 911393)
>>>

可选的 start date 参数可以由另外一个 datetime 实例来提供。比如:

>>> get_previous_byday('Sunday', datetime(2012, 12, 21))
datetime.datetime(2012, 12, 16, 0, 0)
>>>

5.13.3 讨论

上面的算法原理是这样的:先将开始日期和目标日期映射到星期数组的位置上 (星期一索引为 0),然后通过模运算计算出目标日期要经过多少天才能到达开始日期。然后用开始日期减去那个时间差即得到结果日期。

如果你要像这样执行大量的日期计算的话,你最好安装第三方包 python-dateutil来代替。比如,下面是是使用 dateutil 模块中的 relativedelta() 函数执行同样的计算:

>>> 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
>>>

5.14 计算当前月份的日期范围

5.14.1 问题

你的代码需要在当前月份中循环每一天,想找到一个计算这个日期范围的高效方法。

5.14.2 解决方案

在这样的日期上循环并需要事先构造一个包含所有日期的列表。你可以先计算出开始日期和结束日期,然后在你步进的时候使用 datetime.timedelta 对象递增这个日期变量即可。

下面是一个接受任意 datetime对象并返回一个由当前月份开始日和下个月开始日组成的元组对象。

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
2012-08-06
2012-08-07
2012-08-08
2012-08-09
#... and so on...

5.15 字符串转换为日期

5.15.1 问题

你的应用程序接受字符串格式的输入,但是你想将它们转换为 datetime 对象以便在上面执行非字符串操作。

5.15.2 解决方案

使用 Python 的标准模块 datetime 可以很容易的解决这个问题。比如:

>>> 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)
>>>

汇总

>>> t1=[2010,11,9,19,20,30] #2010年11月9日 19:30:30
>>> last_time=datetime.datetime(t1[0],t1[1],t1[2].t1[3],t1[4],t1[5]) #上次更新时间
>>> now_time = datetime.datetime.now() #当前时间
>>> #以下是亮点
>>> mkt_last = time.mktime(last_time.timetuple())
>>> mkt_now = time.mktime(now_time.timetuple())
>>> delt_time = (mkt_now-mkt_last)/60 #转成分钟
>>> if (delt_time -30) > 0 :
>>> print "超过30分钟没有更新啦!"
这是我在解决问题时,发现的其他一些有用的函数

计算两个时间的差,如两个时间相差几天,几小时等

  • 1.计算两个日期相差天数的计算

    >>> import datetime
    >>> d1 = datetime.datetime(2005, 2, 16)
    >>> d2 = datetime.datetime(2004, 12, 31)
    >>> (d1 - d2).days
    输出结果:47
  • 2.计算两个时间相差的秒数

    >>> import datetime
    >>> starttime = datetime.datetime.now()
    >>> #long running
    >>> endtime = datetime.datetime.now()
    >>> print (endtime - starttime).seconds
  • 3.计算当前时间向后10小时的时间

    >>> d1 = datetime.datetime.now()
    >>> d3 = d1 + datetime.timedelta(hours=10)
    >>> d3.ctime()

对时间的操作,其本上常用的类有:datetime和timedelta两个。它们之间可以相互加减。每个类都有一些方法和属性可以查看具体的值,如datetime可以查看:天数(day),小时数(hour),星期几(weekday())等;timedelta可以查看:天数(days),秒数(seconds)等。

  • 4.日期的操作必须使用time或datetime库

    import time 
    >>> s="2006-1-2"
    >>> time.strptime(s,"%Y-%m-%d)
    这是将字符串格式的日期及时间转成日期对象
    转义符对应意义如下
    %a 本地简化星期名称
    %A 本地完整星期名称
    %b 本地简化的月份名称
    %B 本地完整的月份名称
    %c 本地相应的日期表示和时间表示
    %d 月内中的一天(0-31)
    %H 24小时制小时数(0-23)
    %I 12小时制小时数(01-12)
    %j 年内的一天(001-366)
    %m 月份(01-12)
    %M 分钟数(00=59)
    %p 本地A.M.或P.M.的等价符
    %S 秒(00-59)
    %U 一年中的星期数(00-53)星期天为星期的开始
    %w 星期(0-6),星期天为星期的开始
    %W 一年中的星期数(00-53)星期一为星期的开始
    %x 本地相应的日期表示
    %X 本地相应的时间表示
    %y 两位数的年份表示(00-99)
    %Y 四位数的年份表示(000-9999)
    %Z 当前时区的名称
    %% %号本身
  • 5

    # 当前时间 加一天后
    a = datetime.datetime.now() + datetime.timedelta(days=1)
    # 将一天后的时间跳到某个时间点
    a.replace(hour=2)

时间格式 2016-08-9T10:01:54.123Z 20160809100154.123Z

关于时间格式 2016-08-9T10:01:54.123Z 20160809100154.123Z 处理方法

今天遇到了一个奇怪的时间格式

如以下格式,下面两种时间格式所表示的时间是同一个时间,这个不难理解

2016-08-9T10:01:54.123Z

20160809100154.123Z

如图所示,这是一张由网友提供的图片,里面显示的是时间

然后无论如何,这个奇怪的时间我们可能看不懂,但是我们最终要显示的时间是北京时间(如果你是其他国家的人就另当别论了哦)

那么下面我们就来简单介绍一下关于时间的一些基本知识:

首先是UTC:时间标准时间

协调世界时(英:Coordinated Universal Time ,法:Temps Universel Coordonné),又称世界统一时间,世界标准时间,国际协调时间。英文(CUT)和法文(TUC)的缩写不同,作为妥协,简称UTC。

然后是GMT:格林尼治时间

世界时UT 即格林尼治时间,格林尼治所在地的标准时间。以地球自转为基础的时间计量系统。地球自转的角度可用地方子午线相对于地球上的基本参考点的运动来度量。为了测量地球自转,人们在地球上选取了两个基本参考点:春分点(见分至点)和平太阳,由此确定的时间分别称为恒星时和平太阳时。

然后下面是GST时间:也就是北京时间

通常我们在数据库中存放,或者给用户看的时间都是GST时间

现在我们说说上面的时间

2016-08-9T10:01:54.123Z

20160809100154.123Z

首先字母T:他表示后面跟的时间

而最末尾的Z表示UTC统一时间

而123表示的毫秒,大家可以测试将123改为1230,最后得到的时间,秒会增加1秒

网上很多人在搜索000Z是什么意思,其实他的意思就是 0毫秒 utc统一时间

既然我们知道了Z表示UTC统一时间,那么接下来就好办了

如上面第一个 表达式 2016-08-9T10:01:54.123Z

我们可以这样来获得一个GST(北京时间)时间,看如下代码:

String str ="2016-08-9T10:01:54.123Z";
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS Z");
Date d = format.parse(str.replace("Z", " UTC"));//注意是空格+UTC
System.out.println(d);

这样我们就获得了一个本地的时间

最后我们得到的时间是:Tue Aug 09 18:01:54 CST 2016

而表达式 20160809100154.123Z

他的转换方式也是一样的,知识格式化时,将格式化字符串修改以下即可:yyyyMMddHHmmss.SSS Z

之前我也遇到过一个类似的问题,大家也可以参考下