Python 3.10 is the minimum supported version. Code cleanup.

This commit is contained in:
Josh W 2024-11-27 12:03:41 -05:00
parent c31d676a4f
commit 344a7cbae4
8 changed files with 123 additions and 137 deletions

View file

@ -7,7 +7,7 @@ readme = "README.md"
packages = [{include = "dnidatetime", from = "src"}] packages = [{include = "dnidatetime", from = "src"}]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.11" python = ">=3.10"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
pylint = "^3.1.0" pylint = "^3.1.0"

View file

@ -2,11 +2,10 @@
from collections import OrderedDict from collections import OrderedDict
from datetime import datetime, timezone from datetime import datetime, timezone
from typing import Tuple, TypedDict from typing import TypedDict
#: Type alias for a seven-integer tuple used in a datetime timestamp. #: Type alias for a seven-integer tuple used in a datetime timestamp.
DniDateTimeTuple = Tuple[int, int, int, int, int, int, int] DniDateTimeTuple = tuple[int, int, int, int, int, int, int]
class DniUnitType(TypedDict): class DniUnitType(TypedDict):
@ -64,34 +63,34 @@ DNI_EPOCH_HAHR = 9647
#: delta_ms_1900_to_1970 = -2208988800000 #: delta_ms_1900_to_1970 = -2208988800000
#: leap_ms = leap_sec_from_ietf * 1000 + delta_ms_1900_to_1970 #: leap_ms = leap_sec_from_ietf * 1000 + delta_ms_1900_to_1970
LEAP_MS_FROM_EPOCH = [ LEAP_MS_FROM_EPOCH = [
63072000000, # 1 Jan 1972 63072000000, # 1 Jan 1972
78796800000, # 1 Jul 1972 78796800000, # 1 Jul 1972
94694400000, # 1 Jan 1973 94694400000, # 1 Jan 1973
126230400000, # 1 Jan 1974 126230400000, # 1 Jan 1974
157766400000, # 1 Jan 1975 157766400000, # 1 Jan 1975
189302400000, # 1 Jan 1976 189302400000, # 1 Jan 1976
220924800000, # 1 Jan 1977 220924800000, # 1 Jan 1977
252460800000, # 1 Jan 1978 252460800000, # 1 Jan 1978
283996800000, # 1 Jan 1979 283996800000, # 1 Jan 1979
315532800000, # 1 Jan 1980 315532800000, # 1 Jan 1980
362793600000, # 1 Jul 1981 362793600000, # 1 Jul 1981
394329600000, # 1 Jul 1982 394329600000, # 1 Jul 1982
425865600000, # 1 Jul 1983 425865600000, # 1 Jul 1983
489024000000, # 1 Jul 1985 489024000000, # 1 Jul 1985
567993600000, # 1 Jan 1988 567993600000, # 1 Jan 1988
631152000000, # 1 Jan 1990 631152000000, # 1 Jan 1990
662688000000, # 1 Jan 1991 662688000000, # 1 Jan 1991
709948800000, # 1 Jul 1992 709948800000, # 1 Jul 1992
741484800000, # 1 Jul 1993 741484800000, # 1 Jul 1993
773020800000, # 1 Jul 1994 773020800000, # 1 Jul 1994
820454400000, # 1 Jan 1996 820454400000, # 1 Jan 1996
867715200000, # 1 Jul 1997 867715200000, # 1 Jul 1997
915148800000, # 1 Jan 1999 915148800000, # 1 Jan 1999
1136073600000, # 1 Jan 2006 1136073600000, # 1 Jan 2006
1230768000000, # 1 Jan 2009 1230768000000, # 1 Jan 2009
1341100800000, # 1 Jul 2012 1341100800000, # 1 Jul 2012
1435708800000, # 1 Jul 2015 1435708800000, # 1 Jul 2015
1483228800000, # 1 Jan 2017 1483228800000, # 1 Jan 2017
] ]
#: A carry-over from the Python datetime module for timedelta objects. Might #: A carry-over from the Python datetime module for timedelta objects. Might

View file

