def from_year_month_day(year, month, day, validate=True): """Creates DateTensor from tensors of years, months and days. Args: year: Tensor of int32 type. Elements should be positive. month: Tensor of int32 type of same shape as `year`. Elements should be in range `[1, 12]`. day: 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 year = tf.constant([2015, 2017], dtype=tf.int32) month = tf.constant([4, 12], dtype=tf.int32) day = tf.constant([15, 30], dtype=tf.int32) date_tensor = tff.datetime.dates_from_year_month_day(year, month, day) ``` """ year = tf.convert_to_tensor(year, tf.int32) month = tf.convert_to_tensor(month, tf.int32) day = tf.convert_to_tensor(day, tf.int32) control_deps = [] if validate: control_deps.append( tf.debugging.assert_positive(year, message="Year must be positive.")) control_deps.append( tf.debugging.assert_greater_equal( month, constants.Month.JANUARY.value, message=f"Month must be >= {constants.Month.JANUARY.value}")) control_deps.append( tf.debugging.assert_less_equal( month, constants.Month.DECEMBER.value, message="Month must be <= {constants.Month.JANUARY.value}")) control_deps.append( tf.debugging.assert_positive(day, message="Day must be positive.")) is_leap = date_utils.is_leap_year(year) days_in_months = tf.constant(_DAYS_IN_MONTHS_COMBINED, tf.int32) max_days = tf.gather(days_in_months, month + 12 * tf.dtypes.cast(is_leap, np.int32)) control_deps.append( tf.debugging.assert_less_equal( day, max_days, message="Invalid day-month pairing.")) with tf.compat.v1.control_dependencies(control_deps): # Ensure years, months, days themselves are under control_deps. year = tf.identity(year) month = tf.identity(month) day = tf.identity(day) with tf.compat.v1.control_dependencies(control_deps): ordinal = date_utils.year_month_day_to_ordinal(year, month, day) return DateTensor(ordinal, year, month, day)
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 = tff.datetime.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 _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))