Search code examples
pythonpython-3.x

Getting unix timestamps for the start and end of a month in Python


Hello StackOverflow Python community!

I want to generate Unix timestamps for the start and end of a month. I'm looking for a way to retrieve the last day (or second, or minute...) in an arbitrary month in Python.

Given datetime.date values for two consecutive months, I can get to the last value in one month by subtracting a delta value from the next like this:

import datetime

# dates without time
jan = datetime.date(2019, 1, 1)
feb = datetime.date(2019, 2, 1)

# start/end times
start_time = datetime.time(0, 0, 0, 0, tzinfo=datetime.timezone.utc)
end_time = datetime.time(23, 59, 59, 999, tzinfo=datetime.timezone.utc)

jan_start = datetime.datetime.combine(jan, start_time)
last_day = feb - datetime.timedelta (days = 1)
jan_end = datetime.datetime.combine(last_day, end_time)

do_stuff(jan_start, jan_end)

But my minimally-python-literate self is stumbling trying to find a way to plug arbitrary months in and get the same results. I'd like to end up with something like:

import datetime

# start/end times
start_time = datetime.time(0, 0, 0, 0, tzinfo=datetime.timezone.utc)
end_time = datetime.time(23, 59, 59, 999, tzinfo=datetime.timezone.utc)

dates = {
    "Jan19": datetime.date(2019, 1, 1),
    "Feb19": datetime.date(2019, 2, 1),
    "Mar19": datetime.date(2019, 3, 1),
    "Apr19": datetime.date(2019, 4, 1)
}

for i in dates: 
    start = datetime.datetime.combine(dates[i], start_time)
    end_day = dates[i].next() - datetime.timedelta (days = 1)
    end = datetime.datetime.combine(end_day, end_time) 
    do_stuff(start, end)

Only, whoops - Python dictionaries are unordered, so there isn't a next() method I can call on i!

It's possible the conventional way to do this is to use midnight on February 1st as equivalent to the last second in January 31st, but I'm curious as to how one can retrieve the last day (or second, or minute...) in an arbitrary month in Python.

Would I need to use an OrderedList, or is there some module out there immune to my googling that has a month.max() property I could use instead of working it out dynamically?


Solution

  • To get the first day of the next month, one option (there are others) could be:

    >>> import datetime
    >>> my_date = datetime.datetime(2019, 4, 5)
    >>> my_date
    datetime.datetime(2019, 4, 5, 0, 0)
    >>> first_day_this_month = datetime.datetime(my_date.year, my_date.month, 1)
    >>> first_day_this_month
    datetime.datetime(2019, 4, 1, 0, 0)
    
    >>> some_day_next_month = first_day_this_month + datetime.timedelta(days=32)
    >>> some_day_next_month
    datetime.datetime(2019, 5, 3, 0, 0)
    >>> first_day_next_month = datetime.datetime(some_day_next_month.year, some_day_next_month.month, 1)
    >>> first_day_next_month
    datetime.datetime(2019, 5, 1, 0, 0)
    

    Now to get the last second of the current month, one could do:

    >>> last_second_this_month = first_day_next_month - datetime.timedelta(seconds=1)
    >>> last_second_this_month
    datetime.datetime(2019, 4, 30, 23, 59, 59)
    
    >>> import time
    >>> time.mktime(last_second_this_month.timetuple())
    1556683199.0