@ -2,10 +2,8 @@
from datetime import datetime, timezone from datetime import datetime, timezone
from math import floor from math import floor
from typing import Dict, Optional, Tuple
from .constants import ( from .constants import (
DniDateTimeTuple,
DNI_EPOCH_EDT, DNI_EPOCH_EDT,
DNI_EPOCH_HAHR, DNI_EPOCH_HAHR,
DNI_UNITS, DNI_UNITS,
@ -13,17 +11,16 @@ from .constants import (
MIN_DNI_ORDINAL, MIN_DNI_ORDINAL,
MS_PER_HAHR, MS_PER_HAHR,
MS_PER_PRORAHN, MS_PER_PRORAHN,
YAHRTEE_BEFORE_VAILEE YAHRTEE_BEFORE_VAILEE,
DniDateTimeTuple,
) )
from .utils import ( from .utils import (
check_dni_date_fields, check_dni_date_fields,
get_adj_ms_from_epoch, get_adj_ms_from_epoch,
get_ms_from_epoch, get_ms_from_epoch,
is_timezone_aware is_timezone_aware,
) )
# Number of yahrtee (days) in a hahr (year) == 290. # Number of yahrtee (days) in a hahr (year) == 290.
_YAHR_IN_HAHR = DNI_UNITS["yahr"]["max"] * DNI_UNITS["vailee"]["max"] _YAHR_IN_HAHR = DNI_UNITS["yahr"]["max"] * DNI_UNITS["vailee"]["max"]
@ -35,7 +32,7 @@ def hvy2ord(hahr: int, vailee: int, yahr: int) -> int:
return yahr_before_hahr + YAHRTEE_BEFORE_VAILEE[ok_vailee] + ok_yahr return yahr_before_hahr + YAHRTEE_BEFORE_VAILEE[ok_vailee] + ok_yahr
def ord2hvy(ordinal: int) -> Tuple[int, int, int]: def ord2hvy(ordinal: int) -> tuple[int, int, int]:
"""Find the exact hahr, vailee, and yahr from an ordinal value of """Find the exact hahr, vailee, and yahr from an ordinal value of
yahrtee. yahrtee.
""" """
@ -53,19 +50,14 @@ def ord2hvy(ordinal: int) -> Tuple[int, int, int]:
vailee = DNI_UNITS["vailee"]["max"] vailee = DNI_UNITS["vailee"]["max"]
yahr = DNI_UNITS["yahr"]["max"] yahr = DNI_UNITS["yahr"]["max"]
else: else:
vailee, yahr = divmod( vailee, yahr = divmod(rem + DNI_UNITS["yahr"]["max"], DNI_UNITS["yahr"]["max"])
rem + DNI_UNITS["yahr"]["max"],
DNI_UNITS["yahr"]["max"]
)
if yahr == 0: if yahr == 0:
vailee -= 1 vailee -= 1
yahr = DNI_UNITS["yahr"]["max"] yahr = DNI_UNITS["yahr"]["max"]
return hahr, vailee, yahr return hahr, vailee, yahr
def earth_to_dni( def earth_to_dni(date_time: datetime | None = None) -> DniDateTimeTuple:
date_time: Optional[datetime] = None
) -> DniDateTimeTuple:
"""Converts an Earth gregorian datetime to a D'Ni datetime.""" """Converts an Earth gregorian datetime to a D'Ni datetime."""
if date_time is None: if date_time is None:
moment = datetime.now(timezone.utc) moment = datetime.now(timezone.utc)
@ -75,7 +67,7 @@ def earth_to_dni(
else: else:
raise ValueError("Supplied datetime must be timezone aware.") raise ValueError("Supplied datetime must be timezone aware.")
dni_dt: Dict[str, int] = {} dni_dt: dict[str, int] = {}
stamp = get_adj_ms_from_epoch(moment) stamp = get_adj_ms_from_epoch(moment)
dni_epoch = get_adj_ms_from_epoch(DNI_EPOCH_EDT) dni_epoch = get_adj_ms_from_epoch(DNI_EPOCH_EDT)
@ -125,13 +117,13 @@ def dni_to_earth(dni_date_time: DniDateTimeTuple) -> datetime:
"D'Ni datetime must be in the form of a timetuple. " "D'Ni datetime must be in the form of a timetuple. "
"See DniDateTime.timetuple()." "See DniDateTime.timetuple()."
), ),
dni_date_time dni_date_time,
) )
if len(dni_date_time) != 7: if len(dni_date_time) != 7:
raise ValueError( raise ValueError(
"The D'Ni timetuple is malformed. See DniDateTime.timetuple().", "The D'Ni timetuple is malformed. See DniDateTime.timetuple().",
dni_date_time dni_date_time,
) )
temp_units = list(dni_date_time) temp_units = list(dni_date_time)

View file

