scotty-nukem
scotty-nukem

Reputation: 21

Calculating Date from UNIX Time via Iteration - Logic Flaw?

I'm trying to create a function that returns a date in string format (MM-DD-YYYY) given the seconds since epoch. I believe the logic in my function is sound, and I'm posting here because there might be something about UNIX time that I don't understand. I'm looking for anyone who might shed some light on where my blind spot is. I believe my logic and thought process is correct, but clearly it's not. Hoping someone can help clear it up, and that this may be helpful for other newbies.

My function is passed an argument, seconds (int), that is the number of seconds since epoch. I then have to return a string 'MM-DD-YYYY'. Hours, minutes, seconds, and time-zone do not matter. I'm using Python, so int size and the 2038 problem should not matter either. My function calculates the date iteratively. I essentially keep decrementing the seconds parameter for years, then months, then days, tracking the time that has passed. Once I can no longer iterate in each of those three areas (years -> months -> days) I have found my date. Except that the date I find is incorrect.

Years Calculation

I take the seconds parameter, and decrement it by the seconds in the given year, unless the decrement leads to a negative number. I track the years added as I decrement. If the year is a leap year, I decrement by 86400 * 366. For a common year, 86400 * 365. I add +1 to the year tracker each iteration.

Months Calculation

The seconds parameter now contains the leftover number of seconds, which is less than the length of a year. I decrement the number of seconds in each month unless the decrement leads to a negative number. January = 86400 * 31, February is 28 or 29 days depending on if it's a leap year, and so on.

Days Calculation

The seconds parameter now contains some number of seconds less than a month. I follow the same process, decrementing 86400 (and tracking the days) until I can't decrement seconds any longer.

Logic Flaw?

Based on what I understand about UNIX time, I should arrive at the correct MM-DD-YYYY date using this method. However, my function is 2 days shy.

Input: 9876543210

Output: '12-20-2282'

Expected: '12-22-2282'

Function Assumptions

Input is always a positive integer

I do not need to do time-zone conversions or calculations. GMT assumed.

Code

def date_from_epoch_seconds(seconds: int) -> str:
    """
    Returns a date in string format ('MM-DD-YYYY') given param:seconds since epoch
    :param: seconds: int, number of seconds since epoch
    :return: string: date 'MM-DD-YYY'
    """

    # variables
    DAYS_IN_COMMON_MONTH = {1: 31, \
                            2: 28, \
                            3: 31, \
                            4: 30, \
                            5: 31, \
                            6: 30, \
                            7: 31, \
                            8: 31, \
                            9: 30, \
                            10: 31, \
                            11: 30, \
                            12: 31}
    DAY = 86400
    year = 1970
    month = 1
    day = 1

    # calculate year
    while True:

        # get the number of seconds in this year
        if year % 4 != 0:
            add_year = DAY * 365
        else:
            add_year = DAY * 366

        # exit criteria
        if seconds - add_year < 0:
            break

        # add a year
        seconds -= add_year
        year += 1

    print(f"Year calculated: {year}")

    # calculate month
    while True:

        # get the number of seconds in this month
        if month == 2 and year % 4 == 0:
            add_month = DAY * 29
        else:
            add_month = DAY * DAYS_IN_COMMON_MONTH[month]

        # exit criteria
        if seconds - add_month < 0:
            break

        seconds -= add_month
        month += 1

    print(f"months calculated = {month}")

    # calculate day
    while True:
        if seconds - DAY < 0:
            break
        seconds -= DAY
        day += 1

    print(f"day calculated = {day}")
    print()
    return str(twoDigitInt(month)) + "-" + \
           str(twoDigitInt(day)) + "-" + \
           str(year)

Upvotes: 0

Views: 134

Answers (1)

CrankyElderGod
CrankyElderGod

Reputation: 433

Your leap year calculation is wrong. Years 2100 and 2200 are not leap years. Years divisible by 100 are not leap years unless they are also divisible by 400.

Upvotes: 1

Related Questions