Source code for dk.age


"""Age (date subtraction) routines.
"""

from datetime import date as _date
from calendar import monthrange as _monthrange, isleap as _isleap


[docs]class age(object): "The number of years, months, and days since date of birth." def __init__(self, dob, today=None): today = today or _date.today() if dob is None: self.years = 0 self.months = 0 self.days = 0 return y = today.year - dob.year m = today.month - dob.month d = today.day - dob.day while m < 0 or d < 0: while m < 0: y -= 1 m = 12 + m # m is negative if d < 0: m -= 1 days = _days_previous_month(today.year, today.month) d = max(0, days - dob.day) + today.day self.years = y self.months = m self.days = d def __hash__(self): return hash(repr(self)) def __eq__(self, other): return (self.years == other.years and self.months == other.months and self.days == other.days) def __repr__(self): return '(%d, %d, %d)' % (self.years, self.months, self.days)
[docs]def next_birthday(birthday, today=None): "Return the date of the next birthday for someone born on date `birthday`." if today is None: today = _date.today() y, m, d = birthday.year, birthday.month, birthday.day y = today.year # find the birthday this year. if (today.month, today.day) > (m, d): # if the birthday has passed, the next one is next year y += 1 if not _isleap(y) and (m, d) == (2, 29): # Birthdays on the 29th of February are celebrated # on the 28th in non-leap years. d = 28 return _date(y, m, d)
[docs]def birthday_this_year(birthday, today=None): "Return the date of the birthday in the current year." if today is None: today = _date.today() return next_birthday(birthday, _date(today.year, 1, 1))
[docs]def previous_birthday(birthday, today=None): """Return the previous birthday relative to ``today``. """ if today is None: today = _date.today() return next_birthday(birthday, years_ago(1, today))
[docs]def years_ago(n, today=None): "The date that is `n` years before `today`." today = today or _date.today() pastyear = today.year - n _, pdays = _monthrange(pastyear, today.month) day_ok = today.day <= pdays if day_ok: pastday = today.day pastmonth = today.month else: pastday = _days_previous_month(pastyear, today.month) pastmonth = _past_month(today.month) res = _date(pastyear, pastmonth, pastday) return res
[docs]def days_ago(n, dato=None): "The date that is `n` days before `dato` (or today)." today = dato or _date.today() return _date.fromordinal(today.toordinal() - n)
[docs]def weeks_ago(n, today=None): "The date that is `n` weeks before `today`." today = today or _date.today() if n != 0: ret = _date.fromordinal(today.toordinal() - (7 * n)) else: ret = _date.today() return ret
def _past_month(m): "Subtract 1 from month." if m == 1: return 12 else: return m - 1 def _days_previous_month(y, m): "The number of days in the month before year `y` and month `m`." m -= 1 if m == 0: y -= 1 m = 12 _, days = _monthrange(y, m) return days