def day_of_year(self): """Calculates the number of days since the beginning of the year. Returns: Tensor of int32 type with elements in range [1, 366]. January 1st yields "1". ## Example ```python dt = dates.from_tuples([(2019, 1, 25), (2020, 3, 2)]) dt.day_of_year() # [25, 62] ``` """ if self._day_of_year is None: cumul_days_in_month_nonleap = tf.math.cumsum( _DAYS_IN_MONTHS_NON_LEAP, exclusive=True) cumul_days_in_month_leap = tf.math.cumsum(_DAYS_IN_MONTHS_LEAP, exclusive=True) days_before_month_non_leap = tf.gather(cumul_days_in_month_nonleap, self.month() - 1) days_before_month_leap = tf.gather(cumul_days_in_month_leap, self.month() - 1) days_before_month = tf.where(date_utils.is_leap_year(self.year()), days_before_month_leap, days_before_month_non_leap) self._day_of_year = days_before_month + self.day() return self._day_of_year
def test_is_leap_year(self): years = np.array([ 1600, 1700, 1800, 1900, 1901, 1903, 1904, 1953, 2000, 2020, 2025, 2100 ]) expected = np.array([ True, False, False, False, False, False, True, False, True, True, False, False ]) self.assertAllEqual(expected, date_utils.is_leap_year(years))
def _leap_days_since_start(date_tensor): """Calculates the number of leap days until the supplied dates.""" year = date_tensor.year() month = date_tensor.month() day = date_tensor.day() leap_years_since_0 = year // 4 - year // 100 + year // 400 is_leap_year = du.is_leap_year(year) needs_adjustment = (is_leap_year & ((month < 2) | (tf.equal(month, 2) & (day < 29)))) return leap_years_since_0 - tf.where(needs_adjustment, 1, 0)
def from_year_month_day_tensors(cls, years, months, days, validate=True): """Creates DateTensor from tensors of years, months and days. Args: years: Tensor of int32 type. Elements should be positive. months: Tensor of int32 type of same shape as `year`. Elements should be in range `[1, 12]`. days: Tensor of int32 type of same shape as `year`. Elements should be in range `[1, 31]` and represent valid dates together with corresponding elements of `month` and `year` Tensors. validate: Whether to validate the dates. Returns: DateTensor object. Example: ```python years = tf.constant([2015, 2017], dtype=tf.int32) months = tf.constant([4, 12], dtype=tf.int32) days = tf.constant([15, 30], dtype=tf.int32) date_tensor = DateTensor.from_year_month_day_tensors(years, months, days) ``` """ years = tf.convert_to_tensor(years, tf.int32) months = tf.convert_to_tensor(months, tf.int32) days = tf.convert_to_tensor(days, tf.int32) control_deps = [] if validate: control_deps.append(tf.debugging.assert_positive(years)) control_deps.append( tf.debugging.assert_greater_equal(months, Month.JANUARY.value)) control_deps.append( tf.debugging.assert_less_equal(months, Month.DECEMBER.value)) control_deps.append(tf.debugging.assert_positive(days)) is_leap = date_utils.is_leap_year(years) days_in_months = tf.constant(_days_in_months, tf.int32) max_days = tf.gather(days_in_months, months + 12 * tf.dtypes.cast(is_leap, np.int32)) control_deps.append(tf.debugging.assert_less_equal(days, max_days)) with tf.compat.v1.control_dependencies(control_deps): # Ensure years, months, days themselves are under control_deps. years = tf.identity(years) months = tf.identity(months) days = tf.identity(days) with tf.compat.v1.control_dependencies(control_deps): ordinals = date_utils.year_month_day_to_ordinal(years, months, days) return DateTensor(ordinals, years, months, days)
def adjust_day(year, month, day): is_leap = date_utils.is_leap_year(year) days_in_months = tf.constant(_DAYS_IN_MONTHS, tf.int32) max_days = tf.gather( days_in_months, month + 12 * tf.dtypes.cast(is_leap, np.int32)) return tf.math.minimum(day, max_days)
def _num_days_in_month(month, year): """Returns number of days in a given month of a given year.""" days_in_months = tf.constant(_DAYS_IN_MONTHS_COMBINED, tf.int32) is_leap = date_utils.is_leap_year(year) return tf.gather(days_in_months, month + 12 * tf.dtypes.cast(is_leap, tf.int32))