Jimmy那些事儿

Python_日期处理

日期与时间

datetime表示的时间需要时区信息才能确定一个特定的时间,否则只能视为本地时间。

如果要存储datetime,最佳方法是将其转换为timestamp再存储,因为timestamp的值与时区完全无关。

Python中关于时间、日期的处理库有三个:time、datetime和Calendar。

  • datetime又有datetime.date、datetime.time、datetime.datetime三个类
  • 时间又可以分为时间戳、本地时间和UTC时间(世界标准时间)

from time import time

from datetime import datetime


时间序列的几种内容

  • 时间戳 (timestamp),特定的时刻
  • 固定时期 (period),如2017年1月或2017年全年
  • 时间间隔 (internal) ,由起始时间和结束时间戳表示。时期 (period) 可以看做间隔的一个特例


datetime模块

datetime是Python处理日期和时间的标准库。

from datetime import datetime

datetime模块。该模块中包含4个主要的类:

  • datetime.date:日期类,只包含年、月、日、星期等日期信息。
  • datetime.time:时间类,只包含时、分、秒、微秒等时间信息。
  • datetime.datetime:日期时间类,包含以上两者的全部信息。
  • datetime.timedelta:时间日期差值类,用来表示两个datetime之间的差值(日、秒、毫秒)。
1
2
3
4
5
6
7
8
> # 获取当前时间
> >>> from datetime import datetime
> >>> now = datetime.now() # 获取当前datetime
> >>> print(now)
> 2015-05-18 16:28:07.198690
> >>> print(type(now))
> <class 'datetime.datetime'>
>

>

注意到datetime是模块,datetime模块还包含一个datetime类,通过from datetime import datetime导入的才是datetime这个类。

如果仅导入import datetime,则必须引用全名datetime.datetime

datetime.now()返回当前日期和时间,其类型是datetime


时间获取

  • datetime.datetime.now():获取当前日期与时间
  • datetime.datetime(2012, 1, 12):获取指定日期与时间


####指定部分

  • datetime.year : 获取日期与时间的指定部分

    • datetime.year

    • datetime.month

  • datetime.day
  • datetime.hour
  • datetime.minute
  • datetime.second
  • datetime.microsecond In range(1000000)
  • datetime.date():获得日期部分

    • datetime.time()
    • datetime.weekday():将星期几作为整数返回,其中星期一为0,星期日为6
    • datetime.isoweek():将星期几作为整数返回,星期一为1,星期日为7

字符串转换

  • datetime.strftime( format ) :时间转为字符串 f:表示from
    • strftime() 用来格式化 datetime对象

format : ‘%Y-%M-%D %H:%M:%S’

1
2
3
4
5
6
# datetime.datetime类型转字符串
print(a_datetime_local.strftime("%Y-%m-%d, %H:%M:%S, %w"))
# 字符串转datetime.datetime格式
a_datetime = datetime.datetime.strptime("2016-11-15, 15:32:12, 2", "%Y-%m-%d, %H:%M:%S, %w")
  • datetime.strptime( ‘date_string’, ‘%Y-%M-%D’):字符串转为时间格式
    • datetime.strptime 是通过已知的格式进行日期解析的方式。但每次都必须要编写格式定义。


  • parser.parse(‘str’ ,dayfirst =True):可以解析几乎所有人类能够理解的日期表示形式(中文除外)
    • 对于常见的日期格式,可以使用dateutil 第三方包中的 parser.parse 方法
    • 注意:它并不是一个完美的工具;因为会把一些原本不是日期的字符串认作是日期(比如 “42”会被解析为2042年的今天)

dayfirst =True ,将日期显示在最前面;因为国际通用格式中,日通常排在月的前面。

1
2
3
4
from dateutil.parser import parse
parse('2011-03-11')
[out]:datetime.datetime(2011, 3, 11, 0, 0)


timedelta对象 + 加减

datetime.timedelta 表示两个datetime之间的时间差。

给datetime对象加上一个或多个 timedelta,会产生一个新的对象;

  • now + timedelta(days=n, hours=m):在原有基础上加减日期

    • 对日期和时间进行加减实际上就是把datetime往后或往前计算,得到新的datetime。加减可以直接用+-运算符,不过需要导入timedelta这个类:

