Last active
December 5, 2017 22:36
-
-
Save fero23/36d5328c81570eac5b6748db32456970 to your computer and use it in GitHub Desktop.
Basic datetime implementation in Python
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import time | |
import datetime | |
SECONDS_EVERY_FOUR_YEARS = (365 * 4 + 1) * 24 * 3600 | |
SECONDS_EVERY_YEAR = 365 * 24 * 3600 | |
SECONDS_EVERY_DAY = 24 * 3600 | |
DAYS_EVERY_MONTH = [31, (28, 29), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] | |
SECONDS_AFTER_FIRST_LEAP_YEAR = SECONDS_EVERY_YEAR * 3 + SECONDS_EVERY_DAY | |
def _get_numbers_of_days_the_month(m, years_since_last_leap_year): | |
if m == 1: | |
if years_since_last_leap_year == 0: | |
days_month = DAYS_EVERY_MONTH[1][1] | |
else: | |
days_month = DAYS_EVERY_MONTH[1][0] | |
else: | |
days_month = DAYS_EVERY_MONTH[m] | |
return days_month | |
def _calculate_first_days(): | |
current_value = 2 # December 1st 1971 was a Wednesday | |
for y in range(0, 28): | |
year_count = y % 4 | |
for m in range(0, 12): | |
previous_month = m - 1 % 12 | |
days_of_the_month = _get_numbers_of_days_the_month(previous_month, year_count) | |
current_value = (current_value + days_of_the_month) % 7 | |
if m == 0: | |
yield current_value | |
elif y == 27: | |
return | |
FIRST_WEEKDAY_OF_THE_YEAR = list(_calculate_first_days()) # 28 years cicle starting from 1972 | |
class MyDateTime: | |
def __init__(self, t: int = None, tz = None): | |
if t is None: | |
self._timestamp = t = int(time.time()) | |
else: | |
self._timestamp = t = int(t) | |
if tz is None: tz = datetime.datetime.now().astimezone().tzinfo | |
t += int(tz.utcoffset(datetime.datetime.now()).total_seconds()) | |
self.tzinfo = tz | |
leap_years_since_epoch, other_secs = divmod(t, SECONDS_EVERY_FOUR_YEARS) | |
if other_secs > SECONDS_AFTER_FIRST_LEAP_YEAR: | |
other_secs -= SECONDS_EVERY_DAY | |
years, seconds_this_year = divmod(other_secs, SECONDS_EVERY_YEAR) | |
days_this_year, seconds_this_day = divmod(seconds_this_year, SECONDS_EVERY_DAY) | |
hours_this_day, seconds_this_hour = divmod(seconds_this_day, 3600) | |
minutes_this_day, seconds_this_minute = divmod(seconds_this_hour, 60) | |
ad_year = 1970 + leap_years_since_epoch * 4 + years | |
weekday_index = (ad_year - 1972) % 28 | |
weeks_this_year, weekday = divmod(FIRST_WEEKDAY_OF_THE_YEAR[weekday_index] + days_this_year, 7) | |
years_since_last_leap_year = years - 2 | |
for m in range(0, 12): | |
days_of_the_month = _get_numbers_of_days_the_month(m, years_since_last_leap_year) | |
if days_this_year <= days_of_the_month: | |
days_this_month = days_this_year + 1 | |
months_this_year = m + 1 | |
break | |
else: | |
days_this_year -= days_of_the_month | |
self.year = ad_year | |
self.month = months_this_year | |
self.day = days_this_month | |
self.yday = days_this_year + 1 | |
self.wday = weekday | |
self.isoweek = weeks_this_year | |
self.hour = hours_this_day | |
self.minute = minutes_this_day | |
self.second = seconds_this_minute | |
def timetuple(self): | |
dst_d = self.tzinfo.dst(datetime.datetime.now()) | |
if dst_d is None: dst = -1 | |
else: dst = dst_d.total_seconds() / 3600 | |
return time.struct_time((self.year, self.month, self.day, self.hour, self.minute, self.second, | |
self.isoweek, self.yday, dst)) | |
def asctime(self): return time.asctime(self.timetuple()) | |
def __str__(self): return self.asctime() | |
def __repr__(self): | |
return f'<MyDateTime({self.year}, {self.month}, {self.day}, ' \ | |
f'{self.hour}, {self.minute}, {self.second}, ' \ | |
f'week={self.isoweek}, weekday={self.wday})>' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment