def _compute_rolled_dates_table_without_cache(self, convention): is_bus_day = self._compute_is_bus_day_table() cumul_bus_days = self._compute_cumul_bus_days_table() bus_day_ordinals = self._compute_bus_day_ordinals_table() if convention == constants.BusinessDayConvention.FOLLOWING: return tf.gather(bus_day_ordinals, cumul_bus_days) if convention == constants.BusinessDayConvention.PRECEDING: return tf.gather(bus_day_ordinals, cumul_bus_days - (1 - is_bus_day)) following = self._compute_rolled_dates_table( constants.BusinessDayConvention.FOLLOWING) preceding = self._compute_rolled_dates_table( constants.BusinessDayConvention.PRECEDING) dates_following = dt.from_ordinals(following) dates_preceding = dt.from_ordinals(preceding) original_dates = dt.from_ordinals( tf.range(self._ordinal_offset - 1, self._ordinal_offset + self._calendar_size + 1)) if convention == constants.BusinessDayConvention.MODIFIED_FOLLOWING: return tf.where(tf.equal(dates_following.month(), original_dates.month()), following, preceding) if convention == constants. BusinessDayConvention.MODIFIED_PRECEDING: return tf.where(tf.equal(dates_preceding.month(), original_dates.month()), preceding, following) raise ValueError("Unrecognized convention: {}".format(convention))
def add_business_days( self, date_tensor, num_days, roll_convention=constants.BusinessDayConvention.NONE): """Adds given number of business days to given dates. Note that this is different from calling `add_period_and_roll` with PeriodType.DAY. For example, adding 5 business days to Monday gives the next Monday (unless there are holidays on this week or next Monday). Adding 5 days and rolling means landing on Saturday and then rolling either to next Monday or to Friday of the same week, depending on the roll convention. If any of the dates in `date_tensor` are not business days, they will be rolled to business days before doing the addition. If `roll_convention` is `NONE`, and any dates are not business days, an exception is raised. Args: date_tensor: DateTensor of dates to advance from. num_days: Tensor of int32 type broadcastable to `date_tensor`. roll_convention: BusinessDayConvention. Determines how to roll a date that falls on a holiday. Returns: The resulting DateTensor. """ control_deps = [] if roll_convention == constants.BusinessDayConvention.NONE: message = ("Some dates in date_tensor are not business days. " "Please specify the roll_convention argument.") is_bus_day = self.is_business_day(date_tensor) control_deps.append( tf.debugging.assert_equal(is_bus_day, True, message=message)) else: date_tensor = self.roll_to_business_day(date_tensor, roll_convention) with tf.compat.v1.control_dependencies(control_deps): cumul_bus_days_table = self._compute_cumul_bus_days_table() cumul_bus_days = self._gather( cumul_bus_days_table, date_tensor.ordinal() - self._ordinal_offset) target_cumul_bus_days = cumul_bus_days + num_days bus_day_ordinals_table = self._compute_bus_day_ordinals_table() ordinals = self._gather(bus_day_ordinals_table, target_cumul_bus_days) return dt.from_ordinals(ordinals, validate=False)
def roll_to_business_day(self, date_tensor, roll_convention): """Rolls the given dates to business dates according to given convention. Args: date_tensor: `DateTensor` of dates to roll from. roll_convention: BusinessDayConvention. Determines how to roll a date that falls on a holiday. Returns: The resulting `DateTensor`. """ if roll_convention == constants.BusinessDayConvention.NONE: return date_tensor ordinals = dt.convert_to_date_tensor(date_tensor).ordinal() biz_days, is_bizday = self._to_biz_space(ordinals) biz_days_rolled = self._apply_roll_biz_space(date_tensor, biz_days, is_bizday, roll_convention) return dt.from_ordinals(self._from_biz_space(biz_days_rolled))
def roll_to_business_day(self, date_tensor, roll_convention): """Rolls the given dates to business dates according to given convention. Args: date_tensor: DateTensor of dates to roll from. roll_convention: BusinessDayConvention. Determines how to roll a date that falls on a holiday. Returns: The resulting DateTensor. """ if roll_convention == constants.BusinessDayConvention.NONE: return date_tensor adjusted_ordinals_table = self._compute_rolled_dates_table(roll_convention) ordinals_with_offset = date_tensor.ordinal() - self._ordinal_offset adjusted_ordinals = self._gather(adjusted_ordinals_table, ordinals_with_offset) return dt.from_ordinals(adjusted_ordinals, validate=False)
def add_business_days( self, date_tensor, num_days, roll_convention=constants.BusinessDayConvention.NONE): """Adds given number of business days to given dates. Note that this is different from calling `add_period_and_roll` with PeriodType.DAY. For example, adding 5 business days to Monday gives the next Monday (unless there are holidays on this week or next Monday). Adding 5 days and rolling means landing on Saturday and then rolling either to next Monday or to Friday of the same week, depending on the roll convention. If any of the dates in `date_tensor` are not business days, they will be rolled to business days before doing the addition. If `roll_convention` is `NONE`, and any dates are not business days, an exception is raised. Args: date_tensor: `DateTensor` of dates to advance from. num_days: Tensor of int32 type broadcastable to `date_tensor`. roll_convention: BusinessDayConvention. Determines how to roll a date that falls on a holiday. Returns: The resulting `DateTensor`. """ control_deps = [] biz_days, is_bizday = self._to_biz_space( dt.convert_to_date_tensor(date_tensor).ordinal()) if roll_convention == constants.BusinessDayConvention.NONE: control_deps.append( tf.debugging.assert_equal( is_bizday, True, message='Non business starting day with no roll convention.' )) with tf.compat.v1.control_dependencies(control_deps): biz_days_rolled = self._apply_roll_biz_space( date_tensor, biz_days, is_bizday, roll_convention) return dt.from_ordinals( self._from_biz_space(biz_days_rolled + num_days))