2
import calendar
calendar.Calendar().yeardatescalendar(2014)

>>> [[[[datetime.date(2013, 12, 30), datetime.date(2013, 12, 31),...

The above code returns datetimes for calendar year 2014. However, it also includes the last 2 days of 2013 and firs couple of days for 2015. Is there any way I can just extract the 2014 info?

maazza
  • 7,016
  • 15
  • 63
  • 96
user308827
  • 21,227
  • 87
  • 254
  • 417
  • 2
    The `calendar` module, which was specifically designed to ease the task of creating visible calendars, is the wrong starting point for such work. The reason for its apparent oddity is because it includes some days across month-ends in both the last week of one month and the first week of the next. See the answer from @DevShark for a much more sensible way to go about this. – holdenweb Mar 03 '16 at 11:05

5 Answers5

2

One way of doing it:

import datetime
def myFun(year):
     res = []
     d = datetime.datetime(year, 1, 1)
     while d.year != year +1:
             res.append(d)
             d = d + datetime.timedelta(days=1)
     return res

>>> myFun(2014)[:2]
[datetime.datetime(2014, 1, 1, 0, 0), datetime.datetime(2014, 1, 2, 0, 0)]
>>> len(myFun(2014))
365
DevShark
  • 8,558
  • 9
  • 32
  • 56
  • thanks @DevShark, I get this error `AttributeError: 'list' object has no attribute 'year'`. I am using python2.7 – user308827 Mar 03 '16 at 08:58
  • Better method. You can use the method I suggested before, but you would need to flatten the list first. This will work directly for you, you can just copy paste the function. – DevShark Mar 03 '16 at 09:08
2

You can find first and last week and remove datetimes not contains year 2014:

import calendar

c = calendar.Calendar().yeardatescalendar(2014)
#print c

#first week
print c[0][0][0]
[datetime.date(2013, 12, 30), datetime.date(2013, 12, 31), datetime.date(2014, 1, 1), datetime.date(2014, 1, 2), datetime.date(2014, 1, 3), datetime.date(2014, 1, 4), datetime.date(2014, 1, 5)]

#last week
print c[-1][-1][-1]
[datetime.date(2014, 12, 29), datetime.date(2014, 12, 30), datetime.date(2014, 12, 31), datetime.date(2015, 1, 1), datetime.date(2015, 1, 2), datetime.date(2015, 1, 3), datetime.date(2015, 1, 4)]

#filter datetimes by list comprehension
print [x for x in c[0][0][0] if x.year == 2014]
[datetime.date(2014, 1, 1), datetime.date(2014, 1, 2), datetime.date(2014, 1, 3), datetime.date(2014, 1, 4), datetime.date(2014, 1, 5)]

print [x for x in c[-1][-1][-1] if x.year == 2014]
[datetime.date(2014, 12, 29), datetime.date(2014, 12, 30), datetime.date(2014, 12, 31)]

#replace first and last week
c[0][0][0] = [x for x in c[0][0][0] if x.year == 2014]
c[-1][-1][-1] = [x for x in c[-1][-1][-1] if x.year == 2014]

print c[0][0][0]
[datetime.date(2014, 1, 1), datetime.date(2014, 1, 2), datetime.date(2014, 1, 3), datetime.date(2014, 1, 4), datetime.date(2014, 1, 5)]

print c[-1][-1][-1]
[datetime.date(2014, 12, 29), datetime.date(2014, 12, 30), datetime.date(2014, 12, 31)]
jezrael
  • 822,522
  • 95
  • 1,334
  • 1,252
1

Honestly this module is rather weird. as it seems that for the year 2014 there are 434 days. however if you're interested in just 2014, you can use a nested list comprehension

import calendar
year = calendar.Calendar().yeardatescalendar(2014)
my_year = [day for quarter in year for month in quarter for week in month for day in week if day.year == 2014]

if you want to have this without duplicates you can use

no_dupe_year = set([day for quarter in year for month in quarter for week in month for day in week if day.year == 2014])
len(no_dupe_year)
>>> 365
Community
  • 1
  • 1
GLaDOS
  • 620
  • 6
  • 17
0

A simple but crude way of doing it:

c = calendar.Calendar().yeardatescalendar(2014)
for y in c:
    for m in y:
        for w in m:
            for d in reversed(w):
                if d.year != 2014:
                    w.remove(d)
M.T
  • 4,917
  • 4
  • 33
  • 52
  • Removing an item from the list you are iterating over is not a good way of doing things. You can add will-be-removed to some list then remove after your iteration. – Lafexlos Mar 03 '16 at 09:16
  • @Lafexlos it is fine as long as you reverse the list you are removing from, ensuring all items will be traversed. – M.T Mar 03 '16 at 09:18
0

As an alternative approach, you could build the calendar yourself as follows:

from datetime import datetime, timedelta
from itertools import groupby

def get_calendar(year):
    cur_day = datetime(year, 1, 1)
    one_day = timedelta(days=1)
    days = []

    while cur_day.year == year:
        days.append(cur_day)
        cur_day += one_day

    return [list(g) for k, g in groupby(days, lambda x: x.month)]

for month in get_calendar(2014):    
    print month

This generates a list of months, each containing a list of days in datetime format.

Martin Evans
  • 45,791
  • 17
  • 81
  • 97