@ -1,8 +1,10 @@
"""The DniDate class.""" """The DniDate class."""
from typing import Any, Optional, TYPE_CHECKING, Union from __future__ import annotations
from .constants import DniDateTimeTuple, DNI_UNITS, MAX_DNI_ORDINAL from typing import TYPE_CHECKING, Any
from .constants import DNI_UNITS, MAX_DNI_ORDINAL, DniDateTimeTuple
from .conversions import hvy2ord, ord2hvy from .conversions import hvy2ord, ord2hvy
from .dnitimedelta import DniTimedelta from .dnitimedelta import DniTimedelta
from .utils import check_dni_date_fields, cmp from .utils import check_dni_date_fields, cmp
@ -19,8 +21,8 @@ class DniDate:
_yahr: int _yahr: int
# Class properties # Class properties
min: "DniDate" min: DniDate
max: "DniDate" max: DniDate
resolution: DniTimedelta resolution: DniTimedelta
def __new__( def __new__(
@ -28,7 +30,7 @@ class DniDate:
hahr: int = DNI_UNITS["hahr"]["min"], hahr: int = DNI_UNITS["hahr"]["min"],
vailee: int = DNI_UNITS["vailee"]["min"], vailee: int = DNI_UNITS["vailee"]["min"],
yahr: int = DNI_UNITS["yahr"]["min"], yahr: int = DNI_UNITS["yahr"]["min"],
) -> "DniDate": ) -> DniDate:
if isinstance(hahr, int): if isinstance(hahr, int):
hahr, vailee, yahr = check_dni_date_fields(hahr, vailee, yahr) hahr, vailee, yahr = check_dni_date_fields(hahr, vailee, yahr)
self = object.__new__(cls) self = object.__new__(cls)
@ -39,7 +41,7 @@ class DniDate:
return NotImplemented return NotImplemented
@classmethod @classmethod
def from_dnitimestamp(cls, prorahntee: int) -> "DniDate": def from_dnitimestamp(cls, prorahntee: int) -> DniDate:
"""Construct a D'Ni date from a D'Ni timestamp.""" """Construct a D'Ni date from a D'Ni timestamp."""
yahrtee = prorahntee // DNI_UNITS["yahr"]["total_pro"] yahrtee = prorahntee // DNI_UNITS["yahr"]["total_pro"]
return cls.from_ordinal(yahrtee) return cls.from_ordinal(yahrtee)
@ -50,7 +52,7 @@ class DniDate:
return NotImplemented return NotImplemented
@classmethod @classmethod
def from_isoformat(cls, date_str: str) -> "DniDate": def from_isoformat(cls, date_str: str) -> DniDate:
if not isinstance(date_str, str): if not isinstance(date_str, str):
raise TypeError("from_isoformat: argument must be str.") raise TypeError("from_isoformat: argument must be str.")
@ -64,7 +66,7 @@ class DniDate:
raise ValueError(f"Invalid isoformat string: {date_str!r}") from exc raise ValueError(f"Invalid isoformat string: {date_str!r}") from exc
@classmethod @classmethod
def from_ordinal(cls, yahrtee: int) -> "DniDate": def from_ordinal(cls, yahrtee: int) -> DniDate:
"""Construct a D'ni date from a D'ni ordinal.""" """Construct a D'ni date from a D'ni ordinal."""
hahr, vailee, yahr = ord2hvy(yahrtee) hahr, vailee, yahr = ord2hvy(yahrtee)
return cls(hahr, vailee, yahr) return cls(hahr, vailee, yahr)
@ -105,10 +107,10 @@ class DniDate:
def replace( def replace(
self, self,
hahr: Optional[int] = None, hahr: int | None = None,
vailee: Optional[int] = None, vailee: int | None = None,
yahr: Optional[int] = None, yahr: int | None = None,
) -> "DniDate": ) -> DniDate:
"""Return a new D'ni date with new values for the specified fields.""" """Return a new D'ni date with new values for the specified fields."""
if hahr is None: if hahr is None:
hahr = self._hahr hahr = self._hahr
@ -119,7 +121,7 @@ class DniDate:
return type(self)(hahr, vailee, yahr) return type(self)(hahr, vailee, yahr)
# Arithmetic # Arithmetic
def __add__(self, other: Any) -> "DniDate": def __add__(self, other: Any) -> DniDate:
if isinstance(other, DniTimedelta): if isinstance(other, DniTimedelta):
ordinal = self.to_ordinal() + other._yahrtee ordinal = self.to_ordinal() + other._yahrtee
if 0 < ordinal <= MAX_DNI_ORDINAL: if 0 < ordinal <= MAX_DNI_ORDINAL:
@ -129,7 +131,7 @@ class DniDate:
__radd__ = __add__ __radd__ = __add__
def __sub__(self, other: Any) -> Union["DniDate", DniTimedelta]: def __sub__(self, other: Any) -> DniDate | DniTimedelta:
if isinstance(other, DniTimedelta): if isinstance(other, DniTimedelta):
return self + DniTimedelta(-other._yahrtee) return self + DniTimedelta(-other._yahrtee)
if isinstance(other, DniDate): if isinstance(other, DniDate):

