1
0
mirror of synced 2024-11-30 16:54:30 +01:00
bemaniutils/bemani/common/time.py

175 lines
6.2 KiB
Python

import calendar
import datetime
from dateutil import tz
from typing import List, Optional
from typing_extensions import Final
class Time:
"""
Python's time stuff sucks, so this provides a sane interface to getting
standard unix timestamps at UTC timezone given various parameters.
"""
SECONDS_IN_MINUTE: Final[int] = 60
SECONDS_IN_HOUR: Final[int] = 3600
SECONDS_IN_DAY: Final[int] = 86400
SECONDS_IN_WEEK: Final[int] = 604800
@staticmethod
def now() -> int:
"""
Returns the current unix timestamp in the UTC timezone.
"""
return calendar.timegm(datetime.datetime.utcnow().timetuple())
@staticmethod
def end_of_today() -> int:
"""
Returns the unix timestamp for the end of today in UTC timezone.
"""
now = datetime.datetime.utcnow().date()
beginning_of_day = datetime.datetime(
now.year, now.month, now.day, tzinfo=tz.tzutc()
)
end_of_day = beginning_of_day + datetime.timedelta(days=1)
return calendar.timegm(end_of_day.timetuple())
@staticmethod
def beginning_of_today() -> int:
"""
Returns the unix timestamp for the beginning of today in UTC timezone.
"""
now = datetime.datetime.utcnow().date()
beginning_of_day = datetime.datetime(
now.year, now.month, now.day, tzinfo=tz.tzutc()
)
return calendar.timegm(beginning_of_day.timetuple())
@staticmethod
def end_of_this_week() -> int:
"""
Returns the unix timestamp for the end of this week in UTC timezone.
"""
now = datetime.datetime.utcnow().date()
this_week = now - datetime.timedelta(days=now.timetuple().tm_wday)
next_week = this_week + datetime.timedelta(days=7)
return calendar.timegm(next_week.timetuple())
@staticmethod
def beginning_of_this_week() -> int:
"""
Returns the unix timestamp for the beginning of this week in UTC timezone.
"""
now = datetime.datetime.utcnow().date()
this_week = now - datetime.timedelta(days=now.timetuple().tm_wday)
return calendar.timegm(this_week.timetuple())
@staticmethod
def end_of_this_month() -> int:
"""
Returns the unix timestamp for the end of this month in UTC timezone.
"""
now = datetime.datetime.utcnow().date()
return Time.timestamp_from_date(now.year, now.month + 1, 1)
@staticmethod
def beginning_of_this_month() -> int:
"""
Returns the unix timestamp for the beginning of this month in UTC timezone.
"""
now = datetime.datetime.utcnow().date()
this_month = datetime.date(now.year, now.month, 1)
return calendar.timegm(this_month.timetuple())
@staticmethod
def todays_date() -> List[int]:
"""
Returns a [year, month, day] list representing today's date.
"""
now = datetime.datetime.utcnow().date()
return [now.year, now.month, now.day]
@staticmethod
def yesterdays_date() -> List[int]:
"""
Returns a [year, month, day] list representing yesterday's date.
"""
now = datetime.datetime.utcnow().date()
yesterday = now - datetime.timedelta(days=1)
return [yesterday.year, yesterday.month, yesterday.day]
@staticmethod
def week_in_days_since_epoch(timestamp: Optional[int] = None) -> int:
"""
Returns the day number of the beginning of this week, where day zero is
the unix epoch at UTC timezone. So if we were one week in, this would return
7. If a timestamp is provided, returns the same value from that reverence
point instead of now.
"""
if timestamp is None:
date = datetime.datetime.utcnow().date()
else:
date = datetime.datetime.utcfromtimestamp(timestamp).date()
week = date - datetime.timedelta(days=date.timetuple().tm_wday)
return (week - datetime.date(1970, 1, 1)).days
@staticmethod
def days_into_year(timestamp: Optional[int] = None) -> List[int]:
"""
Returns a [year, days] list representing the current year, and number
of days into the current year. If a timestamp is provided, returns the
same value from that reverence point instead of now.
"""
if timestamp is None:
date = datetime.datetime.utcnow().date().timetuple()
else:
date = datetime.datetime.utcfromtimestamp(timestamp).date().timetuple()
return [date.tm_year, date.tm_yday]
@staticmethod
def days_into_week(timestamp: Optional[int] = None) -> int:
"""
Returns an integer representing the number of days into the current week
we are, with 0 = monday, 1 = tuesday, etc. If a timestamp is provided,
returns the same value from that reverence point instead of now.
"""
if timestamp is None:
date = datetime.datetime.utcnow().date().timetuple()
else:
date = datetime.datetime.utcfromtimestamp(timestamp).date().timetuple()
return date.tm_wday
@staticmethod
def timestamp_from_date(year: int, month: int = 1, day: int = 1) -> int:
"""
Given a date (either a year, year/month, or year/month/day), returns
the unix timestamp from UTC of that date. Supports out of bounds
indexing on month.
"""
while month < 1:
year = year - 1
month = month + 12
while month > 12:
year = year + 1
month = month - 12
date = datetime.datetime(year, month, day, tzinfo=tz.tzutc())
return calendar.timegm(date.timetuple())
@staticmethod
def date_from_timestamp(timestamp: int) -> List[int]:
"""
Returns a [year, month, day] given a UTC unix timestamp.
"""
date = datetime.datetime.utcfromtimestamp(timestamp).date()
return [date.year, date.month, date.day]
@staticmethod
def format(timestamp: int, formatstr: str) -> str:
"""
Returns a unix timestamp based at UTC timezone formatted as a string.
"""
return datetime.datetime.utcfromtimestamp(timestamp).strftime(formatstr)