Python中的时间格式(1):详细版

时间格式是一类较特殊也十分普遍的格式,大量数据都含有时间信息,在实际的学习中会经常接触。最近有创建、处理或转换时间序列数据的需求,因此做一个梳理并汇总以便在后续遇到相关处理时可以拿来即用,还有另一个简化的速查版。本文主要涉及内容:

  1. python内置模块timedatetime的时间格式及处理
  2. Pandas时间格式的表达及常规处理

主要参考

不论是Python的内置模块还是第三方提供的模块,官网的文档都是很好的学习资源,尤其是想要了解地更深的时候或者debug的时候,

  • https://strftime.org/

Python官方文档

NumPy

Pandas,pandas主要处理表格型数据,因此实际中数据以时间序列存在

涉及Python模块和类、实例、属性及方法相关相关的概念可查阅此文Python中的类

!在实际中最常用的其实一般是datetime的部分功能(如下),此文将各模块功能列出,便于检索

1
2
import time
from datetime import datetime

内置模块time

表达格式

  1. 数字 <'float'>,Unix时间戳:从epoch(1970年1月1日00:00:00 UTC)经过的秒数/偏移量,如631123200000表示"1990-01-01 00:00:00"

  2. 时间元组 < 'time.struct_time'>(实际实现,给计算机看的)包含了一个时间的完整信息

    • time.struct_time(tm_year=2022, tm_mon=5, tm_mday=11, tm_hour=2, tm_min=53, tm_sec=2, tm_wday=2, tm_yday=131, tm_isdst=0)
  3. 字符串 <'str'>(可读性强,给人看的):如"1990-01-01 00:00:00","2018-01-01","1998/01/01"等

时间获取

1
2
3
4
5
6
7
8
9
10
11
12
13
# print("获取计算机当前时间时间:{0},数据类型:{1}".format(t, type(t)))
import time
t = time.time()
# 1652701116.7288237,数据类型: <class 'float'>

t = time.ctime()
# Mon May 16 19:38:36 2022,数据类型:<class 'str'>

t = time.gmtime()
# time.struct_time(tm_year=2022, tm_mon=5, tm_mday=16, tm_hour=11, tm_min=38, tm_sec=36, tm_wday=0, tm_yday=136, tm_isdst=0),数据类型:<class 'time.struct_time'>

t = time.localtime() #逆操作time.mktime():可以将数字转换成元组
#同上 time.struct_time(tm..

单个时间转换(strftime()+strptime())

将时间元组转换为格式化字符串

1
2
t_struct = time.gmtime() #创建时间元组
t_string = time.strftime("%Y-%m-%d %H:%M:%S", t_struct)

将字符串转换为时间元组

1
2
t_string = '2022-05-16 13:16:15'
t_struct = time.strptime(t_string,"%Y-%m-%d %H:%M:%S")

所有格式化参数可以在此页面查找strftime() 常用的如下(注意区分大小写):

  • %Y %m %d: 2022-05-01, %Y %-m %-d: 2022-5-1,
  • %H %M %S: 05:01:08, %-H %-M %-S: 5:1:8,
  • %x:'05/11/22',
  • %X:''02:49:06',
  • %c: 'Wed May 11 02:49:36 2022'
  • %a: Sun, %A: Sunday, %W:0-6,weekday
  • %b: Jan, %B: January,
  • ...
  • %z: UTC offset in the form +HHMM or -HHMM. "%z %Z":'+0800 中国标准时间'
  • %j: 001, 002, ..., 366,
  • %U %W:周数,一年的第多少周,前者表示周日为第一天

其他函数

1
2
3
4
5
6
7
8
9
10
# 脚本运行时间计算
import time
start_time = time.time()
main()#需要计时的代码
end_time = time.time()
print('脚本运行总时长:{:.2f} min'.format((end_time-start_time)/60))
print('脚本运行总时长:{:.2f} h'.format((end_time-start_time)/3600))

# 代码停顿3秒
time.sleep(3)

🔥内置模块datetime

time较为底层,一般用的不多,其他实际中主要用datetime datetime是基于time包开发的包,datetime可以拆解为date和time两个部分。可以将这两个分开管理(datetime.date类,datetime.time类),也可以将两者合在一起(datetime.datetime类),datetime包还定义了时间间隔对象(timedelta)。

子类/对象

类,这些类可以直接通过"属性"进行实例化对象,如datetime.date(2022, 5, 20)

  • datetime.time:独立于任何特定日期的理想化时间,包含属性: hour, minute, second, microsecond 和 tzinfo。
    • 属性的意思表明可以通过 .month .hour获取对象实例的属性值
  • datetime.date: 理想化的简单型日期, 属性: year, month, and day
  • datetime.datetime: 日期和时间的结合。属性:year, month, day, hour, minute, second, microsecond, and tzinfo.
  • datetime.timedelta:表示两个 date 对象或 time 对象,或者 datetime 对象之间的时间间隔,精确到微秒。
    • 常用于时间之间的加减等操做
  • datetime.tzinfo:时区信息对象
  • datetime.timezone:表示相对于UTC的偏移量

这些类创建实例的共有属性

  1. 不可变
  2. 可哈希,即可以作为字典的键key
  3. 支持通过pickle模块进行高效封存,惯用pickle可以为实际工作带来诸多便利,见pickle使用-待更新
  4. 支持加减法,且涉及时间间隔及时间差等可以通过timedelta进行运算

date常用操作

time的操作与之类似

获取/创建时间

1
2
3
4
5
6
from datetime import date, timedelta
today = date.today() #输出 datetime.date(2022, 5, 16)
year, month = today.year, today.month

