python⽣成时间序列(date_range)
介绍
⾃⼰写了⼀个⽤python内置模块实现的⽣成时间序列的函数
⽀持⾃动推断字符串到datetime的转换, 但对格式有⼀定要求, 其它格式可⼿动指定格式化⽅式, 格式化⽅式与python内置格式化格式完全⼀致⽀持输出格式化
以下是⽅法的源代码(python环境3.5以上, 没做更多版本的⽀持, 需要的⾃⼰稍作调整即可)
源代码
import re
import calendar
import datetime
class FormatError(ValueError):
pass
class Date(object):
@classmethod
def date_range(cls, start=None, end=None, periods=None, freq=None, input_format=None, out_format=None):
"""
⽣成时间序列
:param start: 序列开始时间
:param end: 序列结束时间, 给定start时, 结束时间不包含end
:param periods: int, ⽣成的时间序列长度
:param freq: 要⽣成时间序列的时间间隔
:param out_format: 是否输出格式化后的字符串, 若要输出可指定输出格式. "%Y-%m-%d %H:%M:%S"
:param input_format: 若start或end是字符串且⽆法⾃动推断时间格式则需指定格式
:return: [date or date_str]
"""
start = cls.str_to_date(start, input_format)
end = cls.str_to_date(end, input_format)
out = []
if start is None and end and periods:
for i in range(periods-1):
old, end = cls.date_replace(end, cls._freq(freq), mod="-")
if i == 0:
out.append(old)
out = [end] + out
elif end is None and start and periods:
for i in range(periods-1):
old, start = cls.date_replace(start, cls._freq(freq), mod="+")
if i == 0:
out.append(old)
out.append(start)
elif periods is None and start and end:
i = 0
while True:
old, start = cls.date_replace(start, cls._freq(freq), mod="+")
if i == 0:
out.append(old)
i += 1
if start < end:
out.append(start)
else:
break
else:
raise ValueError("start, end, periods 须且只能指定其中两个")
if out_format is True:
out = [str(i) for i in out]
elif out_format is not None:
out = [i.strftime(out_format) for i in out]
return out
@staticmethod
def date_replace(date, freq=(0, )*6, mod="+"):
timedelta = datetime.timedelta(days=freq[2], hours=freq[3], minutes=freq[4], seconds=freq[5])
if mod == "+":
if sum(freq[:2]) == 0:
old = date
date = date + timedelta
elif sum(freq[2:]) == 0:
y = ar + freq[0] + (h + freq[1] - 1) // 12
m = (h + freq[1] - 1) % 12 + 1
old = place(ar, h)[1])
date = place(year=y, month=m, hrange(y, m)[1])
else:
raise ValueError(" '年⽉' 不能同时和 '⽇时分秒' 作为间隔")
elif mod == "-":
if sum(freq[:2]) == 0:
old = date
date = date - timedelta
elif sum(freq[2:]) == 0:
y = ar - freq[0] + (h - freq[1] - 1) // 12
m = (h - freq[1] - 1) % 12 + 1
old = place(ar, h)[1])
date = place(year=y, month=m, hrange(y, m)[1])
else:
raise ValueError(" '年⽉' 不能同时和 '⽇时分秒' 作为间隔")
else:
raise ValueError("mod值只能是 '+' 或 '-' ")
return old, date
@staticmethod
def _freq(freq=None):
"""
设置时间间隔
:param freq: "Y2m3d4H5M6S" 表⽰间隔 1年2⽉3⽇4时5分6秒
:return: [年, ⽉, ⽇, 时, 分, 秒]
"""
freq_ = [0] * 6
if freq is None:
freq_[2] = 1
return freq_
for n, i in enumerate(["Y", "m", "d", "H", "M", "S"]):
r = f'((\d*){i})'
s = re.search(r, freq)
if s:
freq_[n] = up(2)) up(2) else 1
return freq_
@staticmethod
def str_to_date(string, format_=None):
"""
字符串转时间, 默认⾃动推断格式
:param string: 时间字符串
:param format_: 格式
:return: 对应的时间类型, 输⼊⾮字符串则原值输出
"""
if not isinstance(string, str):
return string
if format_:
return datetime.datetime.strptime(string, format_)
s = re.match(r'(\d{4})\D+(\d{1,2})\D+(\d{1,2})(?:\D+(\d{1,2}))?(?:\D+(\d{1,2}))?(?:\D+(\d{1,2}))?\D*$', string)
if s:
result = [int(i) for i ups() if i]
return datetime.datetime(*result)
s = re.match(r'(\d{4})\D*(\d{2})\D*(\d{2})\D*(\d{2})?\D*(\d{2})?\D*(\d{2})?\D*$', string)
if s:
result = [int(i) for i ups() if i]
return datetime.datetime(*result)
else:
raise FormatError("⾃动推断失败, 请指定format_")
使⽤⽅式
print(Date.date_range(datetime.datetime(2018, 9, 18), periods=10))
python格式化输出formatprint()
print(Date.date_range('20180918', '2018-09-28'))
print()
print(Date.date_range(end='20180927', periods=10))
print()
print(Date.date_range('20180918', '2018-09-28', out_format=True))
print()
print(Date.date_range('2018/09/18', '2018-09-28', out_format="%Y-%m-%d"))
print()
print(Date.date_range('2018年9⽉18⽇', '2019-09-28', freq="m", out_format="%Y-%m-%d"))
print()
print(Date.date_range('2018/9/18', '2018-9-19', freq="3H", out_format=True))
对应结果
[datetime.datetime(2018, 9, 18, 0, 0), datetime.datetime(2018, 9, 19, 0, 0), datetime.datetime(2018, 9, 20, 0, 0), datetime.datetime(2018, 9, 21, 0, 0), datetime.datetime(2018, 9, 22, 0, 0), datetime.datetime(2018, 9, 23, 0, 0), datetime.datetime(20 [datetime.datetime(2018, 9, 18, 0, 0), datetime.datetime(2018, 9, 19, 0, 0), datetime.datetime(2018, 9, 20, 0, 0), datetime.datetime(2018, 9, 21, 0, 0), datetime.datetime(2018, 9, 22, 0, 0), datetime.datetime(2018, 9, 23, 0, 0), datetime.datetime(20 [datetime.datetime(2018, 9, 18, 0, 0), datetime.datetime(2018, 9, 19, 0, 0), dat
etime.datetime(2018, 9, 20, 0, 0), datetime.datetime(2018, 9, 21, 0, 0), datetime.datetime(2018, 9, 22, 0, 0), datetime.datetime(2018, 9, 23, 0, 0), datetime.datetime(20 ['2018-09-18 00:00:00', '2018-09-19 00:00:00', '2018-09-20 00:00:00', '2018-09-21 00:00:00', '2018-09-22 00:00:00', '2018-09-23 00:00:00', '2018-09-24 00:00:00', '2018-09-25 00:00:00', '2018-09-26 00:00:00', '2018-09-27 00:00:00']
['2018-09-18', '2018-09-19', '2018-09-20', '2018-09-21', '2018-09-22', '2018-09-23', '2018-09-24', '2018-09-25', '2018-09-26', '2018-09-27']
['2018-09-30', '2018-10-31', '2018-11-30', '2018-12-31', '2019-01-31', '2019-02-28', '2019-03-31', '2019-04-30', '2019-05-31', '2019-06-30', '2019-07-31', '2019-08-31']
['2018-09-18 00:00:00', '2018-09-18 03:00:00', '2018-09-18 06:00:00', '2018-09-18 09:00:00', '2018-09-18 12:00:00', '2018-09-18 15:00:00', '2018-09-18 18:00:00', '2018-09-18 21:00:00']