# -*- coding: utf-8 -*-
import datetime
from .calfns import chop, rangecmp, rangetuple
from .day import Days, Day
from .month import Month
# noinspection PyPep8Naming
[docs]class Year(object):
def __init__(self, year=None):
super(Year, self).__init__()
if year is None:
year = datetime.date.today().year
self.year = year
self.months = [Month(year, i + 1) for i in range(12)]
def __int__(self):
return self.year
[docs] def range(self):
"""Return an iterator for the range of `self`.
"""
return self.dayiter()
[docs] def rangetuple(self):
return self.first.datetime(), (self+1).first.datetime()
def __lt__(self, other):
othr = rangetuple(other)
if othr is other:
return False
return rangecmp(self.rangetuple(), othr) < 0
def __le__(self, other):
othr = rangetuple(other)
if othr is other:
return False
return rangecmp(self.rangetuple(), othr) <= 0
def __eq__(self, other):
othr = rangetuple(other)
if othr is other:
return False
return rangecmp(self.rangetuple(), othr) == 0
def __gt__(self, other):
othr = rangetuple(other)
if othr is other:
return False
return rangecmp(self.rangetuple(), othr) > 0
def __ge__(self, other):
othr = rangetuple(other)
if othr is other:
return False
return rangecmp(self.rangetuple(), othr) >= 0
[docs] def timetuple(self):
d = datetime.date(*self.first.datetuple())
t = datetime.time()
return datetime.datetime.combine(d, t)
[docs] def between_tuple(self): # pylint:disable=E0213
"""Return a tuple of datetimes that is convenient for sql
`between` queries.
"""
return (self.first.datetime(),
(self.last + 1).datetime() - datetime.timedelta(seconds=1))
@property
def middle(self):
"""Return the day that splits the date range in half.
"""
middle = (self.first.toordinal() + self.last.toordinal()) // 2
return Day.fromordinal(middle)
# def timetuple(self):
# """Create timetuple from datetuple.
# (to interact with datetime objects).
# """
# d = datetime.date(*self.datetuple())
# t = datetime.time()
# return datetime.datetime.combine(d, t)
def __unicode__(self):
return unicode(self.year)
@property
def Month(self):
"""For orthogonality in the api.
"""
return self.months[0]
@property
def Year(self):
return self
@classmethod
[docs] def from_idtag(cls, tag):
"""Year tags have the lower-case letter y + the four digit year,
eg. y2008.
"""
y = int(tag[1:5])
return cls(year=y)
[docs] def idtag(self):
"""Year tags have the lower-case letter y + the four digit year,
eg. y2008.
"""
return 'y%d' % self.year
[docs] def marked_days(self):
for m in self.months:
for day in m.marked_days():
yield day
[docs] def datetuple(self):
"""January 1.
"""
return self.year, None, None
def __add__(self, n):
"""Add n years to self.
"""
return Year(self.year + n)
def __radd__(self, n):
return self + n
def __sub__(self, n):
return self + (-n)
# rsub doesn't make sense
[docs] def prev(self):
"""Previous year.
"""
return self - 1
[docs] def next(self):
"""Next year.
"""
return self + 1
@property
def H1(self):
"""First half of this year.
"""
return self.months[:6]
@property
def H2(self):
"""Last half of this year.
"""
return self.months[6:]
[docs] def halves(self):
"""Both halves of the year.
"""
return [self.H1, self.H2]
@property
def Q1(self):
"""1st quarter.
"""
return self.months[:3]
@property
def Q2(self):
"""2nd quarter.
"""
return self.months[3:6]
@property
def Q3(self):
"""3rd quarter.
"""
return self.months[6:9]
@property
def Q4(self):
"""4th quarter.
"""
return self.months[9:]
[docs] def quarters(self):
"""Every quarter in this year.
"""
return [self.Q1, self.Q2, self.Q3, self.Q4]
# pylint:disable=C0111
@property
def january(self):
return self.months[0]
@property
def february(self):
return self.months[1]
@property
def march(self):
return self.months[2]
@property
def april(self):
return self.months[3]
@property
def may(self):
return self.months[4]
@property
def june(self):
return self.months[5]
@property
def july(self):
return self.months[6]
@property
def august(self):
return self.months[7]
@property
def september(self):
return self.months[8]
@property
def october(self):
return self.months[9]
@property
def november(self):
return self.months[10]
@property
def december(self):
return self.months[11]
# pylint:enable=C0111
def __repr__(self):
return 'Year(%d)' % self.year
def __str__(self):
return str(self.year)
[docs] def dayiter(self):
for m in self.months:
for d in m.days():
yield d
[docs] def rows(self):
return chop(iter(self.months), 3)
[docs] def rows4(self):
return chop(iter(self.months), 4)
@property
def first(self):
"""First day of first month.
"""
return self.months[0].first
@property
def last(self):
"""Last day of last month.
"""
return self.months[-1].last
def __hash__(self):
return self.year
# def __eq__(self, other):
# if hasattr(other, 'year'):
# return self.year == other.year
# return False
def __contains__(self, date):
return date.year == self.year
def __getitem__(self, day):
m = self.months[day.month - 1]
return m[day]
[docs] def mark_period(self, p, value='mark'):
d = p.first
while d != p.last:
self.mark(d, value)
d += 1
self.mark(p.last, value)
[docs] def mark(self, d, value='mark'):
try:
self[d].mark = value
except KeyError: # pragma:nocover
pass
def _format(self, fmtchars):
# http://blog.tkbe.org/archive/date-filter-cheat-sheet/
for ch in fmtchars:
if ch == 'y':
yield str(self.year)[-2:]
elif ch == 'Y':
yield str(self.year)
else:
yield ch
# noinspection PyPep8Naming
def _Day_Year(self):
"""Return a Year object representing the year `self` belongs to.
"""
return Year(self.year)
Day.Year = property(_Day_Year)
# noinspection PyPep8Naming
def _Month_Year(self):
"""Return a Year object for the year-part of this month.
"""
return Year(self.year)
Month.Year = property(_Month_Year)