Source code for policyengine_core.periods.instant_

import calendar
import datetime

from policyengine_core import periods
from policyengine_core.periods import config


[docs]class Instant(tuple): def __repr__(self) -> str: """ Transform instant to to its Python representation as a string. >>> repr(instant(2014)) 'Instant((2014, 1, 1))' >>> repr(instant('2014-2')) 'Instant((2014, 2, 1))' >>> repr(instant('2014-2-3')) 'Instant((2014, 2, 3))' """ return "{}({})".format( self.__class__.__name__, super(Instant, self).__repr__() ) def __str__(self) -> str: """ Transform instant to a string. >>> str(instant(2014)) '2014-01-01' >>> str(instant('2014-2')) '2014-02-01' >>> str(instant('2014-2-3')) '2014-02-03' """ instant_str = config.str_by_instant_cache.get(self) if instant_str is None: config.str_by_instant_cache[self] = instant_str = ( self.date.isoformat() ) return instant_str @property def date(self) -> datetime.date: """ Convert instant to a date. >>> instant(2014).date datetime.date(2014, 1, 1) >>> instant('2014-2').date datetime.date(2014, 2, 1) >>> instant('2014-2-3').date datetime.date(2014, 2, 3) """ instant_date = config.date_by_instant_cache.get(self) if instant_date is None: config.date_by_instant_cache[self] = instant_date = datetime.date( *self ) return instant_date @property def day(self) -> int: """ Extract day from instant. >>> instant(2014).day 1 >>> instant('2014-2').day 1 >>> instant('2014-2-3').day 3 """ return self[2] @property def month(self) -> int: """ Extract month from instant. >>> instant(2014).month 1 >>> instant('2014-2').month 2 >>> instant('2014-2-3').month 2 """ return self[1]
[docs] def period(self, unit: str, size: int = 1): """ Create a new period starting at instant. >>> instant(2014).period('month') Period(('month', Instant((2014, 1, 1)), 1)) >>> instant('2014-2').period('year', 2) Period(('year', Instant((2014, 2, 1)), 2)) >>> instant('2014-2-3').period('day', size = 2) Period(('day', Instant((2014, 2, 3)), 2)) """ assert unit in ( config.DAY, config.MONTH, config.YEAR, ), "Invalid unit: {} of type {}".format(unit, type(unit)) assert ( isinstance(size, int) and size >= 1 ), "Invalid size: {} of type {}".format(size, type(size)) return periods.Period((unit, self, size))
[docs] def offset(self, offset: int, unit: str) -> "Instant": """ Increment (or decrement) the given instant with offset units. >>> instant(2014).offset(1, 'day') Instant((2014, 1, 2)) >>> instant(2014).offset(1, 'month') Instant((2014, 2, 1)) >>> instant(2014).offset(1, 'year') Instant((2015, 1, 1)) >>> instant('2014-1-31').offset(1, 'day') Instant((2014, 2, 1)) >>> instant('2014-1-31').offset(1, 'month') Instant((2014, 2, 28)) >>> instant('2014-1-31').offset(1, 'year') Instant((2015, 1, 31)) >>> instant('2011-2-28').offset(1, 'day') Instant((2011, 3, 1)) >>> instant('2011-2-28').offset(1, 'month') Instant((2011, 3, 28)) >>> instant('2012-2-29').offset(1, 'year') Instant((2013, 2, 28)) >>> instant(2014).offset(-1, 'day') Instant((2013, 12, 31)) >>> instant(2014).offset(-1, 'month') Instant((2013, 12, 1)) >>> instant(2014).offset(-1, 'year') Instant((2013, 1, 1)) >>> instant('2011-3-1').offset(-1, 'day') Instant((2011, 2, 28)) >>> instant('2011-3-31').offset(-1, 'month') Instant((2011, 2, 28)) >>> instant('2012-2-29').offset(-1, 'year') Instant((2011, 2, 28)) >>> instant('2014-1-30').offset(3, 'day') Instant((2014, 2, 2)) >>> instant('2014-10-2').offset(3, 'month') Instant((2015, 1, 2)) >>> instant('2014-1-1').offset(3, 'year') Instant((2017, 1, 1)) >>> instant(2014).offset(-3, 'day') Instant((2013, 12, 29)) >>> instant(2014).offset(-3, 'month') Instant((2013, 10, 1)) >>> instant(2014).offset(-3, 'year') Instant((2011, 1, 1)) >>> instant(2014).offset('first-of', 'month') Instant((2014, 1, 1)) >>> instant('2014-2').offset('first-of', 'month') Instant((2014, 2, 1)) >>> instant('2014-2-3').offset('first-of', 'month') Instant((2014, 2, 1)) >>> instant(2014).offset('first-of', 'year') Instant((2014, 1, 1)) >>> instant('2014-2').offset('first-of', 'year') Instant((2014, 1, 1)) >>> instant('2014-2-3').offset('first-of', 'year') Instant((2014, 1, 1)) >>> instant(2014).offset('last-of', 'month') Instant((2014, 1, 31)) >>> instant('2014-2').offset('last-of', 'month') Instant((2014, 2, 28)) >>> instant('2012-2-3').offset('last-of', 'month') Instant((2012, 2, 29)) >>> instant(2014).offset('last-of', 'year') Instant((2014, 12, 31)) >>> instant('2014-2').offset('last-of', 'year') Instant((2014, 12, 31)) >>> instant('2014-2-3').offset('last-of', 'year') Instant((2014, 12, 31)) """ year, month, day = self assert unit in ( config.DAY, config.MONTH, config.YEAR, ), "Invalid unit: {} of type {}".format(unit, type(unit)) if offset == "first-of": if unit == config.MONTH: day = 1 elif unit == config.YEAR: month = 1 day = 1 elif offset == "last-of": if unit == config.MONTH: day = calendar.monthrange(year, month)[1] elif unit == config.YEAR: month = 12 day = 31 else: assert isinstance( offset, int ), "Invalid offset: {} of type {}".format(offset, type(offset)) if unit == config.DAY: day += offset if offset < 0: while day < 1: month -= 1 if month == 0: year -= 1 month = 12 day += calendar.monthrange(year, month)[1] elif offset > 0: month_last_day = calendar.monthrange(year, month)[1] while day > month_last_day: month += 1 if month == 13: year += 1 month = 1 day -= month_last_day month_last_day = calendar.monthrange(year, month)[1] elif unit == config.MONTH: month += offset if offset < 0: while month < 1: year -= 1 month += 12 elif offset > 0: while month > 12: year += 1 month -= 12 month_last_day = calendar.monthrange(year, month)[1] if day > month_last_day: day = month_last_day elif unit == config.YEAR: year += offset # Handle february month of leap year. month_last_day = calendar.monthrange(year, month)[1] if day > month_last_day: day = month_last_day return self.__class__((year, month, day))
@property def year(self) -> int: """ Extract year from instant. >>> instant(2014).year 2014 >>> instant('2014-2').year 2014 >>> instant('2014-2-3').year 2014 """ return self[0]