Skip to content

Instantly share code, notes, and snippets.

@fero23
Last active December 5, 2017 22:36
Show Gist options
  • Save fero23/36d5328c81570eac5b6748db32456970 to your computer and use it in GitHub Desktop.
Save fero23/36d5328c81570eac5b6748db32456970 to your computer and use it in GitHub Desktop.
Basic datetime implementation in Python
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