Python datetime使用指导:操作时间、日期和时间区间
在 Python 中处理日期和时间是一个很麻烦的问题。幸运的是,Python 提供了内置方法来简化这种操作:Python Datetime 模块。
datetime 可以帮助我们识别并处理与时间相关的元素,如日期,小时,分钟,秒,星期,月份,年份等。它还提供了诸如时区和夏令时等很多服务。它可以处理时间戳数据,可以提取星期中的第几天,月份的第几天,以及其他字符串格式的日期和时间等。
总结来说,datetime 是 Python 中处理任何日期和时间相关问题的强大手段。本节教程中,我们将会学习很多 datetime 的方法,包括:
-
创建日期对象
-
从日期中获取年份和月份
-
从日期中获取每月几号和星期几
-
从日期中获取小时和分钟
-
从日期中获取一年中的第几周
-
日期对象转换成时间戳
-
Unix 时间戳字符串转换成日期对象
-
处理timedelta时间差对象
-
比较两个日期和时间之间的差值
-
日期格式化:strftime() 和 strptime()
-
时区处理
-
使用 Pandas 中的 datetime 对象
-
获取年,月,日,时,分
-
获取星期几与一年中的第几天
-
转换日期对象为 DataFrame 索引
Python 的 datetime 类
在编写代码之前,有必要先了解一下 datetime 模块中提供的五个主要的对象类。根据我们具体需要执行的操作,我们可能需要使用其中的一个或多个类。
-
datatime:允许我们同时操作时间和日期(月,日,年,时,秒,微秒)。
-
date:允许我们排除时间仅操作日期(月,日,年)
-
time:允许我们排除日期仅操作时间(时,分,秒,微秒)
-
timedelta:一个用于操作日期以及测量的时间跨度
-
tzinfo:一个用于处理时区的抽象类
创建 Date 对象
datetime 既是模块名也是模块内的类名,所以我们要从 datetime 模块内引用 datetime 类。
然后,打印当前日期和时间来查看 datetime 对象中都包含什么。可以使用 datetime 类的 .now() 函数创建一个 datetime 对象,然后打印这个对象,之后再使用 type() 函数打印这个对象的类型。如此,我们可以看到更详细的信息。
# import datetime class from datetime module
from datetime import datetime
# get current date
datetime_object = datetime.now()
print(datetime_object)
print('Type :- ',type(datetime_object))
2019-10-25 10:24:01.521881
Type :-
从上面的结果中,可以看到 datetime_object 是 datetime 类的对象实例,对象中包含了年,月,日,时,分,秒,以及毫秒。
从 Date 中提取年份和月份
现在已经理解了 datetime 对象的构成,可以猜一下 date 和 time 对象是怎样的。因为我们已经知道 date 对象可以理解为 datetime 去掉了时间数据,而 time 对象可以理解为 datetime 去掉了日期数据。
我们也可以反驳一些问题。例如,在大多数数据集中,日期和时间信息都是以字符串格式存储的! 另外,我们可能并不想要所有的日期和时间数据--如果我们要做的是月度销售分析,那么按微秒来分解就没有什么用了。
所以现在,让我们开始挖掘数据科学中的一个常见任务:使用datetime从字符串中只提取我们实际想要的元素。要做到这一点,我们需要做几件事。
使用 strptime() 和 strftime() 处理日期和时间字符串
datetime包含两个方法,strptime()和strftime(),用于将对象从字符串转换为datetime对象,反之亦然。
当然,strptime()并不神奇--它无法将任何字符串转化为日期和时间,它需要我们的帮助来解释它所看到的东西!但它能够读取大部分的日期和时间信息。但它能够读取大多数传统的字符串格式的日期和时间数据(详情请看文档 the documentation for more details)。让我们给它一个YYY-MM-DD格式的日期字符串,看看它能做什么!
my_string = '2019-10-31'
# Create date object in given time format yyyy-mm-dd
my_date = datetime.strptime(my_string, "%Y-%m-%d")
print(my_date)
print('Type: ',type(my_date))
2019-10-31 00:00:00 Type:
注意,strptime()接收了两个参数:字符串(my_string)和"%Y-%m-%d",另一个字符串告诉strptime()如何解释输入的字符串my_string。例如,"%Y "告诉它期望字符串的前四个字符是年份。
这些模式的完整列表可以在文档中找到,我们将在本教程的后面详细介绍这些方法。
你可能已经注意到,在日期中添加了一个00:00:00:00的时间。这是因为我们创建了一个datetime对象,它必须包括一个日期和一个时间。00:00:00:00是默认的时间,如果我们输入的字符串中没有指定时间,那么就会被分配到时间。
总之,我们希望能将日期中的特定元素分离出来进行分析。一种方法可以使用datetime对象的内置类属性来实现,比如.month或.year。
print('Month: ', my_date.month) # To Get month from date
print('Year: ', my_date.year) # To Get month from year
Month: 10 Year: 2019
从 Date 获取每月的某天和一周的某天
让我们再提取一些信息,因为这真的是一个很常见的任务。这一次,我们将尝试从my_date中获取月份的日期和星期的日期。Datetime会用它的 .weekday()函数给我们一个星期的日期,但是我们可以使用日历模块和一个叫day_name的方法将其转换为文本格式(例如星期一、星期二、星期三......)。
我们将从导入日历开始,然后在my_date上使用.day和.weekday()。从那里,我们可以得到一个星期的日期,以文本格式,就像这样。
# import calendar module
import calendar
print('Day of Month:', my_date.day)
# to get name of day(in number) from date
print('Day of Week (number): ', my_date.weekday())
# to get name of day from date
print('Day of Week (name): ', calendar.day_name[my_date.weekday()])
Day of Month: 31 Day of Week (number): 3 Day of Week (name): Thursday
等一下,这里看起来有一点奇怪。一周的第三天应该是 Wednesday 而不是 Thursday 啊。
我们这里使用一个循环来仔细看一下 day_name 变量中的信息:
j = 0
for i in calendar.day_name:
print(j,'-',i)
j+=1
0 - Monday 1 - Tuesday 2 - Wednesday 3 - Thursday 4 - Friday 5 - Saturday 6 - Sunday
现在我们知道 Python 中星期是从 Monday 开始的,其计数下标则是从 0 开始而不是从 1 开始。所以这就解释了我们上面看到的为什么数字 3 转换成了 "Thursday"。
从 Python 的 Datetime 对象中获取小时和分钟
现在,让我们深入挖掘time,从datetime对象中提取时分。就像上面我们对月和年做的那样,我们可以使用类属性.hour和.mini来获取当天的小时和分钟。
让我们使用.now()函数设置一个新的日期和时间。截至本文写作时,现在是2019年10月25日上午10点25分。当然,根据你选择在什么时候运行这段代码,你会得到不同的结果,当然了!
from datetime import datetime todays_date = datetime.now()
# to get hour from datetime
print('Hour: ', todays_date.hour)
# to get minute from datetime
print('Minute: ', todays_date.minute)
Hour: 10 Minute: 25
从 Datetime 对象中获取一年中的星期数
我们还可以用日期时间来做更多的事情。例如,如果我们想知道今年是哪一周呢?我们可以用.isocalendar()函数从一个datetime对象中获取年份、星期和星期的日期。具体来说,isocalendar()
函数返回一个包含ISO年、周号和星期的tuple。ISO日历是一种基于Gregorian历法的标准日历,被广泛使用。你可以在这个链接中详细了解它,但就我们的目的而言,我们只需要知道它的工作原理是作为一个普通的日历,从每周一开始。
# Return a 3-tuple, (ISO year, ISO week number, ISO weekday).
todays_date.isocalendar()
(2019, 43, 5)
注意,在 ISO 日历中,每星期是从 1 开始计数的,所以这里的 5 真正表示的是星期五:Friday。
从上面我们可以看到当前是今天的第 43 个星期,但是如果你只想获得这个数字,可以像其他 Python 中的列表或元组一样,使用下标索引的方式实现:
todays_date.isocalendar()[1]
43
将 Date 对象转换为 Unix 时间戳,反之亦然
在编程中,我们经常会遇到以时间戳形式存储时间和日期数据的情况,或者想将自己的数据以Unix的时间戳格式存储。
我们可以使用datetime内置的timestamp()函数来实现,它以一个datetime对象作为参数,并以时间戳格式返回日期和时间。
#import datetime
from datetime import datetime
# get current date
now = datetime.now()
# convert current date into timestamp
timestamp = datetime.timestamp(now)
print("Date and Time :", now)
print("Timestamp:", timestamp)
Date and Time : 2019-10-25 10:36:32.827300 Timestamp: 1572014192.8273
同样,我们可以使用fromtimestamp()进行反向转换。这是一个datetime函数,它以时间戳(float格式)作为参数,返回一个datetime对象,如下图所示。
#import datetime
from datetime import datetime
timestamp = 1572014192.8273
#convert timestamp to datetime object
dt_object = datetime.fromtimestamp(timestamp)
print("dt_object:", dt_object)
print("type(dt_object): ", type(dt_object))
dt_object: 2019-10-25 10:36:32.827300 type(dt_object): <class 'datetime.datetime'>
使用timedelta对象测量时间跨度
通常情况下,我们可能想用Python的datetime来测量一个时间跨度或持续时间。我们可以通过其内置的 timedelta 类来实现。timedelta 对象表示两个日期或时间之间的时间量。我们可以用它来测量时间跨度,或者通过加减法来操作日期或时间等。
默认情况下,timedelta对象的所有参数都设置为0。让我们创建一个新的时间长度为两周的timedelta对象,看看效果如何。
#import datetime
from datetime import timedelta
# create timedelta object with difference of 2 weeks
d = timedelta(weeks=2)
print(d)
print(type(d))
print(d.days)
14 days, 0:00:00 <class 'datetime.timedelta'> 14
注意,我们可以通过使用 timedelta 类属性 .days 来获取时间持续时间,单位为天。我们可以在它的文档中看到,我们也可以得到这个时间持续时间,单位为秒或微秒。
让我们再创建一个时间持续时间,以获得更多的练习:
year = timedelta(days=365)
print(year)
365 days, 0:00:00
现在,让我们开始使用timedelta对象和datetime对象一起做一些数学运算吧! 具体来说,让我们在当前时间和日期中加入几个不同的时间持续时间,看看15天后是什么日期,两周前是什么日期。
要做到这一点,我们可以使用+或-操作符来将timedelta对象添加或减去datetime对象。结果将是datetime对象加上或减去我们的timedelta对象中指定的时间长度。很酷吧?
(注意:在下面的代码中,现在是10月25日上午11点12分;你的结果会根据你运行代码的时间而有所不同,因为我们使用.now()函数获取datetime对象)。
#import datetime
from datetime import datetime, timedelta
# get current time
now = datetime.now()
print ("Today's date: ", str(now))
#add 15 days to current date
future_date_after_15days = now + timedelta(days = 15)
print('Date after 15 days: ', future_date_after_15days)
#subtract 2 weeks from current date
two_weeks_ago = now - timedelta(weeks = 2)
print('Date two weeks ago: ', two_weeks_ago)
print('two_weeks_ago object type: ', type(two_weeks_ago))
Today's date: 2019-10-25 11:12:24.863308 Date after 15 days: 2019-11-09 11:12:24.863308 Date two weeks ago: 2019-10-11 11:12:24.863308 two_weeks_ago object type: <class 'datetime.datetime'>
请注意,这些数学运算的输出仍然是一个日期时间对象。
找出两个日期和时间之间的差值
与上面的方法类似,我们也可以用datetime从另一个日期中减去一个日期,找到它们之间的时间跨度。
因为这个计算的结果是一个持续时间,所以当我们把一个日期从另一个日期减去后产生的对象将是一个时间跨度对象。
在这里,我们将创建两个日期对象(记住,这些对象的工作原理和datetime对象一样,只是不包括时间数据),然后从另一个对象中减去一个来找到持续时间。
# import datetime
from datetime import date
# Create two dates
date1 = date(2008, 8, 18)
date2 = date(2008, 8, 10)
# Difference between two dates
delta = date2 - date1
print("Difference: ", delta.days)
print('delta object type: ', type(delta))
Difference: -8 delta object type: <class 'datetime.timedelta'>
上面,为了清晰起见,我们只使用了日期,但我们可以用日期时间对象做同样的事情来得到一个更精确的测量,包括时、分、秒。
# import datetime
from datetime import datetime
# create two dates with year, month, day, hour, minute, and second
date1 = datetime(2017, 6, 21, 18, 25, 30)
date2 = datetime(2017, 5, 16, 8, 21, 10)
# Difference between two dates
diff = date1-date2
print("Difference: ", diff)
Difference: 36 days, 10:04:20
格式化日期,更多关于strftime()和strptime()的内容
之前我们简单的触及了strftime()和strptime(),但让我们来仔细看看这些方法,因为它们在Python中的数据分析工作中往往很重要。
strptime()就是我们之前用过的方法,你会记得它可以把格式化为文本字符串的日期和时间变成一个数据时间对象,格式如下。
time.strptime(string, format)
注意,它需要两个参数。
-
string - 我们要转换的字符串格式的时间。
-
format -字符串中时间的具体格式,以便strptime()能够正确地解析它。
这次让我们尝试转换不同类型的日期字符串。这个网站是一个非常有用的参考,它可以帮助我们找到需要的格式化代码来帮助strptime()解释我们的字符串输入。
# import datetime
from datetime import datetime
date_string = "1 August, 2019"
# format date
date_object = datetime.strptime(date_string, "%d %B, %Y")
print("date_object: ", date_object)
date_object: 2019-08-01 00:00:00
现在,让我们来做一些更高级的事情,来练习一下我们到目前为止所学的一切! 我们将从字符串格式的日期开始,将其转换为日期时间对象,然后看一下不同的格式化方法(dd/mm和mm/dd)。
然后,坚持使用mm/dd格式,我们将把它转换为Unix时间戳。然后,我们将把它转换回一个日期时间对象,并使用一些不同的 strftime patterns来控制输出。
# import datetime
from datetime import datetime
dt_string = "12/11/2018 09:15:32"
# Considering date is in dd/mm/yyyy format
dt_object1 = datetime.strptime(dt_string, "%d/%m/%Y %H:%M:%S")
print("dt_object1:", dt_object1)
# Considering date is in mm/dd/yyyy format
dt_object2 = datetime.strptime(dt_string, "%m/%d/%Y %H:%M:%S")
print("dt_object2:", dt_object2)
# Convert dt_object2 to Unix Timestamp
timestamp = datetime.timestamp(dt_object2)
print('Unix Timestamp: ', timestamp)
# Convert back into datetime
date_time = datetime.fromtimestamp(timestamp)
d = date_time.strftime("%c")
print("Output 1:", d)
d = date_time.strftime("%x")
print("Output 2:", d)
d = date_time.strftime("%X")
print("Output 3:", d)
dt_object1: 2018-11-12 09:15:32 dt_object2: 2018-12-11 09:15:32 Unix Timestamp: 1544537732.0 Output 1: Tue Dec 11 09:15:32 2018 Output 2: 12/11/18 Output 3: 09:15:32
这里有一张图片,你可以保存一个常用的、有用的strptime和strftime模式的练习表。
image.png下面我们就一起来练习一下这些东西的使用方法。
# current date and time
now = datetime.now()
# get year from date
year = now.strftime("%Y")
print("Year:", year)
# get month from date
month = now.strftime("%m")
print("Month;", month)
# get day from date
day = now.strftime("%d")
print("Day:", day)
# format time in HH:MM:SS
time = now.strftime("%H:%M:%S")
print("Time:", time)
# format date
date_time = now.strftime("%m/%d/%Y, %H:%M:%S")
print("Date and Time:",date_time)
Year: 2019 Month; 10 Day: 25 Time: 11:56:41 Date and Time: 10/25/2019, 11:56:41
处理时间区间
在Pythin中处理日期和时间,如果涉及到时区,就会变得更加复杂。幸运的是,pytz模块的存在可以帮助我们处理跨时区的转换。它还可以处理使用夏令时的地点的夏令时。
我们可以使用 localize 函数将一个时区位置添加到 Python 的 datetime 对象中。然后,我们可以使用函数 astimezone() 将现有的本地时区转换为我们指定的任何其他时区 (它以我们要转换的时区作为参数)。
比如说。
# import timezone from pytz module
from pytz import timezone
# Create timezone US/Eastern
east = timezone('US/Eastern')
# Localize date
loc_dt = east.localize(datetime(2011, 11, 2, 7, 27, 0))
print(loc_dt)
# Convert localized date into Asia/Kolkata timezone
kolkata = timezone("Asia/Kolkata")
print(loc_dt.astimezone(kolkata))
# Convert localized date into Australia/Sydney timezone
au_tz = timezone('Australia/Sydney')
print(loc_dt.astimezone(au_tz))
2011-11-02 07:27:00-04:00 2011-11-02 16:57:00+05:30 2011-11-02 22:27:00+11:00
当处理包含多个不同时区的数据集时,这个模块可以帮助我们简化生活。
使用 pandas Datetime 对象
数据科学家喜欢pandas的原因有很多。其中一个原因是它包含了大量用于处理时间序列数据的功能和特性。很像datetime本身,pandas有datetime和timedelta对象,分别用于指定日期和时间和持续时间。
我们可以使用这些函数将日期、时间和持续时间文本字符串转换为pandas Datetime对象。
-
to_datetime(): 将字符串日期和时间转换为Python的datetime对象。
-
to_timedelta():将字符串日期和时间转换为Python的datetime对象。查找以天、时、分、秒为单位的时间差异。
正如我们将看到的那样,这些函数通过自动检测字符串的格式来将字符串转换为Python的datetime对象,而不需要我们使用strftime模式来定义。
让我们来看看一个快速的例子。
# import pandas module as pd
import pandas as pd
# create date object using to_datetime() function
date = pd.to_datetime("8th of sep, 2019")
print(date)
2019-09-08 00:00:00
请注意,即使我们给了一个带有一些复杂因素的字符串,如 "th "和 "sep",而不是 "Sep. "或 "Sept.",pandas 也能正确地解析这个字符串并返回一个格式化的日期。
我们还可以使用pandas(和它的一些附属的numpy功能)自动创建日期范围作为pandas系列。下面,例如,我们从上面定义的日期开始创建一个12个日期系列。然后我们使用 pd.date_range()创建一个不同的日期系列,从预定义的日期开始。
# Create date series using numpy and to_timedelta() function
date_series = date + pd.to_timedelta(np.arange(12), 'D')
print(date_series)
# Create date series using date_range() function
date_series = pd.date_range('08/10/2019', periods = 12, freq ='D')
print(date_series)
DatetimeIndex(['2019-09-08', '2019-09-09', '2019-09-10', '2019-09-11', '2019-09-12', '2019-09-13', '2019-09-14', '2019-09-15', '2019-09-16', '2019-09-17', '2019-09-18', '2019-09-19'], dtype='datetime64[ns]', freq=None) DatetimeIndex(['2019-08-10', '2019-08-11', '2019-08-12', '2019-08-13', '2019-08-14', '2019-08-15', '2019-08-16', '2019-08-17', '2019-08-18', '2019-08-19', '2019-08-20', '2019-08-21'], dtype='datetime64[ns]', freq='D')
获取pandas中的年、月、日、时、分
我们可以使用 dt 属性轻松地从 pandas 数据框架中所有列的日期中获取年、月、日、时或分。例如,我们可以使用 df['date'].dt.year 来提取包含完整日期的 pandas 列中的年份。
为了探索这个问题,让我们用上面创建的一个系列来做一个快速的DataFrame。
# Create a DataFrame with one column date
df = pd.DataFrame()
df['date'] = date_series df.head()
image.png
现在,让我们使用相关的 Python datetime (用 dt 访问) 属性为日期的每个元素创建单独的列。
# Extract year, month, day, hour, and minute. Assign all these date component to new column.
df['year'] = df['date'].dt.year
df['month'] = df['date'].dt.month
df['day'] = df['date'].dt.day
df['hour'] = df['date'].dt.hour
df['minute'] = df['date'].dt.minute
df.head()
image.png
获取 Weekday 和 Day of Year
Pandas还能够从其日期时间对象中获取其他元素,如星期和年月日。同样,我们可以使用 dt 属性来实现这个功能。请注意,这里和 Python 中一样,一般来说,一周从周一开始,索引为 0,所以第 5 周的日子是星期六。
# get Weekday and Day of Year. Assign all these date component to new column.
df['weekday'] = df['date'].dt.weekday
df['day_name'] = df['date'].dt.weekday_name
df['dayofyear'] = df['date'].dt.dayofyear
df.head()
image.png
将日期对象转换为 DataFrame 索引
我们还可以使用pandas将datetime列做成DataFrame的索引。这对于探索性数据可视化等任务非常有帮助,因为matplotlib会识别出DataFrame的索引是一个时间序列,并相应地绘制出数据。
要做到这一点,我们要做的就是重新定义 df.index。
# Assign date column to dataframe index
df.index = df.date
df.head()
image.png
结论
在本教程中,我们深入学习了Python的datetime,同时也做了一些关于pandas和日历模块的工作。我们已经涵盖了很多内容,但请记住:学习一些东西的最好方法就是自己动手写代码!
网友评论