在数据科学和编程领域,处理日期和时间数据是一项极具挑战性的任务。这不仅涉及到不同的日期格式、时区差异、夏令时调整等复杂因素,还涉及到如何准确地引用特定的日期和时间。幸运的是,Python内置的datetime
模块为提供了强大的支持,帮助应对这些挑战。
为何日期和时间编程如此困难
编程处理日期和时间之所以困难,是因为计算机程序偏好有序且规律的事件处理方式,而人类使用日期和时间的方式往往是无序和不规则的。例如,美国和加拿大实行的夏令时就是一个典型的例子。他们在三月的第二个星期日将时钟向前调整一小时,在十一月的第一个星期日再向后调整一小时。
如果项目中需要考虑时区,情况可能会变得更加复杂。理想情况下,时区应该沿着经度线直线划分,但由于政治和历史原因,这些分界线很少是直线。
标准日期格式
不同文化使用不同的日期格式,如D M Y
或Y M D
或M D Y
。如果没有标准化的格式,将会造成混乱。因此,国际标准化组织(ISO)制定了ISO 8601
标准,定义了一个统一的格式以避免混淆。根据该格式,约定是从最重要的数字到最不重要的数字。因此,格式为:YYYY-MM-DD hh:mm:ss
。
计算机如何测量时间
大多数计算机从称为Unix纪元的任意瞬间开始计时。这个任意日期是1970年1月1日,UTC时间00:00:00。协调世界时(UTC)指的是0°经度的时间,也就是众所周知的GMT或格林尼治子午线时间。它不调整夏令时,因此每天始终保持24小时。
Unix时间以1970年1月1日以来的秒数来测量。可以用几行Python代码轻松查看当前的Unix时间。
>>> import datetime
>>> print(datetime.datetime.now().timestamp())
1620566182.766565
这意味着自1970年1月1日以来,已经过去了1620566182.766565秒,当写这篇博客的时候!这里有一个关于Unix时间的有趣事实。由于大多数旧操作系统是32位的,它们以32位有符号整数存储Unix时间。
如果熟悉Y2K问题
,就会知道这个问题的走向。以32位有符号整数格式存储意味着在2038年1月19日03:14:07,整数将溢出,导致所谓的2038年问题,或通常称为Y2038。为了避免对关键系统造成灾难性后果,这个问题需要尽快解决。
datetime模块
datetime
模块是Python内置的,因此无需单独安装。只需将其导入到代码中,就可以开始使用了。
该模块提供了不同的类来处理日期、时间和时间间隔。两个主要的对象是date
和datetime
。这些类有6种类型,这里是它们的官方描述:
datetime.date
:用于操作日期,不涉及时间。属性包括year
、month
和day
。datetime.time
:用于操作时间,不涉及日期,假设每天正好有24*3600秒。属性包括hour
、minute
、second
、microsecond
和tzinfo
。datetime.datetime
:用于操作日期和时间的组合。属性包括year
、month
、day
、hour
、minute
、second
、microsecond
和tzinfo
。datetime.timedelta
:两个日期、时间或datetime对象之间的持续时间,分辨率可达微秒。datetime.tzinfo
:这是一个抽象基类,用于时区对象。可以由datetime和time类使用,以提供可定制的时间调整概念(例如,考虑时区和/或夏令时)。datetime.timezone
:tzinfo抽象基类的实现。
可以在这里阅读更多关于这些类的深入信息。现在让开始编码吧!
创建DateTime对象
可以使用ISO格式创建一个datetime对象。
from datetime import datetime
a = datetime(2021, 5, 9, 13, 13, 6)
print(a)
# 输出: 2021-05-09 13:13:06
要获取当前日期:
today = datetime.now()
print(today)
# 输出: 2021-05-10 16:28:05
print(type(today))
# 输出: <class 'datetime.datetime'>
因此,today
确实是一个datetime对象。以下是datetime类的一些有用方法。
dt_nw = datetime.now()
# 从datetime获取小时
print('Hour: ', dt_nw.hour)
# 输出: Hour: 16
# 从datetime获取分钟
print('Minute: ', dt_nw.minute)
# 输出: Minute: 28
可以使用成员函数.weekday()
获取一周中的某一天的名称,然后使用另一个名为calendar
的模块将其转换为字符串格式(即星期一、星期二、星期三……)。首先,将导入Calendar模块,然后使用一些有用的操作。
import calendar
my_date = datetime.now()
# 从日期获取月份
print('Month: ', my_date.month)
# 输出: Month: 5
# 从日期获取年份
print('Year: ', my_date.year)
# 输出: Year: 2021
# 从日期获取月份中的一天
print('Day of Month:', my_date.day)
# 输出: Day of Month: 10
# 从日期获取一周中的某一天(数字)
print('Day of Week (number): ', my_date.weekday())
# 输出: Day of Week (number): 0
# 从日期获取一周中的某一天(名称)
print('Day of Week (name): ', calendar.day_name[my_date.weekday()])
# 输出: Day of Week (name): Monday
处理时区
Date和Time对象可以分为两大类,主要是“Aware”和“Naive”。简单来说,如果一个对象包含时区信息,它就是Aware的,否则就是Naive的。Aware对象如datetime、date和time有一个额外的可选属性,叫做tzinfo。但tzinfo本身是一个抽象类。要处理这些,需要确切知道需要哪些方法。处理时区问题可以通过pytz模块来简化。使用这个模块,可以处理使用夏令时的地点的夏令时,并进行跨时区转换。
from pytz import timezone
# 创建UTC时区
utc = timezone('UTC')
# 本地化日期和时间
loc = utc.localize(datetime(2020, 5, 10, 17, 41, 0))
print(loc)
# 输出: 2020-05-10 17:41:00+00:00
# 将本地化日期和时间转换为Asia/Dhaka时区
dhaka = timezone("Asia/Dhaka")
print(loc.astimezone(dhaka))
# 输出: 2020-05-10 23:41:00+06:00
# 将本地化日期和时间转换为Europe/Berlin时区
berlin = timezone('Europe/Berlin')
print(loc.astimezone(berlin))
# 输出: 2020-05-10 19:41:00+02:00
localize()
函数用于给datetime对象添加一个时区位置。astimezone()
函数用于将当前时区转换为其他指定的时区。
时间差或时间段
有时在编程时,需要找到某项任务的剩余时间,或指定某种时间段。这时timedelta
对象就派上用场了。在大多数科学术语中,delta意味着两个事物之间的差异。可以使用它来相互加减日期和时间。以下是如何操作的:
from datetime import timedelta
# 获取当前时间
now = datetime.now()
print("Today's date & time: ", str(now))
# 输出: Today's date & time: 2021-05-10 12:56:08.979894
# 在当前日期上加上365天
future_date_after_one_year = now + timedelta(days=365)
print('Date & time after one year: ', future_date_after_one_year)
# 输出: Date & time after one year: 2022-05-10 12:56:08.979894
# 从当前日期减去7天
seven_days_ago = now - timedelta(days=7)
print('Date & time seven days ago: ', seven_days_ago)
# 输出: Date & time seven days ago: 2021-05-03 12:56:08.979894
使用strftime()和strptime()格式化日期
datetime、date和time对象都支持strftime()方法,将对象转换为特定格式的字符串。相反的操作是使用datetime.strptime()方法,从字符串创建datetime对象。
from datetime import datetime
date_str = "10 May, 2021"
# 格式化日期
date_obj = datetime.strptime(date_str, "%d %B, %Y")
print("Today's date is: ", date_obj)
# 输出: Today's date is: 2021-05-10 00:00:00
# 当前日期和时间
now = datetime.now()
# 格式化时间为HH:MM:SS
time = now.strftime("%H:%M:%S")
print("Time:", time)
# 输出: Time: 14:05:55
# 格式化日期和时间
date_time = now.strftime("%m/%d/%Y, %H:%M:%S")
print("Date and Time:", date_time)
# 输出: Date and Time: 05/10/2021, 14:05:55
在处理时间数据或时间序列时,通常需要处理时间戳。可以使用datetime.timestamp()将数据存储为Unix时间戳格式。
# 获取当前日期
now = datetime.now()
# 将当前日期转换为时间戳
timestamp = datetime.timestamp(now)
print("Date and Time :", now)
# 输出: Date and Time : 2021-05-10 14:17:54.739358
print("Timestamp:", timestamp)
# 输出: Timestamp: 1620656274.739358
同样,可以从时间戳获取日期和时间对象:
timestamp = 1620656274.739358
# 将时间戳转换为datetime对象
date_obj = datetime.fromtimestamp(timestamp)
print("Today's date & time:", date_obj)
# 输出: Today's date & time: 2021-05-10 14:17:54.739358
Pandas可以被称为任何数据科学项目的支柱之一。它使得处理日期和时间对象变得更加容易。在处理DataFrame时,to_datetime()函数可以方便地将文本和字符串转换为Pythondatetime对象。
import pandas as pd
# 使用to_datetime()函数创建日期对象
date = pd.to_datetime("10th of May, 2021")
print(date)
# 输出: 2021-05-10 00:00:00