sql_utils/public/functions/date_time_util_internal.cc (43 lines of code) (raw):

/* * Copyright 2023 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "sql_utils/public/functions/date_time_util_internal.h" #include "sql_utils/base/logging.h" #include "absl/time/civil_time.h" namespace bigquery_ml_utils { namespace functions { namespace date_time_util_internal { absl::civil_year_t GetIsoYear(absl::CivilDay day) { // ISO year numbers diverge from Gregorian calendar year numbers at the // beginnings and ends of some years. Specifically, if this date is at // least 12/29 and the week that the date falls in has four or more days // in the following year, then the ISO year is that of the following // year. A similar principal applies for dates between 1/1 and 1/3. absl::CivilDay monday_of_week = PrevWeekdayOrToday(day, absl::Weekday::monday); absl::CivilDay day_defining_year_of_week = absl::NextWeekday(monday_of_week, absl::Weekday::thursday); return day_defining_year_of_week.year(); } absl::CivilDay GetFirstDayOfIsoYear(absl::CivilDay day) { absl::civil_year_t iso_year = GetIsoYear(day); // Find the first Thursday. absl::CivilDay first_day(iso_year, 1, 1); absl::CivilDay first_thursay = NextWeekdayOrToday(first_day, absl::Weekday::thursday); // The first day of the iso year is the prior monday. return absl::PrevWeekday(first_thursay, absl::Weekday::monday); } absl::CivilDay GetLastDayOfIsoYear(absl::CivilDay day) { absl::civil_year_t iso_year = GetIsoYear(day); // Find the last Thursday. absl::CivilDay last_day(iso_year, 12, 31); absl::CivilDay last_thursday = PrevWeekdayOrToday(last_day, absl::Weekday::thursday); // The last day of the iso year is the next sunday. return absl::NextWeekday(last_thursday, absl::Weekday::sunday); } int GetIsoWeek(absl::CivilDay day) { absl::CivilDay monday_of_week = PrevWeekdayOrToday(day, absl::Weekday::monday); absl::CivilDay first_monday_of_iso_year = GetFirstDayOfIsoYear(day); absl::civil_diff_t iso_week = ((monday_of_week - first_monday_of_iso_year) / 7) + 1; SQL_CHECK_GE(iso_week, 1); SQL_CHECK_LE(iso_week, 53); return static_cast<int>(iso_week); } // See https://en.wikipedia.org/wiki/Leap_year#Algorithm for the definition of // leap year. bool IsLeapYear(int64_t year) { return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); } } // namespace date_time_util_internal } // namespace functions } // namespace bigquery_ml_utils