years
months
days
hours
minutes
seconds

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 日期加减
from datetime import timedelta
start = datetime(2011,1,7)
start + timedelta(12)
[out]:datetime.datetime(2011, 1, 19, 0, 0)
# 返回间隔
delta = datetime(2011, 1, 7) - datetime(2008, 6, 24)
delta
[out]:datetime.timedelta(927)
delta.days
[out]:927


time模块

在time模块中,时间有三种表现形式:

  • 时间戳,一般指Unix时间戳,是从1970年开始到现在的秒数。
    • 1970年以前的时间timestamp为负数
  • 本地时间的struct_time形式:一个长度为11的命名元组,第一位为年,第二位为月….
  • UTC时间的struct_time形式:一个长度为11的命名元组,类似于上个,只不过为UTC时间

其中后两者的类型一致,区别在于一个是本地时间(localtime),一个是utc时间。


时间获取

1
2
3
4
5
6
7
8
9
10
# 时间戳:1479193181.829338
print("time stamp:", time.time())
# struct_time类型的本地时间
print("local time:", time.localtime())
time.struct_time(tm_year=2016, tm_mon=11, tm_mday=15, tm_hour=14, tm_min=59, tm_sec=41, tm_wday=1, tm_yday=320, tm_isdst=0)
# struct_time类型的utc时间
print("utc time:", time.gmtime())
time.struct_time(tm_year=2016, tm_mon=11, tm_mday=15, tm_hour=6, tm_min=59, tm_sec=41, tm_wday=1, tm_yday=320, tm_isdst=0)


字符串转换

  • time.strptime():字符串转为时间格式
  • time.strftime():时间格式转为字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 时间戳转字符串(本地时间字符串)
print(time.ctime(time_stamp))
# struct_time类型的本地时间转字符串
print(time.asctime(local_time))
# struct_time类型的utc时间转字符串
print(time.asctime(utc_time))
# struct_time类型的本地时间转字符串:自定义格式
print(time.strftime("%Y-%m-%d, %H:%M:%S, %w", local_time))
# struct_time类型的utc时间转字符串:自定义格式
print(time.strftime("%Y-%m-%d, %H:%M:%S, %w", utc_time))
struct_time = time.strptime("2016-11-15, 15:32:12, 2", "%Y-%m-%d, %H:%M:%S, %w")


img



datetime 与 timestamp转换

在计算机中,时间实际上是用数字表示的。我们把1970年1月1日 00:00:00 UTC+00:00时区的时刻称为epoch time,记为0(1970年以前的时间timestamp为负数),当前时间就是相对于epoch time的秒数,称为timestamp

1
2
3
4
5
# 可以认为
timestamp = 0 = 1970-1-1 00:00:00 UTC+0:00
# 对应的北京时间是:
timestamp = 0 = 1970-1-1 08:00:00 UTC+8:00

可见timestamp的值与时区毫无关系,因为timestamp一旦确定,其UTC时间就确定了,转换到任意时区的时间也是完全确定的,这就是为什么计算机存储的当前时间是以timestamp表示的,因为全球各地的计算机在任意时刻的timestamp都是完全相同的(假定时间已校准)。


datetime 转 timestamp

  • dt.timestamp():把datetime对象转化为timestamp
1
2
3
4
>>> from datetime import datetime
>>> dt = datetime(2015, 4, 19, 12, 20) # 用指定日期时间创建datetime
>>> dt.timestamp() # 把datetime转换为timestamp
1429417200.0


timestamp 转 datetime

  • datetime.fromtimestamp(t):从timestamp 转为datetime(本地时间)
    • 注意到timestamp是一个浮点数,它没有时区的概念,而datetime是有时区的。上述转换是在timestamp和本地时间做转换。
  • datetime. utcfromstimestamp(t):从timestamp 转为datetime(UTC时间)
1
2
3
4
5
6
7
>>> from datetime import datetime
>>> t = 1429417200.0
>>> print(datetime.fromtimestamp(t)) # 本地时间
2015-04-19 12:20:00
>>> print(datetime.utcfromtimestamp(t)) # UTC时间
2015-04-19 04:20:00