View file

@ -1,14 +1,11 @@
"""The DniDatetime class.""" """The DniDatetime class."""
from datetime import datetime, timedelta, timezone from __future__ import annotations
from typing import Any, Optional, TYPE_CHECKING, Union
from .constants import ( from datetime import datetime, timedelta, timezone
DniDateTimeTuple, from typing import TYPE_CHECKING, Any
DNI_EPOCH_HAHR,
DNI_UNITS, from .constants import DNI_EPOCH_HAHR, DNI_UNITS, MAX_DNI_ORDINAL, DniDateTimeTuple
MAX_DNI_ORDINAL
)
from .conversions import dni_to_earth, earth_to_dni, hvy2ord from .conversions import dni_to_earth, earth_to_dni, hvy2ord
from .dnidate import DniDate from .dnidate import DniDate
from .dnitime import DniTime from .dnitime import DniTime
@ -31,8 +28,8 @@ class DniDatetime:
_prorahn: int _prorahn: int
# Class properties # Class properties
min: "DniDatetime" min: DniDatetime
max: "DniDatetime" max: DniDatetime
resolution: DniTimedelta resolution: DniTimedelta
def __new__( def __new__(
@ -44,7 +41,7 @@ class DniDatetime:
tahvo: int = DNI_UNITS["tahvo"]["min"], tahvo: int = DNI_UNITS["tahvo"]["min"],
gorahn: int = DNI_UNITS["gorahn"]["min"], gorahn: int = DNI_UNITS["gorahn"]["min"],
prorahn: int = DNI_UNITS["prorahn"]["min"], prorahn: int = DNI_UNITS["prorahn"]["min"],
) -> "DniDatetime": ) -> DniDatetime:
if isinstance(hahr, int): if isinstance(hahr, int):
hahr, vailee, yahr = check_dni_date_fields(hahr, vailee, yahr) hahr, vailee, yahr = check_dni_date_fields(hahr, vailee, yahr)
gahrtahvo, tahvo, gorahn, prorahn = check_dni_time_fields( gahrtahvo, tahvo, gorahn, prorahn = check_dni_time_fields(
@ -121,13 +118,13 @@ class DniDatetime:
def replace( def replace(
self, self,
hahr: Optional[int] = None, hahr: int | None = None,
vailee: Optional[int] = None, vailee: int | None = None,
yahr: Optional[int] = None, yahr: int | None = None,
gahrtahvo: Optional[int] = None, gahrtahvo: int | None = None,
tahvo: Optional[int] = None, tahvo: int | None = None,
gorahn: Optional[int] = None, gorahn: int | None = None,
prorahn: Optional[int] = None, prorahn: int | None = None,
) -> "DniDatetime": ) -> "DniDatetime":
"""Return a new D'ni datetime with new values for the specified fields.""" """Return a new D'ni datetime with new values for the specified fields."""
if hahr is None: if hahr is None:
@ -147,7 +144,7 @@ class DniDatetime:
return type(self)(hahr, vailee, yahr, gahrtahvo, tahvo, gorahn, prorahn) return type(self)(hahr, vailee, yahr, gahrtahvo, tahvo, gorahn, prorahn)
# Arithmetic # Arithmetic
def __add__(self, other: Any) -> "DniDatetime": def __add__(self, other: Any) -> DniDatetime:
if not isinstance(other, (timedelta, DniTimedelta)): if not isinstance(other, (timedelta, DniTimedelta)):
return NotImplemented return NotImplemented
if isinstance(other, timedelta): if isinstance(other, timedelta):
@ -173,7 +170,7 @@ class DniDatetime:
__radd__ = __add__ __radd__ = __add__
def __sub__(self, other: Any) -> Union["DniDatetime", DniTimedelta]: def __sub__(self, other: Any) -> DniDatetime | DniTimedelta:
if not isinstance(other, DniDatetime): if not isinstance(other, DniDatetime):
if isinstance(other, timedelta): if isinstance(other, timedelta):
return self + -other return self + -other
@ -266,7 +263,7 @@ class DniDatetime:
def timestamp(self) -> int: def timestamp(self) -> int:
"""Return total number of prorahntee since the D'ni epoch.""" """Return total number of prorahntee since the D'ni epoch."""
return (self - DNI_EPOCH_DDT).total_prorahntee() #type: ignore return (self - DNI_EPOCH_DDT).total_prorahntee() # type: ignore
def timetuple(self) -> DniDateTimeTuple: def timetuple(self) -> DniDateTimeTuple:
"""Return the DniDateTime in the form of a timetuple.""" """Return the DniDateTime in the form of a timetuple."""
@ -277,7 +274,7 @@ class DniDatetime:
self._gahrtahvo, self._gahrtahvo,
self._tahvo, self._tahvo,
self._gorahn, self._gorahn,
self._prorahn self._prorahn,
) )
def to_ordinal(self) -> int: def to_ordinal(self) -> int:
@ -285,7 +282,7 @@ class DniDatetime:
return hvy2ord(self._hahr, self._vailee, self._yahr) return hvy2ord(self._hahr, self._vailee, self._yahr)
@classmethod @classmethod
def combine(cls, date_obj: DniDate, time_obj: DniTime) -> "DniDatetime": def combine(cls, date_obj: DniDate, time_obj: DniTime) -> DniDatetime:
"""Construct a D'ni datetime from a given DniDate and DniTime.""" """Construct a D'ni datetime from a given DniDate and DniTime."""
# pylint: disable=protected-access # pylint: disable=protected-access
if not isinstance(date_obj, DniDate): if not isinstance(date_obj, DniDate):
@ -302,12 +299,12 @@ class DniDatetime:
time_obj._prorahn, time_obj._prorahn,
) )
def to_earth(self, tz: Optional[timezone] = timezone.utc) -> datetime: def to_earth(self, tz: timezone | None = timezone.utc) -> datetime:
"""Create an earth datetime from a DniDatetime.""" """Create an earth datetime from a DniDatetime."""
return dni_to_earth(self.timetuple()).astimezone(tz) return dni_to_earth(self.timetuple()).astimezone(tz)
@classmethod @classmethod
def from_earth(cls, date_time: datetime) -> "DniDatetime": def from_earth(cls, date_time: datetime) -> DniDatetime:
"""Create a DniDatetime from an earth datetime.""" """Create a DniDatetime from an earth datetime."""
ddt = earth_to_dni(date_time) ddt = earth_to_dni(date_time)
return cls(*ddt) return cls(*ddt)

