229 lines
5.4 KiB
Python
229 lines
5.4 KiB
Python
from datetime import datetime, timedelta
|
||
from math import ceil
|
||
from typing import Optional
|
||
|
||
|
||
class MinariDateTime:
|
||
DAY_NAMES = (
|
||
'Mirdu',
|
||
'Hëmi',
|
||
'Drak',
|
||
'Þodon',
|
||
'Charm',
|
||
'Ro’unn',
|
||
)
|
||
|
||
MONTH_NAMES = (
|
||
'Mëbel',
|
||
'Dirann',
|
||
'Ma’uþ',
|
||
'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’uþ': {
|
||
'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):
|
||
if not self._calculated:
|
||
self._calculate_minari_parts()
|
||
|
||
return self._minari_day
|
||
|
||
@property
|
||
def minari_special(self):
|
||
if not self._calculated:
|
||
self._calculate_minari_parts()
|
||
|
||
|
||
return self._special_day
|
||
|
||
def __str__(self):
|
||
output = f'{self.minari_year} '
|
||
|
||
if self._special_day is not None:
|
||
output += self.SPECIAL_NAMES[self._special_day]
|
||
else:
|
||
month_name = self.MONTH_NAMES[self._minari_month]
|
||
weekday_name = self.DAY_NAMES[self._minari_weekday]
|
||
output += f'{month_name} {self._minari_day} ({weekday_name})'
|
||
|
||
return output
|