I have written two functions that output a date-time string for any given non-negative integer.
The integer is treated as representing total number of seconds in a given time period, the first function converts that duration to week-day-hour-minute-weekday format (w weeks, d days, HH:mm:ss, dddd), using a mathematically sound mixed radix system: (7, 24, 60, 60, 60), its outputs are factually correct.
The second function is more complex, it outputs a date-time in the following format: MMMM dd, yyyy, HH:mm:ss, dddd, the number is treated as a Gregorian timestamp with the beginning of the Common Era as its epoch, its outputs are factually wrong, however they are practically correct for usage in the 21st century and can be used to correctly calculate date-time.
Specifically, it uses a calendar based on the Gregorian calendar, and the following are assumed:
There was never a Julian calendar, whose ephemeral year is 365.25days.
The start of the Common Era is December 31, 0 CE.
The ephemeral year is always 365.2425days, the Gregorian starts on the epoch of the Common Era, rather than October 15, 1582.
Because October 5 to 14, 1582 exist in this calendar, the number of any given date's weekday is its date expressed as days since epoch modulo seven.
Leap seconds and time zones don't exist.
Having established all above "facts" however, the output of the second function is correct with correct weekday and the second function can be used to calculate the exact second Y2038 occurs.
The code:
WEEKDAYS = [
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday'
]
MONTHS = (
{'Month':'January', 'Days':31},
{'Month':'February', 'Days':28},
{'Month':'March', 'Days':31},
{'Month':'April', 'Days':30},
{'Month':'May', 'Days':31},
{'Month':'June', 'Days':30},
{'Month':'July', 'Days':31},
{'Month':'August', 'Days':31},
{'Month':'September', 'Days':30},
{'Month':'October', 'Days':31},
{'Month':'November', 'Days':30},
{'Month':'December', 'Days':31}
)
def to_wdhms(n: int) -> str:
n, seconds = divmod(n, 60)
n, minutes = divmod(n, 60)
n, hours = divmod(n, 24)
weeks, days = divmod(n, 7)
return '{0} weeks, {1} days, {2:02}:{3:02}:{4:02}, {5}'.format(weeks, days, hours, minutes, seconds, WEEKDAYS[days])
def to_date(n: int) -> str:
n, seconds = divmod(n, 60)
n, minutes = divmod(n, 60)
days, hours = divmod(n, 24)
sumyears = lambda x: x * 365 + x // 4 - x // 100 + x // 400
years = 0
while sumyears(years) < days:
years += 1
weekday = days % 7
days -= sumyears(years - 1)
def leapyear(n):
if not n % 4 and n % 100:
return True
elif not n % 400:
return True
return False
def summonths(x, y):
s = sum(i['Days'] for i in MONTHS[0:x])
if leapyear(y) and x >= 2:
s += 1
return s
months = 1
while summonths(months, years) < days:
months += 1
months -= 1
days -= summonths(months, years)
return '{0} {1:02}, {2:04}, {3:02}:{4:02}:{5:02}, {6}'.format(MONTHS[months]['Month'], days, years, hours, minutes, seconds, WEEKDAYS[weekday])
def totaldays(y, m, d):
ye = y
if m <= 2: y -= 1
leaps = y // 4 - y // 100 + y // 400
M = 0
for b in range(m - 1): M += MONTHS[b]['Days']
days = (ye - 1) * 365 + M + d + leaps
return days
def convert(y, m, d):
return to_date(totaldays(y, m, d) * 86400)
def y2038():
epoch = totaldays(1970,1,1) * 86400
sint32 = 2 ** 31
return to_date(epoch + sint32)
def test():
assert convert(1776,7,4) == 'July 04, 1776, 00:00:00, Thursday'
assert convert(1999,4,10) == 'April 10, 1999, 00:00:00, Saturday'
assert convert(2000,2,29) == 'February 29, 2000, 00:00:00, Tuesday'
assert convert(2000,3,1) == 'March 01, 2000, 00:00:00, Wednesday'
assert convert(2000,3,31) == 'March 31, 2000, 00:00:00, Friday'
assert convert(2000,12,31) == 'December 31, 2000, 00:00:00, Sunday'
assert convert(2008,8,1) == 'August 01, 2008, 00:00:00, Friday'
assert convert(2012,12,21) == 'December 21, 2012, 00:00:00, Friday'
assert convert(2020,9,21) == 'September 21, 2020, 00:00:00, Monday'
assert convert(2021,9,21) == 'September 21, 2021, 00:00:00, Tuesday'
assert convert(2021,12,25) == 'December 25, 2021, 00:00:00, Saturday'
assert convert(2021,12,31) == 'December 31, 2021, 00:00:00, Friday'
assert to_wdhms(86400) == '0 weeks, 1 days, 00:00:00, Monday'
assert to_wdhms(86399) == '0 weeks, 0 days, 23:59:59, Sunday'
assert to_wdhms(0) == '0 weeks, 0 days, 00:00:00, Sunday'
assert to_wdhms(43200) == '0 weeks, 0 days, 12:00:00, Sunday'
assert to_wdhms(21600) == '0 weeks, 0 days, 06:00:00, Sunday'
assert to_wdhms(3600) == '0 weeks, 0 days, 01:00:00, Sunday'
assert to_wdhms(1799) == '0 weeks, 0 days, 00:29:59, Sunday'
assert to_wdhms(172799) == '0 weeks, 1 days, 23:59:59, Monday'
assert to_wdhms(215199) == '0 weeks, 2 days, 11:46:39, Tuesday'
assert to_wdhms(259199) == '0 weeks, 2 days, 23:59:59, Tuesday'
assert to_wdhms(345599) == '0 weeks, 3 days, 23:59:59, Wednesday'
assert to_wdhms(3628799) == '5 weeks, 6 days, 23:59:59, Saturday'
assert y2038() == 'January 19, 2038, 03:14:08, Tuesday'
if __name__ == '__main__':
test()
How well is my code formatted? How is my code in terms of performance? What improvements can be made? Is there any problem I have overlooked?