View file

@ -1,6 +1,8 @@
"""The DniTime class.""" """The DniTime class."""
from typing import Any, Optional, TYPE_CHECKING from __future__ import annotations
from typing import TYPE_CHECKING, Any
from .constants import DNI_UNITS from .constants import DNI_UNITS
from .dnitimedelta import DniTimedelta from .dnitimedelta import DniTimedelta
@ -19,8 +21,8 @@ class DniTime:
_prorahn: int _prorahn: int
# Class properties # Class properties
min: "DniTime" min: DniTime
max: "DniTime" max: DniTime
resolution: DniTimedelta resolution: DniTimedelta
def __new__( def __new__(
@ -29,7 +31,7 @@ class DniTime:
tahvo: int = DNI_UNITS["tahvo"]["min"], tahvo: int = DNI_UNITS["tahvo"]["min"],
gorahn: int = DNI_UNITS["gorahn"]["min"], gorahn: int = DNI_UNITS["gorahn"]["min"],
prorahn: int = DNI_UNITS["prorahn"]["min"], prorahn: int = DNI_UNITS["prorahn"]["min"],
) -> "DniTime": ) -> DniTime:
gahrtahvo, tahvo, gorahn, prorahn = check_dni_time_fields( gahrtahvo, tahvo, gorahn, prorahn = check_dni_time_fields(
gahrtahvo, tahvo, gorahn, prorahn gahrtahvo, tahvo, gorahn, prorahn
) )
@ -41,7 +43,7 @@ class DniTime:
return self return self
@classmethod @classmethod
def from_isoformat(cls, time_str: str) -> "DniTime": def from_isoformat(cls, time_str: str) -> DniTime:
if not isinstance(time_str, str): if not isinstance(time_str, str):
raise TypeError("from_isoformat: argument must be str.") raise TypeError("from_isoformat: argument must be str.")
@ -95,11 +97,11 @@ class DniTime:
def replace( def replace(
self, self,
gahrtahvo: Optional[int] = None, gahrtahvo: int | None = None,
tahvo: Optional[int] = None, tahvo: int | None = None,
gorahn: Optional[int] = None, gorahn: int | None = None,
prorahn: Optional[int] = None, prorahn: int | None = None,
) -> "DniTime": ) -> DniTime:
"""Return a new D'ni time with new values for the specified fields.""" """Return a new D'ni time with new values for the specified fields."""
if gahrtahvo is None: if gahrtahvo is None:
gahrtahvo = self._gahrtahvo gahrtahvo = self._gahrtahvo

