Files
my_wiki/raw/量化/abuquant-src/abupy/UtilBu/ABuDateUtil.py
T

296 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- encoding:utf-8 -*-
"""
时间日期工具模块
"""
from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
import datetime
import time
from datetime import datetime as dt
from ..CoreBu.ABuFixes import six
# noinspection PyUnresolvedReferences
from ..CoreBu.ABuFixes import filter
try:
# 如果有安装dateutil使用relativedelta as timedelta
from dateutil.relativedelta import relativedelta as timedelta
except ImportError:
# 没有安装dateutil使用datetime.timedelta
from datetime import timedelta
__author__ = '阿布'
__weixin__ = 'abu_quant'
"""默认的时间日期格式,项目中金融时间序列等时间相关默认格式"""
K_DEFAULT_DT_FMT = "%Y-%m-%d"
def str_to_datetime(date_str, fmt=K_DEFAULT_DT_FMT, fix=True):
"""
将字符串日期格式转换成datetime.datetime对象 eg. '2016-01-01' > datetime.datetime(2016, 1, 1, 0, 0)
:param date_str: %Y-%m-%d 形式str对象,eg. '2016-01-01'
:param fmt: 如date_str不是%Y-%m-%d形式,对应的格式str对象
:param fix: 是否修复日期不规范的写法,eg. 2016-1-1 fix 2016-01-01
:return: datetime.datetime对象,eg. datetime.datetime(2016, 1, 1, 0, 0)
"""
if fix and fmt == K_DEFAULT_DT_FMT:
# 只针对%Y-%m-%d形式格式标准化日期格式
date_str = fix_date(date_str)
return dt.strptime(date_str, fmt)
def str_to_datetime_fast(date_str, split='-', fix=True):
"""
不使用datetime api直接进行字符串分解,相对str_to_datetime要快很多,大概2倍的时间,大量时间转换,且格式确定使用
将字符串日期格式转换成datetime.datetime对象 eg. '2016-01-01' > datetime.datetime(2016, 1, 1, 0, 0)
:param date_str: 如date_str不是%Y-%m-%d形式,对应的格式str对象
:param split: 年月日的分割符,默认'-'
:param fix: 是否修复日期不规范的写法,eg. 2016-1-1 fix 2016-01-01
:return: datetime.datetime对象,eg. datetime.datetime(2016, 1, 1, 0, 0)
"""
if fix and split == '-':
# 只针对%Y-%m-%d形式格式标准化日期格式
date_str = fix_date(date_str)
y, m, d = date_str.split(split)
return dt(int(y), int(m), int(d))
def datetime_to_str(dt_obj):
"""
datetime时间转换为str对象, str_to_datetime函数的逆向
:param dt_obj: datetime.datetime对象
:return: str对象 eg. '2016-01-01'
"""
return str(dt_obj.date())[:10]
def timestamp_to_str(ts):
"""
针对pandas.tslib.Timestamp对象,即金融时间序列index元素对象转换为str对象, 时间单位只取到天,返回如2016-01-01
:param ts: pandas.tslib.Timestamp对象,eg. Timestamp('2016-01-01 00:00:00')
:return: 回如2016-0101 str对象
"""
try:
# pandas高版本to_pydatetime
s_date = str(ts.to_pydatetime().date())[:10]
except:
# pandas低版本to_datetime
s_date = str(ts.to_datetime().date())[:10]
return s_date
def date_str_to_int(date_str, split='-', fix=True):
"""
eg. 2016-01-01 -> 20160101
不使用时间api,直接进行字符串解析,执行效率高
:param date_str: %Y-%m-%d形式时间str对象
:param split: 年月日的分割符,默认'-'
:param fix: 是否修复日期不规范的写法,eg. 2016-1-1 fix 2016-01-01
:return: int类型时间
"""
if fix and split == '-':
# 只针对%Y-%m-%d形式格式标准化日期格式
date_str = fix_date(date_str)
string_date = date_str.replace(split, '')
return int(string_date)
def fix_date(date_str):
"""
修复日期不规范的写法:
eg. 2016-1-1 fix 2016-01-01
eg. 2016:01-01 fix 2016-01-01
eg. 2016,01 01 fix 2016-01-01
eg. 2016/01-01 fix 2016-01-01
eg. 2016/01/01 fix 2016-01-01
eg. 2016/1/1 fix 2016-01-01
eg. 2016:1:1 fix 2016-01-01
eg. 2016 1 1 fix 2016-01-01
eg. 2016 01 01 fix 2016-01-01
.............................
不使用时间api,直接进行字符串解析,执行效率高,注意fix_date内部会使用fmt_date
:param date_str: 检测需要修复的日期str对象或者int对象
:return: 修复了的日期str对象
"""
if date_str is not None:
# 如果是字符串先统一把除了数字之外的都干掉,变成干净的数字串
if isinstance(date_str, six.string_types):
# eg, 2016:01-01, 201601-01, 2016,01 01, 2016/01-01 -> 20160101
date_str = ''.join(list(filter(lambda c: c.isdigit(), date_str)))
# 再统一确定%Y-%m-%d形式
date_str = fmt_date(date_str)
y, m, d = date_str.split('-')
if len(m) == 1:
# 月上补0
m = '0{}'.format(m)
if len(d) == 1:
# 日上补0
d = '0{}'.format(d)
date_str = "%s-%s-%s" % (y, m, d)
return date_str
def fmt_date(convert_date):
"""
将时间格式如20160101转换为2016-01-01日期格式, 注意没有对如 201611
这样的做fix适配,外部需要明确知道参数的格式,针对特定格式,不使用时间api,
直接进行字符串解析,执行效率高
:param convert_date: 时间格式如20160101所示,int类型或者str类型对象
:return: %Y-%m-%d日期格式str类型对象
"""
if isinstance(convert_date, float):
# float先转换int
convert_date = int(convert_date)
convert_date = str(convert_date)
if len(convert_date) > 8 and convert_date.startswith('20'):
# eg '20160310000000000'
convert_date = convert_date[:8]
if '-' not in convert_date:
if len(convert_date) == 8:
# 20160101 to 2016-01-01
convert_date = "%s-%s-%s" % (convert_date[0:4],
convert_date[4:6], convert_date[6:8])
elif len(convert_date) == 6:
# 201611 to 2016-01-01
convert_date = "%s-0%s-0%s" % (convert_date[0:4],
convert_date[4:5], convert_date[5:6])
else:
raise ValueError('fmt_date: convert_date fmt error {}'.format(convert_date))
return convert_date
def diff(start_date, end_date, check_order=True):
"""
对两个输入日期计算间隔的天数,如果check_order=False, str日期对象效率最高
:param start_date: str对象或者int对象,如果check_order=True int对象效率最高
:param end_date: str对象或者int对象,如果check_order=True int对象效率最高
:param check_order: 是否纠正参数顺序是否放置正常,默认check
:return:
"""
# 首先进来的date都格式化,主要进行的是fix操作,不管是int还是str,这样20160101转换为2016-01-01日期格式
start_date = fix_date(start_date)
end_date = fix_date(end_date)
if check_order and isinstance(start_date, six.string_types):
# start_date字符串的日期格式转换为int
start_date = date_str_to_int(start_date)
if check_order and isinstance(end_date, six.string_types):
# end_date字符串的日期格式转换为int
end_date = date_str_to_int(end_date)
# 是否纠正参数顺序是否放置正常,默认check
if check_order and start_date > end_date:
# start_date > end_date说明要换一下
tmp = end_date
end_date = start_date
start_date = tmp
# fmt_date,但在不需要纠正check_order的情况,这些就都不会执行
if isinstance(start_date, int):
# noinspection PyTypeChecker
start_date = fmt_date(start_date)
if isinstance(end_date, int):
# noinspection PyTypeChecker
end_date = fmt_date(end_date)
# 在不需要纠正check_order的情况, 直接执行的是这里
sd = str_to_datetime(start_date)
ed = str_to_datetime(end_date)
return (ed - sd).days
def current_date_int():
"""
获取当前时间日期 int值
不使用时间api,直接进行字符串解析,执行效率高
:return: 日期int值
"""
date_int = 0
# 首先获取str
today = current_str_date()
# 手动比系统a时间pi快
today_array = today.split("-")
if len(today_array) == 3:
date_int = int(today_array[0]) * 10000 + int(today_array[1]) * 100 + int(today_array[2])
return date_int
def current_str_date():
"""
获取当前时间日期,时间单位只取到天,返回如2016-01-01
:return: 返回如2016-0101 str对象
"""
return str(datetime.date.today())
def week_of_date(date_str, fmt=K_DEFAULT_DT_FMT, fix=True):
"""
输入'2016-01-01' 转换为星期几,返回int 0-6分别代表周一到周日
:param date_str: 式时间日期str对象
:param fmt: 如date_str不是%Y-%m-%d形式,对应的格式str对象
:param fix: 是否修复日期不规范的写法,eg. 2016-1-1 fix 2016-01-01
:return: 返回int 0-6分别代表周一到周日
"""
if fix and fmt == K_DEFAULT_DT_FMT:
# 只针对%Y-%m-%d形式格式标准化日期格式
date_str = fix_date(date_str)
return dt.strptime(date_str, fmt).weekday()
def begin_date(pre_days, date_str=None, split='-', fix=True):
"""
返回date_str日期前pre_days天的日期str对象
eg:
pre_days = 2
date_str = '2017-02-14'
result = '2017-02-12'
pre_days = 365
date_str = '2016-01-01'
result = '2015-01-01'
如果pre_days是负数,则时间向前推:
eg:
pre_days = -365
date_str = '2016-01-01'
result = '2016-12-31'
:param pre_days: pre_days天, int
:param date_str: date_str, 默认current_str_date()
:param split:
:param fix: 是否修复日期不规范的写法,eg. 2016-1-1 fix 2016-01-01
:return: str日期时间对象
"""
if date_str is None:
date_str = current_str_date()
# 如果取current_str_date就没有必要fix了
fix = False
dt_time = str_to_datetime_fast(date_str, split=split, fix=fix)
return str(dt_time + timedelta(days=-pre_days))[:10]
def time_seconds():
"""
获取当前时间seconds级计时值
:return: float值 eg. 1498381468.38095
"""
return time.time()
def time_zone():
"""返回时区int值"""
return time.timezone