|
|
import calendar
|
|
|
import datetime
|
|
|
import time
|
|
|
from typing import Any, Callable, Dict, Optional, TypeVar, Union
|
|
|
|
|
|
import tzlocal
|
|
|
from dateutil.relativedelta import relativedelta
|
|
|
from dateutil.tz import tz
|
|
|
|
|
|
from .isoweek import ISOWeek
|
|
|
from .month import Month
|
|
|
from .quarter import Quarter
|
|
|
from .week import Week
|
|
|
|
|
|
|
|
|
T = TypeVar('T')
|
|
|
TimeAnyT = Union[datetime.datetime, datetime.date, str, bytes]
|
|
|
TimeAnyNT = Union[datetime.datetime, datetime.date, str, bytes, None]
|
|
|
|
|
|
|
|
|
class TimeConvertTools(object):
|
|
|
def __get_base_time_zone(self):
|
|
|
if hasattr(tzlocal, 'get_localzone_name'):
|
|
|
return tzlocal.get_localzone_name()
|
|
|
tz_localzone = tzlocal.get_localzone()
|
|
|
if hasattr(tz_localzone, 'unwrap_shim'):
|
|
|
tz_localzone = tz_localzone.unwrap_shim()
|
|
|
return tz_localzone.key if hasattr(tz_localzone, 'key') else tz_localzone.zone
|
|
|
|
|
|
def __init__(self, timezone: Optional[str] = None, format: Optional[str] = None):
|
|
|
self.BASE_TIME_ZONE = self.__get_base_time_zone()
|
|
|
self.DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
|
|
|
self.DATETIME_ISOFORMAT = '%Y-%m-%dT%H:%M:%S.%f'
|
|
|
self.DATE_FORMAT = '%Y-%m-%d'
|
|
|
# %U - Week number of the year (Sunday as the first day of the week) as a zero-padded decimal number. All days in a new year preceding the first Sunday are considered to be in week 0.
|
|
|
# %W - Week number of the year (Monday as the first day of the week) as a zero-padded decimal number. All days in a new year preceding the first Monday are considered to be in week 0.
|
|
|
# %Y - Year with century as a decimal number.
|
|
|
# %V - ISO 8601 week as a decimal number with Monday as the first day of the week. Week 01 is the week containing Jan 4.
|
|
|
# %G - ISO 8601 year with century representing the year that contains the greater part of the ISO week (%V).
|
|
|
self.WEEK_FORMAT = '%W'
|
|
|
self.WEEK_FORMAT_U = '%U'
|
|
|
self.WEEK_FORMAT_W = '%W'
|
|
|
self.WEEK_FORMAT_ISO = 'ISO'
|
|
|
self.MODE_WEEK_FORMAT = {
|
|
|
0: self.WEEK_FORMAT_U,
|
|
|
3: self.WEEK_FORMAT_ISO,
|
|
|
5: self.WEEK_FORMAT_W,
|
|
|
}
|
|
|
self.YEARWEEK_FORMAT = '%YW%W'
|
|
|
self.YEARWEEK_FORMAT_U = '%YW%U'
|
|
|
self.YEARWEEK_FORMAT_W = '%YW%W'
|
|
|
self.YEARWEEK_FORMAT_ISO = 'ISO'
|
|
|
self.MODE_yearweek_FORMAT = {
|
|
|
0: self.YEARWEEK_FORMAT_U,
|
|
|
3: self.YEARWEEK_FORMAT_ISO,
|
|
|
5: self.YEARWEEK_FORMAT_W,
|
|
|
}
|
|
|
self.LEN_FORMAT = {
|
|
|
19: self.DATETIME_FORMAT,
|
|
|
10: self.DATE_FORMAT,
|
|
|
}
|
|
|
self.TIME_ZONE = timezone or self.BASE_TIME_ZONE
|
|
|
self.TIME_FORMAT = format or self.DATETIME_FORMAT
|
|
|
self.TIME_ISOFORMAT = format or self.DATETIME_ISOFORMAT
|
|
|
self.SECOND_MILLISECOND = 10 ** 3
|
|
|
self.SECOND_MICROSECOND = 10 ** 6
|
|
|
|
|
|
def timezone(self, timezone: Optional[str] = None) -> str:
|
|
|
# In [1]: import pytz
|
|
|
# In [2]: pytz.all_timezones
|
|
|
return timezone or self.TIME_ZONE
|
|
|
|
|
|
def format(self, format: Optional[str] = None) -> str:
|
|
|
return format or self.TIME_FORMAT
|
|
|
|
|
|
def isoformat(self, format: Optional[str] = None) -> str:
|
|
|
return format or self.TIME_ISOFORMAT
|
|
|
|
|
|
def date_format(self, format: Optional[str] = None) -> str:
|
|
|
return format or self.DATE_FORMAT
|
|
|
|
|
|
def value_format(self, value: Optional[str] = None, format: Optional[str] = None) -> str:
|
|
|
if format:
|
|
|
return format
|
|
|
return self.LEN_FORMAT.get(len(value)) if isinstance(value, (str, bytes)) else format
|
|
|
|
|
|
def tzinfo(self, timezone: Optional[str] = None, tzname: str = None):
|
|
|
# tzname = self.timezone(timezone)
|
|
|
# tzinfo = tz.gettz(tzname)
|
|
|
# return tzinfo
|
|
|
return tz.gettz(tzname or self.timezone(timezone))
|
|
|
|
|
|
# PRIVATE
|
|
|
|
|
|
def __utc_datetime(self, utc_dt: Optional[datetime.datetime] = None, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0) -> datetime.datetime:
|
|
|
return self.several_time_coming(dt=utc_dt or self.basic_utc_datetime(), utc=True, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks)
|
|
|
|
|
|
def __local_datetime(self, local_dt: Optional[datetime.datetime] = None, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0) -> datetime.datetime:
|
|
|
return self.several_time_coming(dt=local_dt or self.basic_local_datetime(), utc=False, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks)
|
|
|
|
|
|
def __datetime(self, dt: Optional[datetime.datetime] = None, utc: Optional[bool] = True, timezone: Optional[str] = None) -> datetime.datetime:
|
|
|
return dt or (self.basic_utc_datetime() if utc else self.basic_local_datetime(timezone=timezone))
|
|
|
|
|
|
def __relativedelta(self, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0):
|
|
|
return relativedelta(years=years, months=months) + datetime.timedelta(days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks)
|
|
|
|
|
|
def __remove_ms_or_not(self, dt: datetime.datetime, ms: Optional[bool] = True) -> datetime.datetime:
|
|
|
return dt if ms else self.remove_microsecond(dt)
|
|
|
|
|
|
def __seconds_to_other(self, s: int, base: int = 0) -> int:
|
|
|
return int(s * (base or self.SECOND_MICROSECOND))
|
|
|
|
|
|
# OFFSET
|
|
|
|
|
|
def offset(self) -> int:
|
|
|
now_timestamp = time.time()
|
|
|
return datetime.datetime.fromtimestamp(now_timestamp) - datetime.datetime.utcfromtimestamp(now_timestamp)
|
|
|
|
|
|
# VALIDATE
|
|
|
|
|
|
def validate_string(self, string: str, format: Optional[str] = None) -> bool:
|
|
|
if not string:
|
|
|
return False
|
|
|
try:
|
|
|
time.strptime(string, self.format(format))
|
|
|
except ValueError:
|
|
|
return False
|
|
|
return True
|
|
|
|
|
|
# REPLACE
|
|
|
|
|
|
def remove_microsecond(self, dt: datetime.datetime) -> datetime.datetime:
|
|
|
return dt.replace(microsecond=0) if hasattr(dt, 'replace') else dt
|
|
|
|
|
|
# BASIC DATETIME
|
|
|
|
|
|
def basic_utc_datetime(self, ms: bool = True) -> datetime.datetime:
|
|
|
return self.__remove_ms_or_not(datetime.datetime.utcnow().replace(tzinfo=tz.UTC), ms=ms)
|
|
|
|
|
|
def basic_local_datetime(self, ms: bool = True, timezone: Optional[str] = None) -> datetime.datetime:
|
|
|
# In[1]: import time
|
|
|
#
|
|
|
# In[2]: time.localtime()
|
|
|
# Out[2]: time.struct_time(tm_year=2017, tm_mon=4, tm_mday=3, tm_hour=23, tm_min=19, tm_sec=39, tm_wday=0, tm_yday=93, tm_isdst=0)
|
|
|
#
|
|
|
# In[3]: time.localtime(time.time())
|
|
|
# Out[3]: time.struct_time(tm_year=2017, tm_mon=4, tm_mday=3, tm_hour=23, tm_min=19, tm_sec=40, tm_wday=0, tm_yday=93, tm_isdst=0)
|
|
|
#
|
|
|
# In[4]: time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
|
|
|
# Out[4]: '2017-04-03 23:19:57'
|
|
|
#
|
|
|
# In[5]: time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
|
|
|
# Out[5]: '2017-04-03 23:20:00'
|
|
|
return self.__remove_ms_or_not(self.__to_local_datetime(self.basic_utc_datetime(), self.timezone(timezone)), ms=ms)
|
|
|
|
|
|
def is_utc_datetime(self, dt: datetime.datetime) -> bool:
|
|
|
return dt.tzinfo == tz.UTC
|
|
|
|
|
|
def is_local_datetime(self, dt: datetime.datetime, local_tz: Optional[str] = None) -> bool:
|
|
|
"""
|
|
|
Check whether local datetime or not.
|
|
|
|
|
|
``local_tz`` indicates local tzinfo.
|
|
|
``local_dt`` is ``None``: get_localzone from system.
|
|
|
``local_dt`` is ``-1``: local tzinfo is ``None``.
|
|
|
"""
|
|
|
# In [1]: pytz.timezone('Asia/Shanghai')
|
|
|
# Out[1]: <DstTzInfo 'Asia/Shanghai' LMT+8:06:00 STD>
|
|
|
|
|
|
# In [2]: tc.local_datetime().tzinfo
|
|
|
# Out[2]: <DstTzInfo 'Asia/Shanghai' CST+8:00:00 STD>
|
|
|
|
|
|
# In [3]: pytz.timezone('Asia/Shanghai') == tc.local_datetime().tzinfo
|
|
|
# Out[3]: False
|
|
|
|
|
|
# In [4]: str(pytz.timezone('Asia/Shanghai')) == str(tc.local_datetime().tzinfo)
|
|
|
# Out[4]: True
|
|
|
|
|
|
return str(dt.tzinfo) == str(None if local_tz == -1 else tz.gettz(self.timezone(local_tz)))
|
|
|
|
|
|
def date_to_datetime(self, dt: datetime.date) -> datetime.datetime:
|
|
|
return datetime.datetime(dt.year, dt.month, dt.day)
|
|
|
|
|
|
def __to_utc_datetime(self, dt: datetime.datetime, timezone: Optional[str] = None) -> datetime.datetime:
|
|
|
if self.is_utc_datetime(dt):
|
|
|
return dt
|
|
|
try:
|
|
|
dt = self.make_naive(dt)
|
|
|
except ValueError:
|
|
|
pass
|
|
|
tzinfo = self.tzinfo(timezone)
|
|
|
local_dt = dt.replace(tzinfo=tzinfo)
|
|
|
return local_dt.astimezone(tz.UTC)
|
|
|
|
|
|
def __to_local_datetime(self, dt: datetime.datetime, timezone: Optional[str] = None) -> datetime.datetime:
|
|
|
tzname = self.timezone(timezone)
|
|
|
tzinfo = self.tzinfo(tzname=tzname)
|
|
|
if not dt.tzinfo:
|
|
|
return dt.replace(tzinfo=tzinfo)
|
|
|
if self.is_local_datetime(dt, local_tz=tzname):
|
|
|
return dt
|
|
|
utc_dt = dt.replace(tzinfo=tz.UTC)
|
|
|
return utc_dt.astimezone(tzinfo)
|
|
|
|
|
|
def to_datetime(self, value: TimeAnyT, timezone: Optional[str] = None, format: Optional[str] = None, idx: int = 0, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, dttype: Optional[str] = None) -> Optional[datetime.date]:
|
|
|
if isinstance(value, datetime.datetime):
|
|
|
dt = value
|
|
|
elif isinstance(value, datetime.date):
|
|
|
dt = self.date_to_datetime(value)
|
|
|
elif isinstance(value, (str, bytes)):
|
|
|
dt = self.string_to_datetime(value, format)
|
|
|
else:
|
|
|
return None
|
|
|
if dttype == 'utc':
|
|
|
dt = self.__to_utc_datetime(dt, timezone=timezone)
|
|
|
elif dttype == 'local':
|
|
|
dt = self.__to_local_datetime(dt, timezone=timezone)
|
|
|
return dt + self.__relativedelta(years=years, months=months, days=days or idx, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks)
|
|
|
|
|
|
def to_utc_datetime(self, value: TimeAnyT, timezone: Optional[str] = None, format: Optional[str] = None, idx: int = 0, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0) -> datetime.datetime:
|
|
|
return self.to_datetime(value, timezone=timezone, format=format, idx=idx, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, dttype='utc')
|
|
|
|
|
|
def to_local_datetime(self, value: TimeAnyT, timezone: Optional[str] = None, format: Optional[str] = None, idx: int = 0, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0) -> datetime.datetime:
|
|
|
return self.to_datetime(value, timezone=timezone, format=format, idx=idx, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, dttype='local')
|
|
|
|
|
|
# DATETIME
|
|
|
|
|
|
def yesterday_utc_datetime(self, ms: bool = True) -> datetime.datetime:
|
|
|
return self.__remove_ms_or_not(self.several_days_ago(days=1), ms=ms)
|
|
|
|
|
|
def tomorrow_utc_datetime(self, ms: bool = True) -> datetime.datetime:
|
|
|
return self.__remove_ms_or_not(self.several_days_coming(days=1), ms=ms)
|
|
|
|
|
|
def yesterday_local_datetime(self, ms: bool = True, timezone: Optional[str] = None) -> datetime.datetime:
|
|
|
return self.__remove_ms_or_not(self.several_days_ago(utc=False, timezone=timezone, days=1), ms=ms)
|
|
|
|
|
|
def tomorrow_local_datetime(self, ms: bool = True, timezone: Optional[str] = None) -> datetime.datetime:
|
|
|
return self.__remove_ms_or_not(self.several_days_coming(utc=False, timezone=timezone, days=1), ms=ms)
|
|
|
|
|
|
def several_days_ago(self, dt: Optional[datetime.datetime] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, days: int = 0) -> datetime.datetime:
|
|
|
return self.__remove_ms_or_not(self.__datetime(dt, utc, timezone=timezone) - datetime.timedelta(days=days), ms=ms)
|
|
|
|
|
|
def several_days_coming(self, dt: Optional[datetime.datetime] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, days: int = 0) -> datetime.datetime:
|
|
|
return self.__remove_ms_or_not(self.__datetime(dt, utc, timezone=timezone) + datetime.timedelta(days=days), ms=ms)
|
|
|
|
|
|
def several_time_ago(self, dt: Optional[datetime.datetime] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0) -> datetime.datetime:
|
|
|
return self.__remove_ms_or_not(self.__datetime(dt, utc, timezone=timezone) - self.__relativedelta(years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks), ms=ms)
|
|
|
|
|
|
def several_time_coming(self, dt: Optional[datetime.datetime] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0) -> datetime.datetime:
|
|
|
return self.__remove_ms_or_not(self.__datetime(dt, utc, timezone=timezone) + self.__relativedelta(years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks), ms=ms)
|
|
|
|
|
|
def utc_datetime(self, value: TimeAnyNT = None, format: Optional[str] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, dt: TimeAnyNT = None) -> datetime.datetime:
|
|
|
value = value or dt
|
|
|
if isinstance(value, (str, bytes)):
|
|
|
value = self.utc_string_to_utc_datetime(value, format)
|
|
|
return self.several_time_coming(dt=value, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks)
|
|
|
|
|
|
def local_datetime(self, value: TimeAnyNT = None, format: Optional[str] = None, utc: bool = False, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, dt: TimeAnyNT = None) -> datetime.datetime:
|
|
|
value = value or dt
|
|
|
if isinstance(value, (str, bytes)):
|
|
|
value = self.string_to_local_datetime(value, format)
|
|
|
return self.several_time_coming(dt=value, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks)
|
|
|
|
|
|
# DATE
|
|
|
|
|
|
def utc_date(self, value: TimeAnyNT = None, format: Optional[str] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0) -> datetime.date:
|
|
|
if isinstance(value, (str, bytes)):
|
|
|
value = self.utc_string_to_utc_datetime(value, format)
|
|
|
return self.to_date(self.utc_datetime(value=value, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks))
|
|
|
|
|
|
def local_date(self, value: TimeAnyNT = None, format: Optional[str] = None, utc: bool = False, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0) -> datetime.date:
|
|
|
if isinstance(value, (str, bytes)):
|
|
|
value = self.string_to_local_datetime(value, format)
|
|
|
return self.to_date(self.local_datetime(value=value, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks))
|
|
|
|
|
|
def datetime_to_date(self, dt: datetime.datetime) -> datetime.date:
|
|
|
return dt.date()
|
|
|
|
|
|
def to_date(self, value: TimeAnyT, format: Optional[str] = None, idx: int = 0, years: int = 0, months: int = 0, days: int = 0, weeks: int = 0) -> Optional[datetime.date]:
|
|
|
if isinstance(value, datetime.datetime):
|
|
|
date = value.date()
|
|
|
elif isinstance(value, datetime.date):
|
|
|
date = value
|
|
|
elif isinstance(value, (str, bytes)):
|
|
|
date = self.string_to_date(value, format)
|
|
|
else:
|
|
|
return None
|
|
|
return date + self.__relativedelta(years=years, months=months, days=days or idx, weeks=weeks)
|
|
|
|
|
|
# def is_the_same_day(self, dt1: datetime.date, dt2: datetime.date) -> bool:
|
|
|
# return self.local_string(dt1, format=self.DATE_FORMAT) == self.local_string(dt2, format=self.DATE_FORMAT)
|
|
|
def is_the_same_day(self, value1: TimeAnyT, value2: TimeAnyT, format: Optional[str] = None, format1: Optional[str] = None, format2: Optional[str] = None) -> bool:
|
|
|
return self.to_date(value1, format=format1 or format) == self.to_date(value2, format=format2 or format)
|
|
|
|
|
|
# YEAR WEEK
|
|
|
|
|
|
def utc_yearweek(self, value: Union[datetime.datetime, datetime.date, None] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False, mode: int = 3) -> Union[Week, ISOWeek]:
|
|
|
yearweek_format = self.MODE_yearweek_FORMAT.get(mode, self.YEARWEEK_FORMAT_ISO)
|
|
|
if yearweek_format != self.YEARWEEK_FORMAT_ISO:
|
|
|
return Week.fromstring(self.utc_string(value=value, format=yearweek_format, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc))
|
|
|
return ISOWeek.withdate(self.utc_date(value, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks))
|
|
|
|
|
|
def utc_isoyearweek(self, value: Union[datetime.datetime, datetime.date, None] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False) -> ISOWeek:
|
|
|
return self.utc_yearweek(value, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc, mode=3)
|
|
|
|
|
|
def local_yearweek(self, value: Union[datetime.datetime, datetime.date, None] = None, utc: bool = False, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False, mode: int = 3) -> Union[Week, ISOWeek]:
|
|
|
yearweek_format = self.MODE_yearweek_FORMAT.get(mode, self.YEARWEEK_FORMAT_ISO)
|
|
|
if yearweek_format != self.YEARWEEK_FORMAT_ISO:
|
|
|
return Week.fromstring(self.local_string(value=value, format=yearweek_format, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc))
|
|
|
return ISOWeek.withdate(self.local_date(value, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks))
|
|
|
|
|
|
def local_isoyearweek(self, value: Union[datetime.datetime, datetime.date, None] = None, utc: bool = False, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False) -> ISOWeek:
|
|
|
return self.local_yearweek(value, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc, mode=3)
|
|
|
|
|
|
# WEEK
|
|
|
|
|
|
def utc_week(self, value: Union[datetime.datetime, datetime.date, None] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False, mode: int = 3) -> int:
|
|
|
# week_format = self.MODE_WEEK_FORMAT.get(mode, self.WEEK_FORMAT_ISO)
|
|
|
# if week_format != self.WEEK_FORMAT_ISO:
|
|
|
# return int(self.utc_string(value=value, format=week_format, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc))
|
|
|
# return ISOWeek.withdate(self.utc_date(value, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks)).week
|
|
|
return self.utc_yearweek(value, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc, mode=mode).week
|
|
|
|
|
|
def utc_isoweek(self, value: Union[datetime.datetime, datetime.date, None] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False) -> int:
|
|
|
return self.utc_week(value, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc, mode=3)
|
|
|
|
|
|
def local_week(self, value: Union[datetime.datetime, datetime.date, None] = None, utc: bool = False, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False, mode: int = 3) -> int:
|
|
|
# week_format = self.MODE_WEEK_FORMAT.get(mode, self.WEEK_FORMAT_ISO)
|
|
|
# if week_format != self.WEEK_FORMAT_ISO:
|
|
|
# return int(self.local_string(value=value, format=week_format, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc))
|
|
|
# return ISOWeek.withdate(self.local_date(value, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks)).week
|
|
|
return self.local_yearweek(value, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc, mode=mode).week
|
|
|
|
|
|
def local_isoweek(self, value: Union[datetime.datetime, datetime.date, None] = None, utc: bool = False, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False) -> int:
|
|
|
return self.local_week(value, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc, mode=3)
|
|
|
|
|
|
def to_week(self, value: TimeAnyT, idx: int = 0, mode: int = 3, format: Optional[str] = None) -> Optional[ISOWeek]:
|
|
|
date = self.to_date(value, format=format)
|
|
|
if not date:
|
|
|
return None
|
|
|
if mode != 3:
|
|
|
raise ValueError('to_week only support mode equals 3 nowadays')
|
|
|
return ISOWeek.withdate(date) + idx
|
|
|
|
|
|
def to_isoweek(self, value: TimeAnyT, idx: int = 0, format: Optional[str] = None) -> Optional[ISOWeek]:
|
|
|
return self.to_week(value, idx=idx, mode=3, format=format)
|
|
|
|
|
|
def weekdelta(self, value1: TimeAnyT, value2: TimeAnyT, mode: int = 3) -> int:
|
|
|
return self.to_week(value1, mode=mode) - self.to_week(value2, mode=mode)
|
|
|
|
|
|
def isoweekdelta(self, value1: TimeAnyT, value2: TimeAnyT) -> int:
|
|
|
return self.to_isoweek(value1) - self.to_isoweek(value2)
|
|
|
|
|
|
# STRING
|
|
|
|
|
|
# DATETIME_STRING
|
|
|
def datetime_to_unicode_string(self, dt: datetime.datetime, format: Optional[str] = None) -> str:
|
|
|
format = self.format(format)
|
|
|
# Refer: https://github.com/sphinx-doc/sphinx/blob/8ae43b9fd/sphinx/util/osutil.py#L164
|
|
|
# On Windows, time.strftime() and Unicode characters will raise UnicodeEncodeError.
|
|
|
# http://bugs.python.org/issue8304
|
|
|
try:
|
|
|
return dt.strftime(format)
|
|
|
except UnicodeEncodeError:
|
|
|
return dt.strftime(format.encode('unicode-escape').decode()).encode().decode('unicode-escape')
|
|
|
|
|
|
def datetime_to_string(self, dt: datetime.datetime, format: Optional[str] = None, isuc: bool = False) -> str:
|
|
|
if isuc:
|
|
|
return self.datetime_to_unicode_string(dt, format=format)
|
|
|
return dt.strftime(self.format(format))
|
|
|
|
|
|
def yesterday_utc_string(self, format: Optional[str] = None, ms: bool = True, isuc: bool = False) -> str:
|
|
|
return self.datetime_to_string(self.yesterday_utc_datetime(ms=ms), self.format(format), isuc=isuc)
|
|
|
|
|
|
def tomorrow_utc_string(self, format: Optional[str] = None, ms: bool = True, isuc: bool = False) -> str:
|
|
|
return self.datetime_to_string(self.tomorrow_utc_datetime(ms=ms), self.format(format), isuc=isuc)
|
|
|
|
|
|
def yesterday_local_string(self, format: Optional[str] = None, ms: bool = True, timezone: Optional[str] = None, isuc: bool = False) -> str:
|
|
|
return self.datetime_to_string(self.yesterday_local_datetime(ms=ms, timezone=timezone), self.format(format), isuc=isuc)
|
|
|
|
|
|
def tomorrow_local_string(self, format: Optional[str] = None, ms: bool = True, timezone: Optional[str] = None, isuc: bool = False) -> str:
|
|
|
return self.datetime_to_string(self.tomorrow_local_datetime(ms=ms, timezone=timezone), self.format(format), isuc=isuc)
|
|
|
|
|
|
def several_days_ago_string(self, dt: Optional[datetime.datetime] = None, format: Optional[str] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, days: int = 0, isuc: bool = False) -> str:
|
|
|
return self.datetime_to_string(self.several_days_ago(dt=dt, utc=utc, ms=ms, timezone=timezone, days=days), self.format(format), isuc=isuc)
|
|
|
|
|
|
def several_days_coming_string(self, dt: Optional[datetime.datetime] = None, format: Optional[str] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, days: int = 0, isuc: bool = False) -> str:
|
|
|
return self.datetime_to_string(self.several_days_coming(dt=dt, utc=utc, ms=ms, timezone=timezone, days=days), self.format(format), isuc=isuc)
|
|
|
|
|
|
def several_time_ago_string(self, dt: Optional[datetime.datetime] = None, format: Optional[str] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, isuc: bool = False) -> str:
|
|
|
return self.datetime_to_string(self.several_time_ago(dt=dt, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks), self.format(format), isuc=isuc)
|
|
|
|
|
|
def several_time_coming_string(self, dt: Optional[datetime.datetime] = None, format: Optional[str] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, isuc: bool = False) -> str:
|
|
|
return self.datetime_to_string(self.several_time_coming(dt=dt, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks), self.format(format), isuc=isuc)
|
|
|
|
|
|
def utc_string(self, value: TimeAnyNT = None, format: Optional[str] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False, dt: TimeAnyNT = None, value_format: Optional[str] = None) -> str:
|
|
|
final_dt = value or dt or utc_dt
|
|
|
final_dt = self.utc_datetime(value=local_dt) if not final_dt and local_dt else final_dt
|
|
|
if isinstance(final_dt, (str, bytes)):
|
|
|
final_dt = self.utc_string_to_utc_datetime(final_dt, value_format)
|
|
|
return self.datetime_to_string(self.utc_datetime(value=final_dt, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks), self.format(format), isuc=isuc)
|
|
|
|
|
|
def local_string(self, value: TimeAnyNT = None, format: Optional[str] = None, utc: bool = False, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False, dt: TimeAnyNT = None, value_format: Optional[str] = None) -> str:
|
|
|
final_dt = value or dt or local_dt
|
|
|
final_dt = self.__to_local_datetime(dt=utc_dt) if not final_dt and utc_dt else final_dt
|
|
|
if isinstance(final_dt, (str, bytes)):
|
|
|
final_dt = self.string_to_local_datetime(final_dt, value_format)
|
|
|
return self.datetime_to_string(self.local_datetime(value=final_dt, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks), self.format(format), isuc=isuc)
|
|
|
|
|
|
def utc_datetime_string(self, value: TimeAnyNT = None, format: Optional[str] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False, dt: TimeAnyNT = None, value_format: Optional[str] = None) -> str:
|
|
|
return self.utc_string(value=value or dt, format=self.format(format), utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc, value_format=value_format)
|
|
|
|
|
|
def local_datetime_string(self, value: TimeAnyNT = None, format: Optional[str] = None, utc: bool = False, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False, dt: TimeAnyNT = None, value_format: Optional[str] = None) -> str:
|
|
|
return self.local_string(value=value or dt, format=self.format(format), utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc, value_format=value_format)
|
|
|
|
|
|
def utc_isostring(self, value: TimeAnyNT = None, format: Optional[str] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False, dt: TimeAnyNT = None, value_format: Optional[str] = None) -> str:
|
|
|
return self.utc_string(value=value or dt, format=self.isoformat(format), utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc, value_format=value_format)
|
|
|
|
|
|
def local_isostring(self, value: TimeAnyNT = None, format: Optional[str] = None, utc: bool = False, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False, dt: TimeAnyNT = None, value_format: Optional[str] = None) -> str:
|
|
|
return self.local_string(value=value or dt, format=self.isoformat(format), utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc, value_format=value_format)
|
|
|
|
|
|
def utc_datetime_isostring(self, value: TimeAnyNT = None, format: Optional[str] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False, dt: TimeAnyNT = None, value_format: Optional[str] = None) -> str:
|
|
|
return self.utc_string(value=value or dt, format=self.isoformat(format), utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc, value_format=value_format)
|
|
|
|
|
|
def local_datetime_isostring(self, value: TimeAnyNT = None, format: Optional[str] = None, utc: bool = False, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False, dt: TimeAnyNT = None, value_format: Optional[str] = None) -> str:
|
|
|
return self.local_string(value=value or dt, format=self.isoformat(format), utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc, value_format=value_format)
|
|
|
|
|
|
# DATE_STRING
|
|
|
def utc_date_string(self, value: TimeAnyNT = None, format: Optional[str] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False, dt: TimeAnyNT = None, value_format: Optional[str] = None) -> str:
|
|
|
return self.utc_string(value=value or dt, format=self.date_format(format), utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc, value_format=self.value_format(value or dt, value_format))
|
|
|
|
|
|
def local_date_string(self, value: TimeAnyNT = None, format: Optional[str] = None, utc: bool = False, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False, dt: TimeAnyNT = None, value_format: Optional[str] = None) -> str:
|
|
|
return self.local_string(value=value or dt, format=self.date_format(format), utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc, value_format=self.value_format(value or dt, value_format))
|
|
|
|
|
|
# WEEK_STRING
|
|
|
def utc_yearweek_string(self, dt: Optional[datetime.datetime] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False, mode: int = 3) -> str:
|
|
|
return str(self.utc_yearweek(dt, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc, mode=mode))
|
|
|
|
|
|
def local_yearweek_string(self, dt: Optional[datetime.datetime] = None, utc: bool = False, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False, mode: int = 3) -> str:
|
|
|
return str(self.local_yearweek(dt, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc, mode=mode))
|
|
|
|
|
|
def utc_isoyearweek_string(self, dt: Optional[datetime.datetime] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False) -> str:
|
|
|
return str(self.utc_isoyearweek(dt, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc))
|
|
|
|
|
|
def local_isoyearweek_string(self, dt: Optional[datetime.datetime] = None, utc: bool = False, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False) -> str:
|
|
|
return str(self.local_isoyearweek(dt, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc))
|
|
|
|
|
|
# WEEK_STRING
|
|
|
def utc_week_string(self, dt: Optional[datetime.datetime] = None, utc: bool = True, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False, mode: int = 3) -> str:
|
|
|
return str(self.utc_week(dt, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc, mode=mode))
|
|
|
|
|
|
def local_week_string(self, dt: Optional[datetime.datetime] = None, utc: bool = False, ms: bool = True, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0, local_dt: Optional[datetime.datetime] = None, utc_dt: Optional[datetime.datetime] = None, isuc: bool = False, mode: int = 3) -> str:
|
|
|
return str(self.local_week(dt, utc=utc, ms=ms, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks, local_dt=local_dt, utc_dt=utc_dt, isuc=isuc, mode=mode))
|
|
|
|
|
|
# TIMESTAMP
|
|
|
|
|
|
def __micro_or_milli(self, s, micro: bool = False, milli: bool = False) -> int:
|
|
|
if micro:
|
|
|
return self.seconds_to_microseconds(s)
|
|
|
if milli:
|
|
|
return self.seconds_to_milliseconds(s)
|
|
|
return s
|
|
|
|
|
|
def utc_timestamp(self, utc_dt: Optional[datetime.datetime] = None, ms: bool = False, micro: bool = False, milli: bool = False, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0) -> int:
|
|
|
return self.__micro_or_milli(self.datetime_to_timestamp(self.__utc_datetime(utc_dt, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks), ms=ms), micro=micro, milli=milli)
|
|
|
|
|
|
def local_timestamp(self, local_dt: Optional[datetime.datetime] = None, ms: bool = False, micro: bool = False, milli: bool = False, timezone: Optional[str] = None, years: int = 0, months: int = 0, days: int = 0, seconds: int = 0, microseconds: int = 0, milliseconds: int = 0, minutes: int = 0, hours: int = 0, weeks: int = 0) -> int:
|
|
|
return self.__micro_or_milli(self.datetime_to_timestamp(self.__local_datetime(local_dt, timezone=timezone, years=years, months=months, days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds, minutes=minutes, hours=hours, weeks=weeks), ms=ms), micro=micro, milli=milli)
|
|
|
|
|
|
def datetime_to_timestamp(self, dt: Union[datetime.datetime, datetime.date], ms: bool = False) -> int:
|
|
|
# http://stackoverflow.com/questions/26161156/python-converting-string-to-timestamp-with-microseconds
|
|
|
# ``dt - epoch`` will raise ``TypeError: can't subtract offset-naive and offset-aware datetimes``
|
|
|
# Total seconds from ``1970-01-01 00:00:00``(utc or local)
|
|
|
# Different from definition of timestamp(时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数)
|
|
|
stamp = self.structime_to_timestamp(dt.timetuple())
|
|
|
if not ms:
|
|
|
return stamp
|
|
|
return stamp + dt.microsecond / self.SECOND_MICROSECOND
|
|
|
|
|
|
def date_to_timestamp(self, dt: Union[datetime.datetime, datetime.date], ms: bool = False) -> int:
|
|
|
return self.datetime_to_timestamp(dt, ms=ms)
|
|
|
|
|
|
def structime_to_timestamp(self, structime: time.struct_time) -> int:
|
|
|
return int(time.mktime(structime))
|
|
|
|
|
|
def seconds_to_microseconds(self, s: int) -> int:
|
|
|
return self.__seconds_to_other(s, base=self.SECOND_MICROSECOND)
|
|
|
|
|
|
def seconds_to_milliseconds(self, s: int) -> int:
|
|
|
return self.__seconds_to_other(s, base=self.SECOND_MILLISECOND)
|
|
|
|
|
|
# STRING ==> DATE
|
|
|
|
|
|
def string_to_date(self, string: str, format: Optional[str] = None) -> Optional[datetime.date]:
|
|
|
format = self.value_format(string, format)
|
|
|
if not self.validate_string(string, format):
|
|
|
return None
|
|
|
return self.string_to_datetime(string, format).date()
|
|
|
|
|
|
def string_to_utc_date(self, string: str, format: Optional[str] = None) -> Optional[datetime.date]:
|
|
|
format = self.value_format(string, format)
|
|
|
if not self.validate_string(string, format):
|
|
|
return None
|
|
|
return self.string_to_utc_datetime(string, format).date()
|
|
|
|
|
|
def string_to_local_date(self, string: str, format: Optional[str] = None) -> Optional[datetime.date]:
|
|
|
format = self.value_format(string, format)
|
|
|
if not self.validate_string(string, format):
|
|
|
return None
|
|
|
return self.string_to_local_datetime(string, format).date()
|
|
|
|
|
|
def utc_string_to_utc_date(self, utc_string: str, format: Optional[str] = None) -> Optional[datetime.date]:
|
|
|
format = self.value_format(utc_string, format)
|
|
|
if not self.validate_string(utc_string, format):
|
|
|
return None
|
|
|
return self.utc_string_to_utc_datetime(utc_string, format).date()
|
|
|
|
|
|
def utc_string_to_local_date(self, utc_string: str, format: Optional[str] = None) -> Optional[datetime.date]:
|
|
|
format = self.value_format(utc_string, format)
|
|
|
if not self.validate_string(utc_string, format):
|
|
|
return None
|
|
|
return self.utc_string_to_local_datetime(utc_string, format).date()
|
|
|
|
|
|
# STRING ==> DATETIME
|
|
|
|
|
|
def string_to_datetime(self, string: str, format: Optional[str] = None) -> Optional[datetime.datetime]:
|
|
|
format = self.value_format(string, format)
|
|
|
if not self.validate_string(string, format):
|
|
|
return None
|
|
|
return datetime.datetime.strptime(string, format)
|
|
|
|
|
|
def string_to_utc_datetime(self, string: str, format: Optional[str] = None) -> Optional[datetime.datetime]:
|
|
|
format = self.value_format(string, format)
|
|
|
if not self.validate_string(string, format):
|
|
|
return None
|
|
|
return self.__to_utc_datetime(self.string_to_datetime(string, format))
|
|
|
|
|
|
def string_to_local_datetime(self, string: str, format: Optional[str] = None) -> Optional[datetime.datetime]:
|
|
|
format = self.value_format(string, format)
|
|
|
if not self.validate_string(string, format):
|
|
|
return None
|
|
|
return self.__to_local_datetime(self.string_to_datetime(string, format))
|
|
|
|
|
|
def utc_string_to_utc_datetime(self, utc_string: str, format: Optional[str] = None) -> Optional[datetime.datetime]:
|
|
|
format = self.value_format(utc_string, format)
|
|
|
if not self.validate_string(utc_string, format):
|
|
|
return None
|
|
|
return self.__to_utc_datetime(self.string_to_datetime(utc_string, format)) + self.offset()
|
|
|
|
|
|
def utc_string_to_local_datetime(self, utc_string: str, format: Optional[str] = None) -> Optional[datetime.datetime]:
|
|
|
format = self.value_format(utc_string, format)
|
|
|
if not self.validate_string(utc_string, format):
|
|
|
return None
|
|
|
return self.__to_local_datetime(self.string_to_datetime(utc_string, format)) + self.offset()
|
|
|
|
|
|
# STRING ==> TIMESTAMP
|
|
|
|
|
|
def string_to_timestamp(self, string: str, format: Optional[str] = None, ms: bool = False) -> Optional[int]:
|
|
|
return self.string_to_local_timestamp(string, format, ms=ms)
|
|
|
|
|
|
def string_to_utc_timestamp(self, string: str, format: Optional[str] = None, ms: bool = False) -> Optional[int]:
|
|
|
format = self.format(format)
|
|
|
if not self.validate_string(string, format):
|
|
|
return None
|
|
|
return self.datetime_to_timestamp(self.string_to_utc_datetime(string, format), ms=ms)
|
|
|
|
|
|
def string_to_local_timestamp(self, string: str, format: Optional[str] = None, ms: bool = False) -> Optional[int]:
|
|
|
format = self.format(format)
|
|
|
if not self.validate_string(string, format):
|
|
|
return None
|
|
|
return self.datetime_to_timestamp(self.string_to_local_datetime(string, format), ms=ms)
|
|
|
|
|
|
# TIMESTAMP ==> DATETIME
|
|
|
|
|
|
# local_stamp => utc_datetime - fromtimestamp + to_utc_datetime / utcfromtimestamp
|
|
|
# local_stamp => local_datetime - fromtimestamp
|
|
|
# utc_stamp => utc_datetime - fromtimestamp
|
|
|
# utc_stamp => local_datetime - fromtimestamp + to_local_datetime
|
|
|
def timestamp_to_datetime(self, stamp: int) -> datetime.datetime:
|
|
|
return datetime.datetime.fromtimestamp(stamp)
|
|
|
|
|
|
def timestamp_to_utc_datetime(self, stamp: int) -> datetime.datetime:
|
|
|
# return datetime.datetime.utcfromtimestamp(stamp)
|
|
|
return self.__to_utc_datetime(self.timestamp_to_datetime(stamp))
|
|
|
|
|
|
def timestamp_to_local_datetime(self, stamp: int) -> datetime.datetime:
|
|
|
return self.timestamp_to_datetime(stamp)
|
|
|
|
|
|
def utc_timestamp_to_utc_datetime(self, stamp: int) -> datetime.datetime:
|
|
|
# return self.make_aware(self.timestamp_to_datetime(stamp), timezone='UTC')
|
|
|
return self.make_aware(self.timestamp_to_datetime(stamp), timezone=self.timezone('UTC'))
|
|
|
|
|
|
def utc_timestamp_to_local_datetime(self, stamp: int) -> datetime.datetime:
|
|
|
return self.__to_local_datetime(self.timestamp_to_datetime(stamp))
|
|
|
|
|
|
# TIMESTAMP ==> AGE
|
|
|
|
|
|
# TIME_DELTA
|
|
|
|
|
|
def timestamp_delta(self, stamp1: int, stamp2: int, interval: Optional[int] = None) -> Dict[str, Any]:
|
|
|
delta = stamp1 - stamp2
|
|
|
abs_delta = abs(delta)
|
|
|
sign = abs_delta and delta // abs_delta
|
|
|
delta_seconds = abs_delta % 60
|
|
|
delta_minutes = abs_delta // 60 % 60
|
|
|
delta_hours = abs_delta // 3600 % 24
|
|
|
delta_days = abs_delta // 86400
|
|
|
delta_weeks = abs_delta // 604800
|
|
|
return {
|
|
|
'sign': sign,
|
|
|
'weeks': delta_weeks,
|
|
|
'days': delta_days,
|
|
|
'hours': delta_hours,
|
|
|
'minutes': delta_minutes,
|
|
|
'seconds': delta_seconds,
|
|
|
'total_seconds': abs_delta,
|
|
|
'delta': delta,
|
|
|
'count_down_seconds': abs(min(delta, 0)),
|
|
|
'interval': interval and abs_delta >= interval
|
|
|
}
|
|
|
|
|
|
def datetime_delta(self, dt1: Union[datetime.datetime, datetime.date], dt2: Union[datetime.datetime, datetime.date], interval: Optional[int] = None) -> Optional[Dict[str, Any]]:
|
|
|
return self.timestamp_delta(self.datetime_to_timestamp(dt1), self.datetime_to_timestamp(dt2), interval)
|
|
|
|
|
|
def date_delta(self, dt1: Union[datetime.datetime, datetime.date], dt2: Union[datetime.datetime, datetime.date], interval: Optional[int] = None) -> Optional[Dict[str, Any]]:
|
|
|
return self.datetime_delta(dt1, dt2, interval=interval)
|
|
|
|
|
|
def string_delta(self, string1: str, string2: str, interval: Optional[int] = None, format: Optional[str] = None, format1: Optional[str] = None, format2: Optional[str] = None) -> Optional[Dict[str, Any]]:
|
|
|
format = self.format(format)
|
|
|
if (not self.validate_string(string1, format1 or format)) or (not self.validate_string(string2, format2 or format)):
|
|
|
return None
|
|
|
return self.timestamp_delta(self.string_to_timestamp(string1, format1 or format), self.string_to_timestamp(string2, format2 or format), interval)
|
|
|
|
|
|
def delta(self, value1: TimeAnyT, value2: TimeAnyT, interval: Optional[int] = None, format: Optional[str] = None, format1: Optional[str] = None, format2: Optional[str] = None) -> Optional[Dict[str, Any]]:
|
|
|
if isinstance(value1, datetime.datetime):
|
|
|
value1 = self.datetime_to_timestamp(value1)
|
|
|
elif isinstance(value1, datetime.date):
|
|
|
value1 = self.date_to_timestamp(value1)
|
|
|
elif isinstance(value1, (str, bytes)):
|
|
|
value1 = self.string_to_timestamp(value1, format1 or format)
|
|
|
|
|
|
if isinstance(value2, datetime.datetime):
|
|
|
value2 = self.datetime_to_timestamp(value2)
|
|
|
elif isinstance(value2, datetime.date):
|
|
|
value2 = self.date_to_timestamp(value2)
|
|
|
elif isinstance(value2, (str, bytes)):
|
|
|
value2 = self.string_to_timestamp(value2, format2 or format)
|
|
|
|
|
|
return self.timestamp_delta(value1, value2, interval=interval)
|
|
|
|
|
|
# TIME_COUNT_DOWN
|
|
|
|
|
|
def timestamp_countdown(self, stamp: int, utc: bool = True) -> int:
|
|
|
return abs(min((self.utc_timestamp() if utc else self.local_timestamp()) - stamp, 0))
|
|
|
|
|
|
def datetime_countdown(self, dt: datetime.datetime) -> int:
|
|
|
return self.timestamp_countdown(self.datetime_to_timestamp(self.__to_utc_datetime(dt)))
|
|
|
|
|
|
def string_countdown(self, string: str, format: Optional[str] = None) -> Optional[int]:
|
|
|
format = self.format(format)
|
|
|
if not self.validate_string(string, format):
|
|
|
return None
|
|
|
return self.timestamp_countdown(self.string_to_utc_timestamp(string, format))
|
|
|
|
|
|
# MIDNIGHT
|
|
|
|
|
|
def utc_datetime_midnight(self, utc_dt: Optional[datetime.datetime] = None) -> datetime.datetime:
|
|
|
return (self.__utc_datetime(utc_dt)).replace(hour=0, minute=0, second=0, microsecond=0)
|
|
|
|
|
|
def utc_seconds_since_midnight(self, utc_dt: Optional[datetime.datetime] = None, seconds_cast_func: Callable[[Any], T] = float) -> T:
|
|
|
utc_dt = self.__utc_datetime(utc_dt)
|
|
|
return seconds_cast_func(self.total_seconds(utc_dt - self.utc_datetime_midnight(utc_dt)))
|
|
|
|
|
|
def local_datetime_midnight(self, local_dt: Optional[datetime.datetime] = None) -> datetime.datetime:
|
|
|
return (self.__local_datetime(local_dt)).replace(hour=0, minute=0, second=0, microsecond=0)
|
|
|
|
|
|
def local_seconds_since_midnight(self, local_dt: Optional[datetime.datetime] = None, seconds_cast_func: Callable[[Any], T] = float) -> T:
|
|
|
local_dt = self.__local_datetime(local_dt)
|
|
|
return seconds_cast_func(self.total_seconds(local_dt - self.local_datetime_midnight(local_dt)))
|
|
|
|
|
|
def datetime_midnight(self, dt: Optional[datetime.datetime] = None, utc: bool = False) -> datetime.datetime:
|
|
|
return self.utc_datetime_midnight(dt) if utc else self.local_datetime_midnight(dt)
|
|
|
|
|
|
def seconds_since_midnight(self, dt: Optional[datetime.datetime] = None, utc: bool = False, seconds_cast_func: Callable[[Any], T] = float) -> T:
|
|
|
return seconds_cast_func(self.utc_seconds_since_midnight(dt) if utc else self.local_seconds_since_midnight(dt))
|
|
|
|
|
|
def seconds_until_midnight(self, dt: Optional[datetime.datetime] = None, utc: bool = False, seconds_cast_func: Callable[[Any], T] = float) -> T:
|
|
|
return seconds_cast_func(86400 - self.seconds_since_midnight(dt=dt, utc=utc))
|
|
|
|
|
|
# AWARE vs. NAIVE
|
|
|
|
|
|
# By design, these four functions don't perform any checks on their arguments.
|
|
|
# The caller should ensure that they don't receive an invalid value like None.
|
|
|
|
|
|
def is_aware(self, value: datetime.datetime) -> bool:
|
|
|
"""
|
|
|
Determine if a given datetime.datetime is aware.
|
|
|
The concept is defined in Python's docs:
|
|
|
https://docs.python.org/library/datetime.html#datetime.tzinfo
|
|
|
Assuming value.tzinfo is either None or a proper datetime.tzinfo,
|
|
|
value.utcoffset() implements the appropriate logic.
|
|
|
"""
|
|
|
return value.utcoffset() is not None
|
|
|
|
|
|
def is_naive(self, value: datetime.datetime) -> bool:
|
|
|
"""
|
|
|
Determine if a given datetime.datetime is naive.
|
|
|
The concept is defined in Python's docs:
|
|
|
https://docs.python.org/library/datetime.html#datetime.tzinfo
|
|
|
Assuming value.tzinfo is either None or a proper datetime.tzinfo,
|
|
|
value.utcoffset() implements the appropriate logic.
|
|
|
"""
|
|
|
return value.utcoffset() is None
|
|
|
|
|
|
def make_aware(self, value: datetime.datetime, timezone: Optional[str] = None) -> datetime.datetime:
|
|
|
"""Make a naive datetime.datetime in a given time zone aware."""
|
|
|
tzinfo = self.tzinfo(timezone)
|
|
|
# Check that we won't overwrite the timezone of an aware datetime.
|
|
|
if self.is_aware(value):
|
|
|
raise ValueError('make_aware expects a naive datetime, got %s' % value)
|
|
|
# This may be wrong around DST changes!
|
|
|
return value.replace(tzinfo=tzinfo)
|
|
|
|
|
|
def make_naive(self, value: datetime.datetime, timezone: Optional[str] = None) -> datetime.datetime:
|
|
|
"""Make an aware datetime.datetime naive in a given time zone."""
|
|
|
tzinfo = self.tzinfo(timezone)
|
|
|
# Emulate the behavior of astimezone() on Python < 3.6.
|
|
|
if self.is_naive(value):
|
|
|
raise ValueError('make_naive() cannot be applied to a naive datetime')
|
|
|
return value.astimezone(tzinfo).replace(tzinfo=None)
|
|
|
|
|
|
# PAST vs. FUTURE
|
|
|
|
|
|
def is_past_time(self, value: Union[str, int, datetime.datetime], base_dt: Optional[datetime.datetime] = None, format: Optional[str] = None, utc: bool = True) -> Optional[bool]:
|
|
|
base_dt = base_dt or self.basic_utc_datetime()
|
|
|
|
|
|
if not value:
|
|
|
return None
|
|
|
|
|
|
if isinstance(value, datetime.datetime):
|
|
|
return (value if utc else self.__to_local_datetime(value)) < base_dt
|
|
|
|
|
|
if isinstance(value, (str, bytes)):
|
|
|
utc_dt = self.utc_string_to_utc_datetime(value, format=format) if utc else self.string_to_utc_datetime(value, format=format)
|
|
|
return utc_dt and utc_dt < base_dt
|
|
|
|
|
|
if isinstance(value, int):
|
|
|
stamp = self.datetime_to_timestamp(base_dt if utc else self.__to_local_datetime(base_dt), ms=True)
|
|
|
return value < stamp
|
|
|
|
|
|
return None
|
|
|
|
|
|
def is_future_time(self, value: Union[str, int, datetime.datetime], base_dt: Optional[datetime.datetime] = None, format: Optional[str] = None, utc: bool = True) -> Optional[bool]:
|
|
|
base_dt = base_dt or self.basic_utc_datetime()
|
|
|
|
|
|
if not value:
|
|
|
return None
|
|
|
|
|
|
if isinstance(value, datetime.datetime):
|
|
|
return (value if utc else self.__to_local_datetime(value)) > base_dt
|
|
|
|
|
|
if isinstance(value, (str, bytes)):
|
|
|
utc_dt = self.utc_string_to_utc_datetime(value, format=format) if utc else self.string_to_utc_datetime(value, format=format)
|
|
|
return utc_dt and utc_dt > base_dt
|
|
|
|
|
|
if isinstance(value, int):
|
|
|
stamp = self.datetime_to_timestamp(base_dt if utc else self.__to_local_datetime(base_dt), ms=True)
|
|
|
return value > stamp
|
|
|
|
|
|
return None
|
|
|
|
|
|
# YEAR/MONTH/DAY
|
|
|
|
|
|
def year(self, dt: Optional[datetime.datetime] = None, utc: bool = False, timezone: Optional[str] = None, idx: int = 0) -> int:
|
|
|
return self.__datetime(dt=self.several_time_coming(dt=dt, utc=utc, timezone=timezone, years=idx), utc=utc).year
|
|
|
|
|
|
def month(self, dt: Optional[datetime.datetime] = None, utc: bool = False, timezone: Optional[str] = None, idx: int = 0) -> int:
|
|
|
return self.__datetime(dt=self.several_time_coming(dt=dt, utc=utc, timezone=timezone, months=idx), utc=utc).month
|
|
|
|
|
|
def day(self, dt: Optional[datetime.datetime] = None, utc: bool = False, timezone: Optional[str] = None, idx: int = 0) -> int:
|
|
|
return self.__datetime(dt=self.several_time_coming(dt=dt, utc=utc, timezone=timezone, days=idx), utc=utc).day
|
|
|
|
|
|
def days_of_year(self, year: Optional[int] = None, dt: Optional[datetime.datetime] = None, idx: int = 0) -> int:
|
|
|
return 366 if calendar.isleap(year or self.year(dt, idx=idx)) else 365
|
|
|
|
|
|
def days_of_month(self, year: Optional[int] = None, month: Optional[int] = None, dt: Optional[datetime.datetime] = None, idx: int = 0) -> int:
|
|
|
return calendar.monthrange(year=(year or self.year(dt, idx=idx)), month=(month or self.month(dt, idx=idx)))[-1]
|
|
|
|
|
|
# OTHER
|
|
|
|
|
|
def total_seconds(self, td: datetime.timedelta, ms: bool = True) -> int:
|
|
|
"""Total seconds in the duration."""
|
|
|
if not ms:
|
|
|
return td.days * 86400 + td.seconds
|
|
|
return ((td.days * 86400 + td.seconds) * self.SECOND_MICROSECOND + td.microseconds) / self.SECOND_MICROSECOND
|
|
|
|
|
|
def date_range(self, start_date: Union[str, datetime.date], end_date: Union[str, datetime.date], include_end: bool = False, format: Optional[str] = None, start_date_format: Optional[str] = None, end_date_format: Optional[str] = None, return_type: str = 'date', return_format: Optional[str] = None) -> Callable:
|
|
|
if isinstance(start_date, str):
|
|
|
start_date = self.string_to_date(start_date, start_date_format or format or self.DATE_FORMAT)
|
|
|
if isinstance(end_date, str):
|
|
|
end_date = self.string_to_date(end_date, end_date_format or format or self.DATE_FORMAT)
|
|
|
if include_end:
|
|
|
end_date = end_date + datetime.timedelta(1)
|
|
|
if return_type in ['string', 'str']:
|
|
|
for n in range(int((end_date - start_date).days)):
|
|
|
yield self.datetime_to_string(start_date + datetime.timedelta(n), return_format or format or self.DATE_FORMAT)
|
|
|
else:
|
|
|
for n in range(int((end_date - start_date).days)):
|
|
|
yield start_date + datetime.timedelta(n)
|
|
|
|
|
|
def week_range(self, start_date: Union[str, datetime.date], end_date: Union[str, datetime.date], format: Optional[str] = None, start_date_format: Optional[str] = None, end_date_format: Optional[str] = None, return_type: str = 'isoweek', return_format: Optional[str] = None) -> Callable:
|
|
|
if isinstance(start_date, str):
|
|
|
start_date = self.string_to_date(start_date, start_date_format or format or self.DATE_FORMAT)
|
|
|
if isinstance(end_date, str):
|
|
|
end_date = self.string_to_date(end_date, end_date_format or format or self.DATE_FORMAT)
|
|
|
start_week = ISOWeek.withdate(start_date)
|
|
|
end_week = ISOWeek.withdate(end_date)
|
|
|
if return_type in ['string', 'str']:
|
|
|
for n in range(int(end_week - start_week) + 1):
|
|
|
current_week = start_week + n
|
|
|
yield {
|
|
|
'week': current_week.isoformat(),
|
|
|
'start': self.datetime_to_string(current_week.monday(), return_format or format or self.DATE_FORMAT),
|
|
|
'end': self.datetime_to_string(current_week.sunday(), return_format or format or self.DATE_FORMAT),
|
|
|
}
|
|
|
else:
|
|
|
for n in range(int(end_week - start_week) + 1):
|
|
|
yield start_week + n
|
|
|
|
|
|
def month_range(self, start_date: Union[str, datetime.date], end_date: Union[str, datetime.date], format: Optional[str] = None, start_date_format: Optional[str] = None, end_date_format: Optional[str] = None, return_type: str = 'date', return_format: Optional[str] = None) -> Callable:
|
|
|
if isinstance(start_date, str):
|
|
|
start_date = self.string_to_date(start_date, start_date_format or format or self.DATE_FORMAT)
|
|
|
if isinstance(end_date, str):
|
|
|
end_date = self.string_to_date(end_date, end_date_format or format or self.DATE_FORMAT)
|
|
|
start_month = Month.from_date(start_date)
|
|
|
end_month = Month.from_date(end_date)
|
|
|
if return_type in ['string', 'str']:
|
|
|
for n in range(int(end_month - start_month) + 1):
|
|
|
current_month = start_month + n
|
|
|
yield {
|
|
|
'month': str(current_month),
|
|
|
'start': self.datetime_to_string(current_month.start_date, return_format or format or self.DATE_FORMAT),
|
|
|
'end': self.datetime_to_string(current_month.end_date, return_format or format or self.DATE_FORMAT),
|
|
|
}
|
|
|
else:
|
|
|
for n in range(int(end_month - start_month) + 1):
|
|
|
yield start_month + n
|
|
|
|
|
|
def quarter_range(self, start_date: Union[str, datetime.date], end_date: Union[str, datetime.date], format: Optional[str] = None, start_date_format: Optional[str] = None, end_date_format: Optional[str] = None, return_type: str = 'date', return_format: Optional[str] = None) -> Callable:
|
|
|
if isinstance(start_date, str):
|
|
|
start_date = self.string_to_date(start_date, start_date_format or format or self.DATE_FORMAT)
|
|
|
if isinstance(end_date, str):
|
|
|
end_date = self.string_to_date(end_date, end_date_format or format or self.DATE_FORMAT)
|
|
|
start_quarter = Quarter.from_date(start_date)
|
|
|
end_quarter = Quarter.from_date(end_date)
|
|
|
if return_type in ['string', 'str']:
|
|
|
for n in range(int(end_quarter - start_quarter) + 1):
|
|
|
current_quarter = start_quarter + n
|
|
|
yield {
|
|
|
'quarter': current_quarter.isoformat(),
|
|
|
'start': self.datetime_to_string(current_quarter.start_date, return_format or format or self.DATE_FORMAT),
|
|
|
'end': self.datetime_to_string(current_quarter.end_date, return_format or format or self.DATE_FORMAT),
|
|
|
}
|
|
|
else:
|
|
|
for n in range(int(end_quarter - start_quarter) + 1):
|
|
|
yield start_quarter + n
|
|
|
|
|
|
daterange = date_range
|
|
|
weekrange = week_range
|
|
|
monthrange = month_range
|
|
|
quarterrange = quarter_range
|
|
|
|
|
|
def isoweekdaycount(self, start_date: Union[str, datetime.date], end_date: Union[str, datetime.date], isoweekday: int = 7, format: Optional[str] = None, start_date_format: Optional[str] = None, end_date_format: Optional[str] = None) -> int:
|
|
|
if isinstance(start_date, str):
|
|
|
start_date = self.string_to_date(start_date, start_date_format or format or self.DATE_FORMAT)
|
|
|
if isinstance(end_date, str):
|
|
|
end_date = self.string_to_date(end_date, end_date_format or format or self.DATE_FORMAT)
|
|
|
weeks = self.datetime_delta(start_date, end_date).get('weeks')
|
|
|
# datetime.datetime.now().isoweekday() # 返回1-7,代表周一到周日,当前时间所在本周第几天
|
|
|
# datetime.datetime.now().weekday() # 返回的0-6,代表周一到周日
|
|
|
# 标准格式 %w 中,1-6表示周一到周六,0代表周日
|
|
|
start_isoweekday = start_date.isoweekday()
|
|
|
end_isoweekday = end_date.isoweekday()
|
|
|
if end_isoweekday >= start_isoweekday:
|
|
|
if start_isoweekday <= isoweekday <= end_isoweekday:
|
|
|
weeks += 1
|
|
|
else:
|
|
|
if start_isoweekday <= isoweekday or end_isoweekday >= isoweekday:
|
|
|
weeks += 1
|
|
|
return weeks
|
|
|
|
|
|
def between(self, value: TimeAnyT, start_value: TimeAnyT, end_value: TimeAnyT, timezone: Optional[str] = None, format: Optional[str] = None, start_format: Optional[str] = None, end_format: Optional[str] = None) -> bool:
|
|
|
value = self.to_datetime(value, timezone=timezone, format=format, dttype='utc')
|
|
|
start_value = self.to_datetime(start_value, timezone=timezone, format=format or start_format, dttype='utc')
|
|
|
end_value = self.to_datetime(end_value, timezone=timezone, format=format or end_format, dttype='utc')
|
|
|
|
|
|
if not start_value or not end_value:
|
|
|
raise ValueError('`start_value` and `end_value` should not empty')
|
|
|
|
|
|
if start_value > end_value:
|
|
|
start_value, end_value = end_value, start_value
|
|
|
|
|
|
return start_value <= value <= end_value
|
|
|
|
|
|
|
|
|
TC = tc = TimeConvert = TimeConvertTools()
|