View file

@ -1,8 +1,10 @@
"""The DniTimedelta class.""" """The DniTimedelta class."""
from __future__ import annotations
from datetime import timedelta from datetime import timedelta
from math import modf from math import modf
from typing import Any, Tuple, TYPE_CHECKING, Union from typing import TYPE_CHECKING, Any, Self
from .constants import DNI_UNITS, MAX_DNI_DELTA_YAHRTEE, MS_PER_PRORAHN from .constants import DNI_UNITS, MAX_DNI_DELTA_YAHRTEE, MS_PER_PRORAHN
from .utils import cmp, divide_and_round from .utils import cmp, divide_and_round
@ -19,19 +21,19 @@ class DniTimedelta:
_prorahntee: int _prorahntee: int
# Class properties # Class properties
min: "DniTimedelta" min: DniTimedelta
max: "DniTimedelta" max: DniTimedelta
resolution: "DniTimedelta" resolution: DniTimedelta
def __new__( def __new__(
cls, cls,
yahrtee: Union[float, int] = 0, yahrtee: float | int = 0,
pahrtahvotee: Union[float, int] = 0, pahrtahvotee: float | int = 0,
prorahntee: Union[float, int] = 0, prorahntee: float | int = 0,
gorahntee: Union[float, int] = 0, gorahntee: float | int = 0,
tahvotee: Union[float, int] = 0, tahvotee: float | int = 0,
gahrtahvotee: Union[float, int] = 0, gahrtahvotee: float | int = 0,
vaileetee: Union[float, int] = 0, vaileetee: float | int = 0,
) -> "DniTimedelta": ) -> "DniTimedelta":
# Final values are integer. # Final values are integer.
yahr: int = 0 yahr: int = 0
@ -165,7 +167,7 @@ class DniTimedelta:
return self._prorahntee return self._prorahntee
# Arithmetic functions # Arithmetic functions
def __add__(self, other: Any) -> "DniTimedelta": def __add__(self, other: Any) -> DniTimedelta:
if isinstance(other, (timedelta, DniTimedelta)): if isinstance(other, (timedelta, DniTimedelta)):
if isinstance(other, timedelta): if isinstance(other, timedelta):
other = self.from_timedelta(other) other = self.from_timedelta(other)
@ -178,7 +180,7 @@ class DniTimedelta:
__radd__ = __add__ __radd__ = __add__
def __sub__(self, other: Any) -> "DniTimedelta": def __sub__(self, other: Any) -> DniTimedelta:
if isinstance(other, (timedelta, DniTimedelta)): if isinstance(other, (timedelta, DniTimedelta)):
if isinstance(other, timedelta): if isinstance(other, timedelta):
other = self.from_timedelta(other) other = self.from_timedelta(other)
@ -189,25 +191,25 @@ class DniTimedelta:
) )
return NotImplemented return NotImplemented
def __rsub__(self, other: Any) -> "DniTimedelta": def __rsub__(self, other: Any) -> DniTimedelta:
if isinstance(other, (timedelta, DniTimedelta)): if isinstance(other, (timedelta, DniTimedelta)):
if isinstance(other, timedelta): if isinstance(other, timedelta):
other = self.from_timedelta(other) other = self.from_timedelta(other)
return -self + other return -self + other
return NotImplemented return NotImplemented
def __neg__(self) -> "DniTimedelta": def __neg__(self) -> DniTimedelta:
return DniTimedelta(-self._yahrtee, -self._pahrtahvotee, -self._prorahntee) return DniTimedelta(-self._yahrtee, -self._pahrtahvotee, -self._prorahntee)
def __pos__(self) -> "DniTimedelta": def __pos__(self) -> DniTimedelta:
return self return self
def __abs__(self) -> "DniTimedelta": def __abs__(self) -> DniTimedelta:
if self._yahrtee < 0: if self._yahrtee < 0:
return -self return -self
return self return self
def __mul__(self, other: Any) -> "DniTimedelta": def __mul__(self, other: Any) -> DniTimedelta:
if isinstance(other, int): if isinstance(other, int):
return DniTimedelta( return DniTimedelta(
self._yahrtee * other, self._yahrtee * other,
@ -222,7 +224,7 @@ class DniTimedelta:
__rmul__ = __mul__ __rmul__ = __mul__
def __floordiv__(self, other: Any) -> Union["DniTimedelta", int]: def __floordiv__(self, other: Any) -> DniTimedelta | int:
if not isinstance(other, (int, DniTimedelta)): if not isinstance(other, (int, DniTimedelta)):
return NotImplemented return NotImplemented
pro = self.total_prorahntee() pro = self.total_prorahntee()
@ -231,7 +233,7 @@ class DniTimedelta:
if isinstance(other, int): if isinstance(other, int):
return DniTimedelta(0, 0, pro // other) return DniTimedelta(0, 0, pro // other)
def __truediv__(self, other: Any) -> Union["DniTimedelta", float]: def __truediv__(self, other: Any) -> DniTimedelta | float:
if not isinstance(other, (float, int, DniTimedelta)): if not isinstance(other, (float, int, DniTimedelta)):
return NotImplemented return NotImplemented
pro = self.total_prorahntee() pro = self.total_prorahntee()
@ -243,13 +245,13 @@ class DniTimedelta:
if isinstance(other, int): if isinstance(other, int):
return DniTimedelta(0, 0, divide_and_round(pro, other)) return DniTimedelta(0, 0, divide_and_round(pro, other))
def __mod__(self, other: Any) -> "DniTimedelta": def __mod__(self, other: Any) -> DniTimedelta:
if isinstance(other, DniTimedelta): if isinstance(other, DniTimedelta):
rem = self.total_prorahntee() % other.total_prorahntee() rem = self.total_prorahntee() % other.total_prorahntee()
return DniTimedelta(0, 0, rem) return DniTimedelta(0, 0, rem)
return NotImplemented return NotImplemented
def __divmod__(self, other: Any) -> Tuple[int, "DniTimedelta"]: def __divmod__(self, other: Any) -> tuple[int, DniTimedelta]:
if isinstance(other, DniTimedelta): if isinstance(other, DniTimedelta):
quot, rem = divmod(self.total_prorahntee(), other.total_prorahntee()) quot, rem = divmod(self.total_prorahntee(), other.total_prorahntee())
return quot, DniTimedelta(0, 0, rem) return quot, DniTimedelta(0, 0, rem)
@ -290,7 +292,7 @@ class DniTimedelta:
return self._yahrtee != 0 or self._pahrtahvotee != 0 or self._prorahntee != 0 return self._yahrtee != 0 or self._pahrtahvotee != 0 or self._prorahntee != 0
@classmethod @classmethod
def from_timedelta(cls, delta: timedelta) -> "DniTimedelta": def from_timedelta(cls, delta: timedelta) -> DniTimedelta:
"""Converts a normal timedelta to a D'Ni timedelta.""" """Converts a normal timedelta to a D'Ni timedelta."""
prorahntee = delta.total_seconds() * 1000 / MS_PER_PRORAHN prorahntee = delta.total_seconds() * 1000 / MS_PER_PRORAHN
return cls(prorahntee=prorahntee) return cls(prorahntee=prorahntee)

View file

@ -3,7 +3,7 @@
# pylint: disable=line-too-long # pylint: disable=line-too-long
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from typing import Any, Optional, Tuple, Union from typing import Any
from .constants import DNI_UNITS, EARTH_EPOCH, LEAP_MS_FROM_EPOCH from .constants import DNI_UNITS, EARTH_EPOCH, LEAP_MS_FROM_EPOCH
@ -18,7 +18,7 @@ def cmp(x: Any, y: Any) -> int:
return 0 if x == y else 1 if x > y else -1 return 0 if x == y else 1 if x > y else -1
def divide_and_round(a: Union[float, int], b: Union[float, int]) -> int: def divide_and_round(a: float | int, b: float | int) -> int:
"""Divide a by b and round result to the nearest integer. When the ratio """Divide a by b and round result to the nearest integer. When the ratio
is exactly half-way between two integers, the even integer is returned. is exactly half-way between two integers, the even integer is returned.
""" """
@ -35,7 +35,7 @@ def check_dni_date_fields(
hahr: int = DNI_UNITS["hahr"]["min"], hahr: int = DNI_UNITS["hahr"]["min"],
vailee: int = DNI_UNITS["vailee"]["min"], vailee: int = DNI_UNITS["vailee"]["min"],
yahr: int = DNI_UNITS["yahr"]["min"], yahr: int = DNI_UNITS["yahr"]["min"],
) -> Tuple[int, int, int]: ) -> tuple[int, int, int]:
"""Verifies the D'Ni date fields are within proper boundaries.""" """Verifies the D'Ni date fields are within proper boundaries."""
if not DNI_UNITS["hahr"]["min"] <= hahr <= DNI_UNITS["hahr"]["max"]: if not DNI_UNITS["hahr"]["min"] <= hahr <= DNI_UNITS["hahr"]["max"]:
raise ValueError( raise ValueError(
@ -60,7 +60,7 @@ def check_dni_time_fields(
tahvo: int = DNI_UNITS["tahvo"]["min"], tahvo: int = DNI_UNITS["tahvo"]["min"],
gorahn: int = DNI_UNITS["gorahn"]["min"], gorahn: int = DNI_UNITS["gorahn"]["min"],
prorahn: int = DNI_UNITS["prorahn"]["min"], prorahn: int = DNI_UNITS["prorahn"]["min"],
) -> Tuple[int, int, int, int]: ) -> tuple[int, int, int, int]:
"""Verifies the D'Ni time fields are within proper boundaries.""" """Verifies the D'Ni time fields are within proper boundaries."""
if ( if (
not DNI_UNITS["gahrtahvo"]["min"] not DNI_UNITS["gahrtahvo"]["min"]
@ -76,20 +76,12 @@ def check_dni_time_fields(
f"Tahvo must be in {DNI_UNITS['tahvo']['min']}..{DNI_UNITS['tahvo']['max'] - 1}", f"Tahvo must be in {DNI_UNITS['tahvo']['min']}..{DNI_UNITS['tahvo']['max'] - 1}",
tahvo, tahvo,
) )
if ( if not DNI_UNITS["gorahn"]["min"] <= gorahn <= DNI_UNITS["gorahn"]["max"] - 1:
not DNI_UNITS["gorahn"]["min"]
<= gorahn
<= DNI_UNITS["gorahn"]["max"] - 1
):
raise ValueError( raise ValueError(
f"Gorahn must be in {DNI_UNITS['gorahn']['min']}..{DNI_UNITS['gorahn']['max'] - 1}", f"Gorahn must be in {DNI_UNITS['gorahn']['min']}..{DNI_UNITS['gorahn']['max'] - 1}",
gorahn, gorahn,
) )
if ( if not DNI_UNITS["prorahn"]["min"] <= prorahn <= DNI_UNITS["prorahn"]["max"] - 1:
not DNI_UNITS["prorahn"]["min"]
<= prorahn
<= DNI_UNITS["prorahn"]["max"] - 1
):
raise ValueError( raise ValueError(
f"Prorahn must be in {DNI_UNITS['prorahn']['min']}..{DNI_UNITS['prorahn']['max'] - 1}", f"Prorahn must be in {DNI_UNITS['prorahn']['min']}..{DNI_UNITS['prorahn']['max'] - 1}",
prorahn, prorahn,
@ -111,7 +103,7 @@ def add_leap_seconds(timestamp: int) -> int:
return timestamp + (leap_seconds * 1000) return timestamp + (leap_seconds * 1000)
def get_ms_from_epoch(date_time: Optional[datetime] = None) -> int: def get_ms_from_epoch(date_time: datetime | None = None) -> int:
""" """
Returns the amount of milliseconds since the UNIX epoch (1-1-1970). Returns the amount of milliseconds since the UNIX epoch (1-1-1970).
""" """
@ -124,7 +116,7 @@ def get_ms_from_epoch(date_time: Optional[datetime] = None) -> int:
return ((date - EARTH_EPOCH) // timedelta(microseconds=1)) // 1000 return ((date - EARTH_EPOCH) // timedelta(microseconds=1)) // 1000
def get_adj_ms_from_epoch(date_time: Optional[datetime] = None) -> int: def get_adj_ms_from_epoch(date_time: datetime | None = None) -> int:
""" """
Returns the amount of milliseconds since the UNIX epoch (1-1-1970), Returns the amount of milliseconds since the UNIX epoch (1-1-1970),
but also accounting for leap seconds. but also accounting for leap seconds.