类型和时间戳、struct_time类型的相互转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# datetime类型转时间戳
time_stamp = a_datetime_local.timestamp()
print(time_stamp)
# 时间戳转datetime.datetime类型的本地时间
a_datetime_local = datetime.datetime.fromtimestamp(time.time())
a_datetime_utc = datetime.datetime.utcfromtimestamp(time.time()) # 时间戳转datetime.datetime类型的utc时间
print(a_datetime_local, a_datetime_utc)
# datetime类型转struct_time类型
print(a_datetime_local.timetuple())
print(a_datetime_utc.utctimetuple()) # datetime类型转struct_time类型


img


时区

本地时间转UTC时间

本地时间是指系统设定时区的时间,例如北京时间是UTC+8:00时区的时间,而UTC时间指UTC+0:00时区的时间。

一个datetime类型有一个时区属性tzinfo,但是默认为None,所以无法区分这个datetime到底是哪个时区,除非强行给datetime设置一个时区:

1
2
3
4
5
6
7
8
>>> from datetime import datetime, timedelta, timezone
>>> tz_utc_8 = timezone(timedelta(hours=8)) # 创建时区UTC+8:00
>>> now = datetime.now()
>>> now
datetime.datetime(2015, 5, 18, 17, 2, 10, 871012)
>>> dt = now.replace(tzinfo=tz_utc_8) # 强制设置为UTC+8:00
>>> dt
datetime.datetime(2015, 5, 18, 17, 2, 10, 871012, tzinfo=datetime.timezone(datetime.timedelta(0, 28800)))


时区转换

  • utcnow():获取当前的UTC时间
  • 时区转换的关键在于,拿到一个datetime时,要获知其正确的时区,然后强制设置时区,作为基准时间。
  • 利用带时区的datetime,通过astimezone()方法,可以转换到任意时区。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 拿到UTC时间,并强制设置时区为UTC+0:00:
>>> utc_dt = datetime.utcnow().replace(tzinfo=timezone.utc)
>>> print(utc_dt)
2015-05-18 09:05:12.377316+00:00
# astimezone()将转换时区为北京时间:
>>> bj_dt = utc_dt.astimezone(timezone(timedelta(hours=8)))
>>> print(bj_dt)
2015-05-18 17:05:12.377316+08:00
# astimezone()将转换时区为东京时间:
>>> tokyo_dt = utc_dt.astimezone(timezone(timedelta(hours=9)))
>>> print(tokyo_dt)
2015-05-18 18:05:12.377316+09:00
# astimezone()将bj_dt转换时区为东京时间:
>>> tokyo_dt2 = bj_dt.astimezone(timezone(timedelta(hours=9)))
>>> print(tokyo_dt2)
2015-05-18 18:05:12.377316+09:00

注:不是必须从UTC+0:00时区转换到其他时区,任何带时区的datetime都可以正确转换,例如上述bj_dttokyo_dt的转换。


格式定义

datetime格式定义

代码 说明
%Y 4位数的年
%y 2位数的年
%m 2位数的月 [01, 12]
%d 2位数的日 [01, 31]
%F %Y-%m-%d 简写形式;2012-04-18
%D %m/%d/%y 简写形式;04/18/12
%H 时间(24小时制) [00, 23]
%I 时间(12小时制) [00, 12]
%M 2位数的分钟 [00, 59]
%S 秒 [00, 61] (秒60和61用于闰秒)
%w 用整数表示的星期几 (星期天为第0天) [0, 6]
%U 每年的第几周 [00, 53]。星期天被认为是每周的第一天,每年第一个星期天之前的那几天被认为是 “第0周”
%W 每年的第几周 [00, 53]。星期一被认为是每周的第一天,每年第一个星期一之前的那几天被认为是 “第0周”
%z 以+HHMM 或-HHMM 表示的UTC时区偏移量


特定于当前环境的日期格式

代码 说明
%a 星期几的简写
%A 星期几的全称
%b 月份的简写
%B 月份的全称
%c 完成的日期和时间;Tue 01 May 2012 04:20:57 pm
%p 不同环境中的AM 或PM
%x 适用于当前环境的日期格式 ;若在美国, “May 1 2012” 会产生 “05/01/2012”
%X 适用于当前环境的时间格式; “04:24:12 PM”


【实战演练】

输出为 月-日格式


时间序列

pandas最基本的时间序列类型就是以时间戳为索引的Series;

当创建一个带有DatatimeIndex 的Series时,pandas就会知道该对象是一个时间序列

索引是 时间格式的字段;