python-minari-date/minari_date/__init__.py

239 lines
5.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from datetime import datetime, timedelta
from math import ceil
from typing import Optional
class MinariDateTime:
DAY_NAMES = (
'Mirdu',
'Hëmi',
'Drak',
'Þodon',
'Charm',
'Rounn',
)
MONTH_NAMES = (
'Mëbel',
'Dirann',
'Ma',
'Gerub',
'Þrei',
'Dimoc',
'Xentor',
'Mëðir',
'Draþ',
'Quaden',
'Ridïmel',
'Rodom',
)
SPECIAL_NAMES = (
'Hëður',
'Rideyy',
'Morkh',
'Khmerd',
'Chamog',
)
ENTITIES = {
'Hëður': {
'entity': 'Garquon',
'element': 'Meren'
},
'Mëbel': {
'entity': 'Þoraðrin',
'element': 'Aðun'
},
'Dirann': {
'entity': 'Detërien',
'element': 'Merðen'
},
'Ma': {
'entity': 'Elin',
'element': 'Fronn'
},
'Rideyy': {
'entity': 'Hëriel',
'element': 'Enðir'
},
'Gerub': {
'entity': 'Iliþon',
'element': 'Miþon'
},
'Þrei': {
'entity': 'Amenar',
'element': None
},
'Dimoc': {
'entity': 'Iminiru',
'element': 'Sëdur'
},
'Morkh': {
'entity': 'Luminar',
'element': 'Holar'
},
'Xentor': {
'entity': 'Motimor',
'element': 'Rort'
},
'Mëðïr': {
'entity': 'Mirian',
'element': 'Ilšir'
},
'Draþ': {
'entity': 'Heloor',
'element': None
},
'Khmerd': {
'entity': 'Zuþeron',
'element': 'Gord'
},
'Quaden': {
'entity': 'Umonar',
'element': 'Ulquon'
},
'Ridïmel': {
'entity': 'Feiriamen',
'element': 'Reina'
},
'Rodom': {
'entity': 'Nozoru',
'element': 'Zima'
},
'Chamog': {
'entity': 'Ketirai',
'element': 'Loar'
}
}
def __init__(self, timestamp: datetime):
self.set_timestamp(timestamp.replace(hour=0, minute=0, second=0, microsecond=0))
self._minari_year = None
self._minari_month = None
self._minari_day = None
self._special_day = None
self._minari_weekday = None
def set_timestamp(self, timestamp: datetime):
self._timestamp = timestamp + timedelta(days=11)
self._calculated = False
@staticmethod
def _get_doy(timestamp: datetime) -> int:
onejan = datetime(timestamp.year, 1, 1)
time_diff = timestamp - onejan
return ceil(time_diff.total_seconds() / 86400)
@staticmethod
def _is_leap(timestamp: datetime) -> bool:
year = timestamp.year
if year % 400 == 0:
return True
if year % 100 == 0:
return False
if year % 4 == 0:
return True
return False
def _calculate_minari_parts(self):
if self._calculated:
return
minari_leap = self._is_leap(self._timestamp)
doy = self._get_doy(self._timestamp)
self._minari_year = self._timestamp.year - 1873
self._minari_month = None
self._minari_day = None
special_days = (
(0, None, 0),
(91, None, 1),
(182, None, 2),
(183, True, 2),
(273, False, 3),
(274, True, 3),
(364, False, 4),
(365, True, 4),
)
for special_doy, leap_only, special_num in special_days:
if doy == special_doy and (leap_only is None or leap_only == minari_leap):
self._special_day = special_num
break
if self._special_day is None:
decr = 0
minari_doy = doy
for special_doy, leap_only, _ in special_days:
if minari_doy > special_doy and (leap_only is None or leap_only == minari_leap):
decr += 1
minari_doy -= decr - 1
self._minari_month = ceil(minari_doy / 30)
self._minari_day = minari_doy % 30
if self._minari_day == 0:
self._minari_day = 30
self._minari_weekday = self._minari_day % 6
self._calculated = True
@property
def minari_year(self):
if not self._calculated:
self._calculate_minari_parts()
return self._minari_year
@property
def minari_month(self):
if not self._calculated:
self._calculate_minari_parts()
return self._minari_month
@property
def minari_day(self):
"""Return the current Minari calendar day
"""
if not self._calculated:
self._calculate_minari_parts()
return self._minari_day
@property
def minari_special(self):
"""Return the name of the current special day, if any
"""
if not self._calculated:
self._calculate_minari_parts()
return self._special_day
def __str__(self):
output = f'{self.minari_year} '
if self.minari_special is not None:
output += self.SPECIAL_NAMES[self.minari_special]
else:
weekday = self._minari_weekday - 1
if weekday == -1:
weekday = 5
month_name = self.MONTH_NAMES[self.minari_month - 1]
weekday_name = self.DAY_NAMES[weekday]
output += f'{month_name} {self.minari_day} ({weekday_name})'
return output