Source code for badidatetime._structures
# -*- coding: utf-8 -*-
#
# badidatetime/_structures.py
#
__docformat__ = "restructuredtext en"
import importlib
from typing import NamedTuple
[docs]
class ShortFormStruct(NamedTuple):
"""
Implements a short form Badí' date and time NamedTuple.
"""
tm_year: int # range[-1842, 1161]
tm_mon: int # range[0, 19]
tm_mday: int # range[1, 19]
tm_hour: int # range[0, 23]
tm_min: int # range[0, 59]
tm_sec: float # range[0, 61]
tm_wday: int # range[0, 6]; Jalál (Saturday) is 0
tm_yday: int # range[1, 366]; day in year
# tm_isdst, may be set to 1 when daylight savings time is in effect,
# and 0 when it is not. A value of -1 indicates that this is not known,
# and will usually result in the correct state being filled in.
tm_isdst: int # 0, 1 or -1 (set only with localtime)
# abbreviation of timezone name (set only with localtime)
tm_zone: str = None
# offset east of UTC in seconds (set only with localtime)
tm_gmtoff: int = None
@property
def short(self):
"""
Indicates if this NamedTuple is a short or long form Badí' date.
"""
return True
def __repr__(self) -> str:
return (f"structures.ShortFormStruct(tm_year={self.tm_year}, "
f"tm_mon={self.tm_mon}, tm_mday={self.tm_mday}, "
f"tm_hour={self.tm_hour}, tm_min={self.tm_min}, "
f"tm_sec={self.tm_sec}, tm_wday={self.tm_wday}, "
f"tm_yday={self.tm_yday}, tm_isdst={self.tm_isdst})")
[docs]
class LongFormStruct(NamedTuple):
"""
Implements a long form Badí' date and time NamedTuple.
"""
tm_kull_i_shay: int # example, 1
tm_vahid: int # range[1, 19]
tm_year: int # range[1, 19]
tm_mon: int # range[0, 19]
tm_mday: int # range[1, 19]
tm_hour: int # range[0, 23]
tm_min: int # range[0, 59]
tm_sec: float # range[0, 61]
tm_wday: int # range[0, 6]; Jalál (Saturday) is 0
tm_yday: int # range[1, 366]; day in year
# tm_isdst, may be set to 1 when daylight savings time is in effect,
# and 0 when it is not. A value of -1 indicates that this is not known,
# and will usually result in the correct state being filled in.
tm_isdst: int # 0, 1 or -1 (set only with localtime)
# abbreviation of timezone name (set only with localtime)
tm_zone: str = None
# offset east of UTC in seconds (set only with localtime)
tm_gmtoff: int = None
@property
def short(self):
"""
Indicates if this NamedTuple is a short or long form Badí' date.
"""
return False
def __repr__(self) -> str:
return (f"structures.LongFormStruct("
f"tm_kull_i_shay={self.tm_kull_i_shay}, "
f"tm_vahid={self.tm_vahid}, tm_year={self.tm_year}, "
f"tm_mon={self.tm_mon}, tm_mday={self.tm_mday}, "
f"tm_hour={self.tm_hour}, tm_min={self.tm_min}, "
f"tm_sec={self.tm_sec}, tm_wday={self.tm_wday}, "
f"tm_yday={self.tm_yday}, tm_isdst={self.tm_isdst})")
[docs]
class struct_time:
"""
Create a structure representing a Badí' date and time.
"""
def __new__(cls, date: tuple, tzinfo=None):
"""
Creates a ShortFormStruct or LongFormStruct NamedTuple.
:param tuple date: A tuple containing the data needed to create
a NamedTuple.
:param tzinfo tzinfo: Timezone information or None.
:returns: Instance object
:rtype: ShortFormStruct or LongFormStruct
"""
self = object.__new__(cls)
super().__init__(self)
short = cls.__is_short_form(date)
if date[-1] not in (-1, 0, 1):
msg = (f"Invalid isdst '{date[-1]}', it must be in the range "
"of [-1, 1].")
raise ValueError(msg)
if short:
inst = ShortFormStruct(
*self.__fill_in_missing(date, tzinfo, short))
else:
inst = LongFormStruct(
*self.__fill_in_missing(date, tzinfo, short))
return inst
@classmethod
def __is_short_form(cls, date: tuple):
"""
Determines if the date tuple contains short or long form data.
:param tuple date: The date tuple to be processed.
:returns: If `True` then the date tuple represents a short form Badí'
date and time, if `False` date tuple represents a long form
Badí' date and time.
:rtype: bool
:raises TypeError: Wrong tuple sequence size.
"""
d_size = len(date)
if d_size == 9:
short = True
elif d_size == 11:
short = False
else:
raise TypeError("struct_time() takes a 9 or 11-sequence "
f"({d_size}-sequence given)")
return short
@classmethod
def __fill_in_missing(cls, date: tuple, tzinfo, short: bool):
"""
Fill in missing data.
:param tuple date: The date tuple to be processed.
:param tzinfo tzinfo: Timezone information or None.
:param bool short: If `True` then the date tuple represents a short
form Badí' date and time, if `False` date tuple
represents a long form Badí' date and time.
:returns: The updated date tuple.
:rtype: tuple
"""
datetime = importlib.import_module('badidatetime.datetime')
if short:
b_date = date[:3] + (None, None) + date[3:6]
else:
b_date = date[:8]
date = list(date)
dt = datetime.datetime(*b_date, tzinfo=tzinfo)
# Build out the tm_isdst, tm_zone and tm_gmtoff.
if tzinfo:
dst = tzinfo.dst(dt)
if hasattr(dst, 'total_seconds'):
ts = dst.total_seconds()
if ts:
date[-1] = 1
elif ts == 0:
date[-1] = 0
offset = dt.utcoffset()
total_seconds = offset.total_seconds() if offset else None
if tzinfo and hasattr(tzinfo, 'tzname'):
tm_zone = tzinfo.tzname(dt)
else:
tm_zone = dt.tzname()
date += [tm_zone, total_seconds]
return tuple(date)