my_birthday = date(1998, 1, 1)
time_to_birthday = abs(my_birthday - today) # datetime.timedelta(days=8901)

UTC时间转北京时间:time_bj = time_utc+ timedelta(hours=8)

日期与字符串格式的转换

将时间date转换为格式化字符串

1
2
3
4
from datetime import date
t1 = date(2022, 1, 1)
# ISO 8601 格式 YYYY-MM-DD
t_string = date.isoformat(t1) #'2022-01-01'

将字符串转换为日期date

1
2
t1 = '2022-01-01'
t_date = date.fromisoformat(t1) #输出datetime.date(2022, 1, 1)
  • 其他方法,时间替换date.replace(year=self.year, month=self.month, day=self.day)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    d = date(2022, 12, 31)
    # 时间替换
    d2 = d.replace(day=26)
    #返回一个 time.struct_time
    d3 = date.timetuple(d)
    # 获取当前时间的字符串格式
    t = date.today()
    t.ctime()# 等价于`time.ctime(time.mktime(d.timetuple()))`
    #输出'Mon May 16 00:00:00 2022'

🔥datetime常用操作

获取/创建时间

1
2
3
4
5
6
7
8
9
from datetime import datetime, date, time, timezone
datetime.now()
datetime.now(timezone.utc)
# 年月日等属性获取,date()
t = datetime.now()
year,month, udate = t.year, t.month, t.date()
#输出
# datetime.datetime(2022, 5, 16, 21, 10, 32, 304773)
# datetime.datetime(2022, 5, 16, 13, 10, 32, 306332, tzinfo=datetime.timezone.utc)

时间合并

1
2
3
4
from datetime import datetime, date, time
d = date(2022, 5, 12)
t = time(1, 18)
dt = datetime.combine(d, t)

时间与字符串的转换,参数与time模块类似

1
2
3
4
# 字符串转时间
dt = datetime.strptime("21/11/06 16:30", "%d/%m/%y %H:%M")
# 时间转字符串
t_str = dt.strftime("%Y-%m-%d %H:%M")

Pandas中的时间格式

pandas为表格,因此处理的一般为时间序列而非单个时间

pandas中的时间格式主要为以下两类

  • datetime (datetime64[ns]), 类比datetime
  • String/Object

创建序列

pd.date_range()

  • pandas.date_range(start=None, end=None, periods=None, freq=None, tz=None, normalize=False, name=None, ...)文档
  • 参数说明
    • start end:起始日期
    • periods:日期数量
    • freq: 间隔,默认D,可以设M,8H详见
    • inclusive:='both','left','right','neither'指定左右是否闭合,如生成某月份数据但不知道该月多少天,可以指定为left,右边写下月第一天

常用代码

1
2
3
4
5
6
7
8
9
# 创建序列, 可以直接接收
# 默认都是ISO 8601 格式 YYYY-MM-DD, '2018-01-01 03:00:00'
df['time'] = pd.date_range(start='1/1/2018', end='1/08/2018', freq='D') #8天
pd.date_range(start='1/1/2018', end='1/08/2018') #8天
pd.date_range(start='1/1/2018', periods=8) #8天
pd.date_range(start='1/1/2018', periods=8, freq='2M') #8天,两天之间间隔为两个月
pd.date_range(start='2018-01-01', end='2018-02-01', freq='3H')
pd.date_range(start='2017-01-01', end='2017-02-01', closed='left') #创建指定月份的日期范围pandas<1.4版本
pd.date_range(start='2017-01-01', end='2017-02-01', inclusive='left') #创建指定月份的日期范围pandas>1.4版本

🔥时间序列格式转换

datetime→string:astype()+strftime(),输入的列为datetime64[ns]类型

1
2
3
4
# astype()
df['time_str']=df['time'].astype(str)
# strftime()
df['time_str'] = df['time'].dt.strftime('%m/%d/%Y')

string→datetime: to_datetime,输入的列为String或Object类型

1
df['time']=pd.to_datetime(df['time_str'].astype(str), format='%Y/%m/%d')

时间合并与拆分

这里pd.to_datetime函数比较憨,只能识别指定的列名,所以如果不一致需要先改名

1
2
3
4
5
6
7
8
9
10
11
# 合并
df = pd.DataFrame({'year': [2015, 2016],'month': [2, 3],'day': [4, 5],'hour':[10,20]})
# 不一致需要改名再合并,比如
# df.rename(columns = {'Year':'year','Mon':'month','Day':'day'}, inplace=True)
df['date'] = pd.to_datetime(df[['year','month','day']])
df['datetime'] = pd.to_datetime(df.date) + pd.to_timedelta(df.hour, unit='h')

#拆分/转换示例
df['day2'] = df['time'].dt.strftime('%D')
df['hour2'] = df['time'].dt.strftime('%H')
df['date2'] = df['time'].dt.strftime('%x')

基于时间筛选数据

&与;|

1
2
3
4
5
# df['time']为时间格式:
df2 = df.loc[(df.time > pd.datetime(2017,8,23,0)) & (df.time < pd.datetime(2017,8,27,0))]
df2 = df.loc[(df.time < pd.datetime(2017,8,23,0)) | (df.time > pd.datetime(2017,8,27,0))]
# df['time']为字符串:
df2 = df.loc[(df.time > '2017-08-20 00:00:00') & (df.time < '2017-08-26 00:00:00')]

其他操作

待补充 ……

有了以上的基础,在实际中可以灵活按需涉及方案排列组合等实现想要的结果……