time,datetime
dateutil、dateparser
timeit,深入理解list()和[]区别

在项目中经常要用到时间,日期等数据,这里做对常用的库及方法进行简单的总结

time

time模块中时间表现的格式主要有三种:

  • timestamp:时间戳,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量
  • struct_time:时间元组(tm_year,tm_mon,tm_mday,tm_hour,tm_min,tm_sec,tm_wday,tm_yday,tm_isdst)
  • format_time:格式化时间。已格式化的结构使时间更具可读性
import time

time_start = time.time()
perf_counter_start = time.perf_counter()
process_start = time.process_time()

print(1, list(filter(lambda x: x if not x.startswith('_') and not x.isupper() else '', sorted(list(time.__dict__.keys())))))

# 生成timestamp
print(2, time.time())

# struct_time to timestamp
print(3, time.mktime(time.localtime()))

# 生成struct_time
# timestamp to struct_time 本地时间
print(4, time.localtime())
print(5, time.localtime(time.time()))

# timestamp to struct_time 格林威治时间
print(6, time.gmtime())
print(7, time.gmtime(time.time()))

# format_time to struct_time
print(8, time.strptime('2020-05-05 16:37:06', '%Y-%m-%d %X'))

# 生成format_time
# struct_time to format_time
print(9, time.strftime("%Y-%m-%d %X"))
print(10, time.strftime("%Y-%m-%d %X", time.localtime()))
print(11, time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime()))
"""
%Y  Year with century as a decimal number.
%m  Month as a decimal number [01,12].
%d  Day of the month as a decimal number [01,31].
%H  Hour (24-hour clock) as a decimal number [00,23].
%M  Minute as a decimal number [00,59].
%S  Second as a decimal number [00,61].
%z  Time zone offset from UTC.
%a  Locale's abbreviated weekday name.
%A  Locale's full weekday name.
%b  Locale's abbreviated month name.
%B  Locale's full month name.
%c  Locale's appropriate date and time representation.
%I  Hour (12-hour clock) as a decimal number [01,12].
%p  Locale's equivalent of either AM or PM.
Other codes may be available on your platform.
See documentation for the C library strftime function.
"""

# 生成固定格式的时间表示格式
print(12, time.asctime(time.localtime()))
print(13, time.ctime(time.time()))

# 其他
time.sleep(1)
time_end = time.time()
perf_counter_end = time.perf_counter()
process_end = time.process_time()
# 计算执行时间
print(14, time_end - time_start)
print(15, perf_counter_end - perf_counter_start)
print(16, process_end - process_start) # 不包括sleep()休眠时间期间经过的时间,上面两个包含

datetime

datatime模块重新封装了time模块,提供更多接口,提供的类有:date,time,datetime,timedelta,tzinfo,timezone

类名称 描述
datetime.date 表示日期,常用的属性有:year, month和day
datetime.time 表示时间,常用属性有:hour, minute, second, microsecond
datetime.datetime 表示日期时间
datetime.timedelta 表示两个date、time、datetime实例之间的时间间隔,分辨率(最小单位)可达到微秒
datetime.tzinfo 时区相关信息对象的抽象基类。它们由datetime和time类使用,以提供自定义时间的而调整。
datetime.timezone Python 3.2中新增的功能,实现tzinfo抽象基类的类,表示与UTC的固定偏移量

date类

  • datetime.date(year, month, day)
# print(13, time_end - time_start)
# print(14, perf_counter_end - perf_counter_start)
# print(15, process_end - process_start)
# t1 = time.localtime()
# t2 = time.localtime(12344)
# print(t1)
# print(t2)
# print(t1 + t2)

# from datetime import date, time, datetime, timedelta, tzinfo, timezone
import datetime
import time

'''
date.today():返回一个表示当前本地日期的date对象;
date.fromtimestamp(timestamp):根据给定的时间戮,返回一个date对象
'''
today = datetime.date.today()
print(today, type(today))
today_fromtimestamp = datetime.date.fromtimestamp(time.time())
print(today_fromtimestamp, type(today_fromtimestamp))

