0

With python I want to calculate the delta days of a day_of_a_year day and its corresponding month, as well delta days for month + 1.

*Sorry I forgot to mention that the year is a known variable eg.

def a(day_of_year):
    <...>
    return [(days_from_start_of_month),(days_untill_end_of_month)]

so If

day_of_year = 32 
a(32) = (2,28) #assuming the month which the day_of_year corresponds to starts from day 30 and ends to day 60.

So far im studying the datetime , timeutils and calendar modules and I really can't figure out the logic for the code! I wish i had something solid to show, but Im getting lost somewhere in timedelta functions.

7
  • 3
    could you clarify your example. Its difficult to follow. ALso what have you tried? What exactly do you want as your output? Commented Jun 22, 2012 at 13:34
  • 1
    The 32nd day of a year is February 1st; January has 31 days. Commented Jun 22, 2012 at 13:40
  • You'll need to pass the year into your function as well, as some years have a different number of days Commented Jun 22, 2012 at 13:50
  • Yes I know you are correct. The numbers I said were indented as example Commented Jun 22, 2012 at 13:51
  • When you say "I can't figure out the logic for the code" what explicitly are you talking about? Commented Jun 22, 2012 at 13:53

2 Answers 2

2

The first day of the month is easy to construct, as is the first day of the next month. Once you have those, the rest is even easier. As pointed out by the OP, the calendar.monthrange function gives us the most readable method to get the last day of a month.

>>> from datetime import date, year
>>> import calendar
>>> def first_day(dt):
...      # Simply copy year and month into new date instance
...      return date(dt.year, dt.month, 1)
...
>>> def last_day(dt):
...      days_in_month = calendar.monthrange(dt.year, dt.month)[1]
...      return date(dt.year, dt.month, days_in_month)
...
>>> nth_day = 32
>>> day_of_year = date(2012, 1, 1) + timedelta(days=nth_day - 1)
>>> day_of_year
datetime.date(2012, 2, 1)
>>> first_day(day_of_year), last_day(day_of_year)
(datetime.date(2012, 2, 1), datetime.date(2012, 2, 29))
>>> day_of_year - first_day(day_of_year), last_day(day_of_year) - day_of_year
(datetime.timedelta(0), datetime.timedelta(28))

To combine these techniques into one function:

def delta_to_start_and_end(year, day_of_year):
    dt = date(year, 1, 1) + timedelta(days=(day_of_year - 1))

    def first_day(dt):
         return date(dt.year, dt.month, 1)
    def last_day(dt):
         days_in_month = calendar.monthrange(dt.year, dt.month)[1]
         return date(dt.year, dt.month, days_in_month)

    return (dt - first_day(dt)).days, (last_day(dt) - dt).days

Output:

>>> delta_to_start_and_end(2012, 32)
(0, 28)
>>> delta_to_start_and_end(2011, 32)
(0, 27)
>>> delta_to_start_and_end(2012, 34)
(2, 26)
>>> delta_to_start_and_end(2012, 364)
(28, 2)

I'm not sure if you want to add 1 to each of these two values; currently the first day of the month (first example) gives you 0 as the first value and (days-in-the-month - 1) as the second value, as this is the difference in days from those points. It's trivial to add + 1 twice on the last line of the delta_to_start_and_end function if you need these.

As a historic note, a previous version of this answer used a different method to calculate the last day of a month without the calendar module:

def last_day(dt):
     rest, month = divmod(dt.month, 12)
     return date(dt.year + rest, month + 1, 1) - timedelta(days=1) 

This function uses the divmod builtin function to handle the 'current month is December' edge-case; in that case the next month is not 13, but 1 and we'd need to increase the year by one as well. Rolling over a number back to the 'start' is the modulus of the number, but the divmod function gives us the divisor as well, which happens to be 1 if the current month is 12. This gives us a handy indicator when to increase the year.

Sign up to request clarification or add additional context in comments.

6 Comments

ah you noticed the problem with days=31, I was just going to point it out :P
the last day of a month can be also calculated with calendar.monthrange(year,month) -> (0~6(0=mon,6=Sun), days_of_month) calendar.monthrange(2000,30) -> (3,31)
Also can you please explain if possible the last_day function? I got lost while trying to figure out what's happening
@user528025: golly, forgot about the calendar module. :-) I've included some comments in the last_day funcion already, did you see those (later edit).
@user528025: using the calendar module is easier, so I replaced the old divmod based function with the calendar.monthrange call.
|
0

I don't think that there's an existing library that works for this. You have to make something yourself, like this:

monthdays = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)

day = 32

total = 0
for i in monthdays:
    if day - total - i < 0:
        before = day - total
        after = total + i - day
        break
    total += i

print before, after

(just a quick start, there is possibly a more elegant way)

5 Comments

This will break in a leap year, like 2012.
That's why I said 'just a quick start' :D
I thought about that, but unfortunately I have to take into consideration leap years
you can check for a leap year by just doing if year % 4: #not leap as far as I know. or are there also other rules for leap years?
@BrtH Yes,if a year is a multiple of 100, then it is only a leap year if it is also a multiple of 400. For example, 1900 was not a leap year, but 2000 is one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.