0

I want to count summer days between two dates. Summer is May first to August last.

This will count all days:

import datetime

startdate=datetime.datetime(2015,1,1)
enddate=datetime.datetime(2016,6,1)

delta=enddate-startdate

print delta.days
>>517

But how can only count the passed summer days?

BERA
  • 1,345
  • 3
  • 16
  • 36
  • Check [this](https://stackoverflow.com/questions/151199/how-do-i-calculate-number-of-days-between-two-dates-using-python) out. – GreenSaber Oct 10 '17 at 12:54
  • That's a very strange definition of summer… –  Oct 10 '17 at 13:10
  • @GreenSaber: It doesn't really help with summer days, though. Does it? – Eric Duminil Oct 10 '17 at 13:10
  • You should probably make a bit more of an attempt than that. (Also possibly bound the problem; do you have to potentially deal with 31 December 2015 to 7 May 2018 (which includes a leap day)). You could also try posting it to codegolf; if this is a homework assignment, I'm sure your teacher would appreciate Jelly or if you're really lucky, the python code that a pyth answer compiles to... – Foon Oct 10 '17 at 13:40

3 Answers3

4

You could define a generator to iterate over every date between startdate and enddate, define a function to check if a date represents a summer day and use sum to count the summer days:

import datetime

startdate = datetime.datetime(2015,1,1)
enddate = datetime.datetime(2016,6,1)

all_dates = (startdate + datetime.timedelta(days=x) for x in range(0, (enddate-startdate).days))

def is_summer_day(date):
    return 5 <= date.month <= 8

print(sum(1 for date in all_dates if is_summer_day(date)))
# 154

Thanks to the generator, you don't need to create a huge list in memory with every day between startdate and enddate.

This iteration still considers every single day, even if it's not needed. For very large gaps, you could use the fact that every complete year has 123 summer days according to your definition.

Eric Duminil
  • 52,989
  • 9
  • 71
  • 124
  • that's a clever solution. I may be suboptimal in terms of performance for large periods (separated by many years or centuries) because of the iteration and sum, but I don't think it will matter much in "normal" cases. – Guillaume Oct 10 '17 at 13:19
0

You can create a few functions to count how many summer days you have between two days:

from datetime import date

def get_summer_start(year):
    return date(year, 5, 1)

def get_summer_end(year):
    return date(year, 8, 31)

def get_start_date(date, year):
    return max(date, get_summer_start(year))

def get_end_date(date, year):
    return min(date, get_summer_end(year))

def count_summer_days(date1, date2):
    date1_year = date1.year
    date2_year = date2.year

    if date1_year == date2_year:
        s = get_start_date(date1, date1_year)
        e = get_end_date(date2, date1_year)
        return (e - s).days

    else:
        s1 = max(date1, get_summer_start(date1_year))
        e1 = get_summer_end(date1_year)

        first_year = max(0,(e1 -s1).days)

        s1 = get_summer_start(date2_year)
        e1 = min(date2, get_summer_end(date2_year))

        last_year = max(0,(e2 -s2).days)

        other_years = date2_year - date1_year - 1
        summer_days_per_year = (get_summer_end(date1_year) - get_summer_start(date1_year)).days

        return first_year + last_year + (other_years * summer_days_per_year)

date1 = date(2015,1,1)
date2 = date(2016,6,1)

print count_summer_days(date1, date2)
mabe02
  • 2,676
  • 2
  • 20
  • 35
  • Your function return None when date1 and date2 are not the same year, which is the case in question example – Antwane Oct 10 '17 at 13:05
  • Also, you don't use `get_summer_end`. – Eric Duminil Oct 10 '17 at 13:07
  • I was finishing to edit it. @EricDuminil your solution is for sure the quickest to implement as script. I was trying to provide a solution that might be included in a class and used in different context. btw, your answer was worth for an upvote! – mabe02 Oct 10 '17 at 13:13
  • This solution should be very scalable for huge year ranges! – mabe02 Oct 10 '17 at 13:30
0

Here is a better solution for large periods:

first_summer_day = (5,1)
last_summer_day = (8,31)

from datetime import date

startdate = date(2015,1,1)
enddate = date(2016,6,1)

# make sure that startdate > endate
if startdate > enddate:
    startdate, endate = endate, startdate


def iter_yearly_summer_days(startdate, enddate):
    for year in range(startdate.year, enddate.year+1):
        start_period = startdate if year == startdate.year else date(year, 1, 1)
        end_period = enddate if year == enddate.year else date(year, 12, 31)

        year_first_summer_day = date(year, *first_summer_day)
        year_last_summer_day = date(year, *last_summer_day)

        summer_days_that_year = (min(year_last_summer_day, end_period) - max(year_first_summer_day, start_period)).days
        print('year {} had {} days of summer'.format(year, summer_days_that_year))
        yield summer_days_that_year


print(sum(iter_yearly_summer_days(startdate, enddate)))
Guillaume
  • 5,497
  • 3
  • 24
  • 42