'''
d1 = datetime.date(2019, 11, 1)
d1.year、date.month、date.day:年、月、日;
d1.replace(year, month, day):生成一个新的日期对象,用参数指定的年,月,日代替原有对象中的属性。(原有对象仍保持不变)
d1.timetuple():返回日期对应的time.struct_time对象;
d1.weekday():返回weekday,如果是星期一,返回0;如果是星期2,返回1,以此类推;
d1.isoweekday():返回weekday,如果是星期一,返回1;如果是星期2,返回2,以此类推;
d1.isocalendar():返回格式如(year,month,day)的元组;
d1.isoformat():返回格式如'YYYY-MM-DD’的字符串;
d1.strftime(fmt):和time模块format相同。
'''
today_date = datetime.date(2019, 11, 1)
print(today_date.year, today_date.month, today_date.day)
tomorrow_date = today_date.replace(2019, 11, 2)
print(tomorrow_date, tomorrow_date.timetuple(), tomorrow_date.weekday(), tomorrow_date.isoweekday(), tomorrow_date.isocalendar(), tomorrow_date.isoformat(), tomorrow_date.strftime('%Y_%m_%d') )

time类

  • class datetime. time ( hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0 ) 参数可选
import datetime
import time

'''
t1 = datetime.time(10,23,15) #time对象
t1.hour、t1.minute、t1.second、t1.microsecond:时、分、秒、微秒;
t1.tzinfo:时区信息;
t1.replace([ hour[ , minute[ , second[ , microsecond[ , tzinfo] ] ] ] ] ):创建一个新的时间对象,用参数指定的时、分、秒、微秒代替原有对象中的属性(原有对象仍保持不变);
t1.isoformat():返回型如"HH:MM:SS"格式的字符串表示;
t1.strftime(fmt):同time模块中的format;
'''

now_time = datetime.time(12, 24, 36, 59)
print(now_time.hour, now_time.minute, now_time.second, now_time.microsecond)
next_time = now_time.replace(12, 25, 36, 59)
print(next_time, next_time.isoformat(), next_time.strftime('%H:%M:%S'))

datetime类

  • datetime相当于date和time结合起来
  • datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
import datetime
import time

'''
datetime.today():返回一个表示当前本地时间的datetime对象;
datetime.now([tz]):返回一个表示当前本地时间的datetime对象,如果提供了参数tz,则获取tz参数所指时区的本地时间;
datetime.utcnow():返回一个当前utc时间的datetime对象;#格林威治时间
datetime.fromtimestamp(timestamp[, tz]):根据时间戮创建一个datetime对象,参数tz指定时区信息;
datetime.utcfromtimestamp(timestamp):根据时间戮创建一个datetime对象;
datetime.combine(date, time):根据date和time,创建一个datetime对象;
datetime.strptime(date_string, format):将格式字符串转换为datetime对象;
'''
today_datetime = datetime.datetime.today()
print(today_datetime, type(today_datetime))
now_datetime = datetime.datetime.now()
print(now_datetime, datetime.datetime.utcnow(), datetime.datetime.fromtimestamp(time.time()))

print(now_datetime.year, now_datetime.month, now_datetime.day, now_datetime.hour, now_datetime.minute, now_datetime.second)

print(datetime.datetime.now().date())  # 获取date对象
print(datetime.datetime.now().time())  # 获取time对象

获取到date,time对象后则可以用date类和time类的相关方法和属性

timedelta类

使用timedelta可以很方便的在日期上做天days,小时hour,分钟,秒,毫秒,微妙的时间计算(如果要计算月份则可用下面的dateutil库来解决)

import datetime
import time

start_time = datetime.datetime.now()

