2021-03-19 14:42:41 +00:00
|
|
|
|
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',
|
2021-11-19 07:44:20 +00:00
|
|
|
|
'Mëðir',
|
2021-03-19 14:42:41 +00:00
|
|
|
|
'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
|