Initial version
This commit is contained in:
228
minari_date/__init__.py
Normal file
228
minari_date/__init__.py
Normal file
@@ -0,0 +1,228 @@
|
||||
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
|
15
minari_date/__main__.py
Normal file
15
minari_date/__main__.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from datetime import datetime
|
||||
import sys
|
||||
|
||||
from dateutil.parser import parse
|
||||
|
||||
from . import MinariDateTime
|
||||
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
timestamp = parse(sys.argv[1]).replace(tzinfo=None)
|
||||
else:
|
||||
timestamp = datetime.utcnow()
|
||||
|
||||
dt = MinariDateTime(timestamp)
|
||||
print(str(dt))
|
Reference in New Issue
Block a user