today_datetime = datetime.datetime.now()
'''
datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0):在日期上做计算
datetime.timedelta.day, datetime.timedelta.seconds, datetime.timedelta.microseconds : 时间差的day, seconds,microseconds 数
datetime.timedelta.total_seconds():时间差的总秒数
'''
yesterday_datetime_1 = today_datetime + datetime.timedelta(days=-1, hours=1)  # 昨天此时一个小时后
yesterday_datetime_2 = today_datetime - datetime.timedelta(days=1)  # 昨天此时
tomorrow_datetime = today_datetime + datetime.timedelta(days=1)  # 明天此时
print(yesterday_datetime_1, yesterday_datetime_2, tomorrow_datetime, sep='\n')

delta_datetime = today_datetime - yesterday_datetime_1  # 相差23个小时
print(delta_datetime, type(delta_datetime))

print(delta_datetime.days, delta_datetime.seconds, delta_datetime.total_seconds(), delta_datetime.microseconds)

time.sleep(1)

end_time = datetime.datetime.now()
delta_datetime = end_time - start_time  # 计算执行时间
print(delta_datetime.total_seconds())

dateutil

The dateutil module provides powerful extensions to the standard datetime module, available in Python.
dateutil模块是python标准库datetime的增强版本,能够很方便计算相对时间(下一个月的,明年,下周一,一个月的最后一周等),计算两个给定时间的增量,而且能够解析几乎任何字符串格式的日期,时区处理等

dateutil安装

pip install python-dateutil

dateutil使用简介

from dateutil.relativedelta import *
from dateutil.easter import *
from dateutil.rrule import *
from dateutil.parser import *
from datetime import *

# now = datetime.now()
# now = parse("Sat Oct 11 17:13:46 UTC 2003")
now = parse("2028-11-5 15:33:12")
today = now.date()
year = rrule(YEARLY, dtstart=now, bymonth=8, bymonthday=13, byweekday=FR)[0].year
rdelta = relativedelta(easter(year), today)
print("Today is: %s" % today)
print("Year with next Aug 13th on a Friday is: %s" % year)
print("How far is the Easter of that year: %s" % rdelta)
print("And the Easter of that year is: %s" % (today + rdelta))

其他

  • 如计算一个月后的的今天是周几
from dateutil.relativedelta import *
# from datetime import *
import datetime

today = datetime.datetime.now()
next_month = today + relativedelta(months=+1)
print(f"一个月后的今天是周{next_month.isoweekday()}")

更多使用方法可参考官方文档

dateparser

  • 可以处理多种语言的几乎所有格式日期时间字符串
  • 很容易处理相对时间

官方文档

dateparser安装

pip install dateparser

dateparser基本使用

  • 基本使用
d1 = dateparser.parse('Fri, 12 Dec 2014 10:55:50')
d2 = dateparser.parse('1991-05-17')

# 相对时间处理如  '1 min ago', '2 weeks ago', '3 months, 1 week and 1 day ago', 'in 2 days', 'tomorrow'
d3 = dateparser.parse('In two months') 
d4 = dateparser.parse('1484823450')  # timestamp时间戳处理
print(d1, d2, d3, d4)
  • 多语言支持
d5 = dateparser.parse('2小时前') 
d6 = dateparse.parse('明天')
print(d5, d6)
  • settings参数
d7 = dateparser.parse('14-10-20', settings={'DATE_ORDER': 'YMD'})
d8 = dateparser.parse('14-10-20', settings={'DATE_ORDER': 'MDY'})
print(d7, d8)

这里仅举例了日期顺序的设置,还可以处理其他settings如不完整日期,可进一步参考官方文档

  • dateparser.parse返回的对象类型
