【Day41】Python之路——Time时间模块

time与datetime模块

在Python中,通常有这几种方式来表示时间:

  • 时间戳(timestamp):通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。
  • 格式化的时间字符串(Format String)
  • 结构化的时间(struct_time --元组):struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)

#导入时间模块
>>>import time

#时间戳
>>>time.time()
1500875844.800804

#时间字符串
>>>time.strftime("%Y-%m-%d %X")
'2017-07-24 13:54:37'
>>>time.strftime("%Y-%m-%d %H-%M-%S")
'2017-07-24 13-55-04'

#时间元组:localtime将一个时间戳转换为当前时区的struct_time
time.localtime()
time.struct_time(tm_year=2017, tm_mon=7, tm_mday=24,
          tm_hour=13, tm_min=59, tm_sec=37, 
                 tm_wday=0, tm_yday=205, tm_isdst=0)

#格式化的时间字符串:'2017-02-15 11:40:53'
print(time.strftime("%Y-%m-%d %X")) 

#本地时区的struct_time
print(time.localtime()) 

 #UTC时区的struct_time
print(time.gmtime())   

小结:时间戳是计算机能够识别的时间;时间字符串是人能够看懂的时间;元组则是用来操作时间的

 几种格式之间的转换

 

#时间戳-->结构化时间

#时间戳-->结构化时间
#time.gmtime(时间戳)    #UTC时间,与英国伦敦当地时间一致
#time.localtime(时间戳) #当地时间。例如我们现在在北京执行这个方法:与UTC时间相差8小时,UTC时间+8小时 = 北京时间 
>>>time.gmtime(1500000000)
time.struct_time(tm_year=2017, tm_mon=7, tm_mday=14, tm_hour=2, tm_min=40, tm_sec=0, tm_wday=4, tm_yday=195, tm_isdst=0)
>>>time.localtime(1500000000)
time.struct_time(tm_year=2017, tm_mon=7, tm_mday=14, tm_hour=10, tm_min=40, tm_sec=0, tm_wday=4, tm_yday=195, tm_isdst=0)

#结构化时间-->时间戳 
#time.mktime(结构化时间)
>>>time_tuple = time.localtime(1500000000)
>>>time.mktime(time_tuple)
1500000000.0
结构化时间-->字符串时间
#结构化时间-->字符串时间
#time.strftime("格式定义","结构化时间")  结构化时间参数若不传,则现实当前时间
>>>time.strftime("%Y-%m-%d %X")
'2017-07-24 14:55:36'
>>>time.strftime("%Y-%m-%d",time.localtime(1500000000))
'2017-07-14'

#字符串时间-->结构化时间
#time.strptime(时间字符串,字符串对应格式)
>>>time.strptime("2017-03-16","%Y-%m-%d")
time.struct_time(tm_year=2017, tm_mon=3, tm_mday=16, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=75, tm_isdst=-1)
>>>time.strptime("07/24/2017","%m/%d/%Y")
time.struct_time(tm_year=2017, tm_mon=7, tm_mday=24, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=0, tm_yday=205, tm_isdst=-1)

#结构化时间 --> %a %b %d %H:%M:%S %Y串
#time.asctime(结构化时间) 如果不传参数,直接返回当前时间的格式化串
>>>time.asctime(time.localtime(1500000000))
'Fri Jul 14 10:40:00 2017'
>>>time.asctime()
'Mon Jul 24 15:18:33 2017'

#时间戳 --> %a %d %d %H:%M:%S %Y串
#time.ctime(时间戳)  如果不传参数,直接返回当前时间的格式化串
>>>time.ctime()
'Mon Jul 24 15:19:07 2017'
>>>time.ctime(1500000000)
'Fri Jul 14 10:40:00 2017' 
#时间加减
import datetime

# print(datetime.datetime.now()) #返回 2016-08-19 12:47:03.941925
#print(datetime.date.fromtimestamp(time.time()) )  # 时间戳直接转成日期格式 2016-08-19
# print(datetime.datetime.now() )
# print(datetime.datetime.now() + datetime.timedelta(3)) #当前时间+3天
# print(datetime.datetime.now() + datetime.timedelta(-3)) #当前时间-3天
# print(datetime.datetime.now() + datetime.timedelta(hours=3)) #当前时间+3小时
# print(datetime.datetime.now() + datetime.timedelta(minutes=30)) #当前时间+30分


#
# c_time  = datetime.datetime.now()
# print(c_time.replace(minute=3,hour=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.now()
>>> a.year
2018
>>> a.day
19
>>> print(a + timedelta(days=10))
2018-01-29 18:03:18.837018
>>> b = datetime(2012,12,21)
>>> d = a-b
>>> d
datetime.timedelta(1855, 64998, 837018)
>>> d.days
1855
>>> now = datetime.today()
>>> now
datetime.datetime(2018, 1, 19, 18, 6, 7, 306654)
>>> print(now)
2018-01-19 18:06:07.306654

注意 :当以datetime 进行获取时间时,获取天数使用 obj.day  ,但是当两个日期进行相减时,获取天数使用 obj.days

>>> e = datetime.now()
>>> f = datetime.now()
>>> e
datetime.datetime(2018, 1, 19, 18, 22, 30, 380882)
>>> f
datetime.datetime(2018, 1, 19, 18, 22, 33, 405055)
>>> a = f+e
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'datetime.dat
>>> a = f-e
>>> a.seconds
3
>>> a.days
0
>>> now = datetime.today()
>>> print(now)
2012-12-21 14:54:43.094063
>>> print(now + timedelta(minutes=10))
2012-12-21 15:04:43.094063 注意: 两个时间只能相减,只能获取到时间的天与秒 天:obj.days 秒:obj.seconds

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

