def __add__(self, period_tensor): """Adds a tensor of periods. When adding months or years, the resulting day of the month is decreased to the largest valid value if necessary. E.g. 31.03.2020 + 1 month = 30.04.2020, 29.02.2020 + 1 year = 28.02.2021. Args: period_tensor: A `PeriodTensor` object broadcastable to the shape of "self". Returns: The new instance of DateTensor. #### Example ```python dates = tff.datetime.dates_from_tuples([(2020, 2, 25), (2020, 3, 31)]) new_dates = dates + tff.datetime.month() # DateTensor([(2020, 3, 25), (2020, 4, 30)]) new_dates = dates + tff.datetime.month([1, 2]) # DateTensor([(2020, 3, 25), (2020, 5, 31)]) ``` """ period_type = period_tensor.period_type() if period_type == constants.PeriodType.DAY: ordinals = self._ordinals + period_tensor.quantity() return from_ordinals(ordinals) if period_type == constants.PeriodType.WEEK: return self + periods.PeriodTensor(period_tensor.quantity() * 7, constants.PeriodType.DAY) def adjust_day(year, month, day): return tf.math.minimum(day, _num_days_in_month(month, year)) if period_type == constants.PeriodType.MONTH: m = self._months - 1 + period_tensor.quantity() y = self._years + m // 12 m = m % 12 + 1 d = adjust_day(y, m, self._days) return from_year_month_day(y, m, d, validate=False) if period_type == constants.PeriodType.YEAR: y = self._years + period_tensor.quantity() # Use tf.shape to handle the case of dynamically shaped `y` m = tf.broadcast_to(self._months, tf.shape(y)) d = adjust_day(y, m, self._days) return from_year_month_day(y, m, d, validate=False) raise ValueError("Unrecognized period type: {}".format(period_type))
def __sub__(self, period_tensor): """Subtracts a tensor of periods. When subtracting months or years, the resulting day of the month is decreased to the largest valid value if necessary. E.g. 31.03.2020 - 1 month = 29.02.2020, 29.02.2020 - 1 year = 28.02.2019. Args: period_tensor: a PeriodTensor object broadcastable to the shape of "self". Returns: The new instance of DateTensor. """ return self + periods.PeriodTensor(-period_tensor.quantity(), period_tensor.period_type())
def subtract_period_and_roll( self, date_tensor, period_tensor, roll_convention=constants.BusinessDayConvention.NONE): """Subtracts given periods from given dates and rolls to business days. The original dates are not rolled prior to subtraction. Args: date_tensor: DateTensor of dates to subtract from. period_tensor: PeriodTensor broadcastable to `date_tensor`. roll_convention: BusinessDayConvention. Determines how to roll a date that falls on a holiday. Returns: The resulting DateTensor. """ minus_period_tensor = periods.PeriodTensor(-period_tensor.quantity(), period_tensor.period_type()) return self.add_period_and_roll(date_tensor, minus_period_tensor, roll_convention)