d1 = dateparser.parse('2020-05-17')
print(d1, type(d1), sep='\n)
------------------
2020-05-17 00:00:00
<class 'datetime.datetime'>

由上可知,dateparser.parse返回的是datetime.datetime对象,根据需要可利用datetime.datetime的函数和属性进一步处理

d1 = dateparser.parse('2020-05-17 12:23:23')
print(d1.year, d1.time())

timeit

  • 用来测试小段代码的运行时间
  • 主要通过timeit和repeat两个函数实现,源码如下:
# timeit和repeat源码,都是调用了Timer对象的timeit或repeat函数
def timeit(stmt="pass", setup="pass", timer=default_timer,
           number=default_number, globals=None):
    """Convenience function to create Timer object and call timeit method."""
    return Timer(stmt, setup, timer, globals).timeit(number)

def repeat(stmt="pass", setup="pass", timer=default_timer,
           repeat=default_repeat, number=default_number, globals=None):
    """Convenience function to create Timer object and call repeat method."""
    return Timer(stmt, setup, timer, globals).repeat(repeat, number)

stmt:用于传入要测试时间的代码,可以直接接受字符串的表达式,也可以接受单个变量,也可以接受函数。传入函数时要把函数申明在当前文件中,然后在 stmt = 'func()' 执行函数,然后使用 setup = 'from __main__ import func'
setup:传入stmt的运行环境,比如stmt中使用到的参数、变量,要导入的模块等。可以写一行语句,也可以写多行语句,写多行语句时要用分号;隔开语句。
number:要测试的代码的运行次数,默认100000次
repeat:指测试要重复几次,每次的结果构成列表返回,默认3次

import timeit

# stmt为字符串表达式
print(timeit.timeit(stmt='list(i**2 for i in normal_list)', setup='normal_list=range(10000)', number=10))
print(timeit.timeit(stmt='list(i**2 for i in range(10000))', number=10))

print(timeit.repeat(stmt='list(i**2 for i in normal_list)', setup='normal_list=range(10000)', repeat=2, number=10))

# setup 为复合语句
print(timeit.timeit(stmt='list(i**2 for i in normal_list)', setup='a=10000;normal_list=range(a)', number=10))
print(timeit.repeat(stmt='list(i**2 for i in normal_list)', setup='a=10000;normal_list=range(a)', repeat=2, number=10))

def func():
    normal_list = range(10000)
    lst = [i ** 2 for i in normal_list]

# stmt为函数
print(timeit.timeit("func()", setup="from __main__ import func", number=10))
print(timeit.repeat("func()", setup="from __main__ import func", repeat=2, number=10))

timeit机制

  • 从内部讲,timeit 构建起一个独立的虚拟环境,手工地执行建立语句 (导入 soundex 模块),然后手工地编译和执行被计时语句 (调用 Soundex 函数)
  • 可以说使用timeit计时更准确,切勿自己编写计时函数。在程序中有很多因素会影响计算的时间,比如垃圾回收机制。使用timeit会自动关掉垃圾回收机制,让程序的运行更加独立,时间计算更加准确

在jupyter notebook中使用timeit

可在jupyter notebook中执行%timeit?查看具体使用方法

Usage, in line mode:
%timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] statement
or in cell mode:
%%timeit [-n<N> -r<R> [-t|-c] -q -p<P> -o] setup_code

[]和list()

  • list()是内置类型(built-in types)
  • 内置函数built-in functions内置类型built-in types 官方文档
  • 内置函数和内置类型都不是关键字,可参看官方文档keywords
  • Python 给一些常用的内置类型提供了字面量表示法,也就是""、[]、()、{} 等等,表示字符串、列表、元组和字典等数据类型,参看官方文档delimiters
import timeit

print(timeit.timeit('[]', number=10 ** 7))  # 0.22205465100000002
print(timeit.timeit('list()', number=10 ** 7))  # 0.8627885369999999
  • list() 比 [] 执行步骤多,因此list()比[]慢(可通过dis模块的dis()函数查看两者字节码,[] 的字节码有两条指令(BUILD_LIST 与 RETURN_VALUE),而 list() 的字节码有三条指令(LOAD_NAME、CALL_FUNCTION 与 RETURN_VALUE))

扩展阅读及参考