>>> a = datetime(2012, 3, 1)
>>> b = datetime(2012, 2, 28)
>>> a-b
datetime.timedelta(2)
>>> c = datetime(2013, 3, 1)
>>> d = datetime(2013, 2, 28)
>>> c-d
datetime.timedelta(1)

复杂的日期操作,比如处理时区,模糊时间范围,节假日计算等等,可以考虑使
用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
>>>

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

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

 讨论
    上面的算法原理是这样的:先将开始日期和目标日期映射到星期数组的位置上(星
  期一索引为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

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

解决方案
在这样的日期上循环并需要事先构造一个包含所有日期的列表。你可以先计算出
开始日期和结束日期,然后在你步进的时候使用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

讨论
上面的代码先计算出一个对应月份第一天的日期。一个快速的方法就是使用date
或datetime 对象的replace() 方法简单的将days 属性设置成1 即可。replace() 方
法一个好处就是它会创建和你开始传入对象类型相同的对象。所以,如果输入参数是一
个date 实例,那么结果也是一个date 实例。同样的,如果输入是一个datetime 实
例,那么你得到的就是一个datetime 实例。
然后,使用calendar.monthrange() 函数来找出该月的总天数。任何时候只要你
想获得日历信息,那么calendar 模块就非常有用了。monthrange() 函数会返回包含
星期和该月天数的元组。
一旦该月的天数已知了,那么结束日期就可以通过在开始日期上面加上这个天数
获得。有个需要注意的是结束日期并不包含在这个日期范围内(事实上它是下个月的开
始日期)。这个和Python 的slice 与range 操作行为保持一致,同样也不包含结尾。
为了在日期范围上循环,要使用到标准的数学和比较操作。比如,可以利用
timedelta 实例来递增日期,小于号< 用来检查一个日期是否在结束日期之前。
理想情况下,如果能为日期迭代创建一个同内置的range() 函数一样的函数就好
了。幸运的是,可以使用一个生成器来很容易的实现这个目标:

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

字符串转换为日期

问题
  你的应用程序接受字符串格式的输入,但是你想将它们转换为datetime 对象以便
在上面执行非字符串操作。
解决方案
  使用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)
>>>

讨论
  datetime.strptime() 方法支持很多的格式化代码,比如%Y 代表4 位数年份,%m
代表两位数月份。还有一点值得注意的是这些格式化占位符也可以反过来使用,将日期
输出为指定的格式字符串形式。
  比如,假设你的代码中生成了一个datetime 对象,你想将它格式化为漂亮易读形
式后放在自动生成的信件或者报告的顶部:

>>> 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() 的性能要比你想象中的差很多,因为它是使
用纯Python 实现,并且必须处理所有的系统本地设置。如果你要在代码中需要解析大
量的日期并且已经知道了日期字符串的确切格式,可以自己实现一套解析方案来获取
更好的性能。比如,如果你已经知道所以日期格式是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))

  实际测试中,这个函数比datetime.strptime() 快7 倍多。如果你要处理大量的
涉及到日期的数据的话,那么最好考虑下这个方案!

结合时区的日期操作

问题
  你有一个安排在2012 年12 月21 日早上9:30 的电话会议,地点在芝加哥。而你
的朋友在印度的班加罗尔,那么他应该在当地时间几点参加这个会议呢?
解决方案
  对几乎所有涉及到时区的问题,你都应该使用pytz 模块。这个包提供了Olson 时
区数据库,它是时区信息的事实上的标准,在很多语言和操作系统里面都可以找到。
pytz 模块一个主要用途是将datetime 库创建的简单日期对象本地化。比如,下
面如何表示一个芝加哥时间的示例:

>>> from datetime import datetime
>>> from pytz import timezone
>>> d = datetime(2012, 12, 21, 9, 30, 0)
>>> print(d)
2012-12-21 09:30:00
>>> central = timezone('US/Central')
>>> loc_d = central.localize(d)
>>> print(loc_d)
2012-12-21 09:30:00-06:00

  一旦日期被本地化了,它就可以转换为其他时区的时间了。为了得到班加罗尔对应
的时间,你可以这样做:

>>> # Convert to Bangalore time
>>> bang_d = loc_d.astimezone(timezone('Asia/Kolkata'))
>>> print(bang_d)
2012-12-21 21:00:00+05:30

处理本地化日期的通常的策略先将所有日
期转换为UTC 时间,并用它来执行所有的中间存储和操作。比如:

>>> print(loc_d)
2013-03-10 01:45:00-06:00
>>> utc_d = loc_d.astimezone(pytz.utc)
>>> print(utc_d)
2013-03-10 07:45:00+00:00

  一旦转换为UTC,你就不用去担心跟夏令时相关的问题了。因此,你可以跟之前
一样放心的执行常见的日期计算。当你想将输出变为本地时间的时候,使用合适的时区
去转换下就行了。比如:

>>> later_utc = utc_d + timedelta(minutes=30)
>>> print(later_utc.astimezone(central))
2013-03-10 03:15:00-05:00

  当涉及到时区操作的时候,有个问题就是我们如何得到时区的名称。比如,在这个
例子中,我们如何知道“Asia/Kolkata”就是印度对应的时区名呢?为了查找,可以使
用ISO 3166 国家代码作为关键字去查阅字典pytz.country_timezones 。比如:

>>> pytz.country_timezones['IN']
['Asia/Kolkata']

注:当你阅读到这里的时候,有可能pytz 模块已经不再建议使用了,因为PEP431
提出了更先进的时区支持。但是这里谈到的很多问题还是有参考价值的(比如使用UTC
日期的建议等)。

 

 构建时间对象

原文地址:https://www.cnblogs.com/huyangblog/p/8318594.html