| // Copyright 2016 The Fuchsia Authors |
| // |
| // 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. |
| |
| // A Cobalt day-index assigns to each date of the calendar on or after |
| // Junuary 1, 1970 a non-negative integer index with |
| // January 1, 1970 being assigned the index 0. For example |
| // |
| // Calendar Date Cobalt day-index |
| // ---------- ---------------- |
| // January 1, 1970 0 |
| // January 2, 1970 1 |
| // February 1, 1970 31 |
| // October 18, 2016 17,092 |
| // |
| // Notice that a day-index does not represent a fixed 24-hour period of real |
| // time because the day with day-index n has a different meaning in |
| // different time-zones. Thus there is no well-defined mapping from an |
| // instant of time to a day index. |
| // |
| // For the purpose of aggregating observations for analysis and reporting, |
| // Cobalt uses three types of epochs: Day, Week, and Month. A week epoch |
| // is a squence of 7 days from a Sunday to a Saturday. A month epoch is a |
| // sequence of days in a calendar month. |
| // |
| // Each week and month epoch containing days on or after January 1, 1970 is |
| // also given a zero-based index as follows: |
| // |
| // Calendar Week Cobalt week epoch index |
| // ---------------------------- ----------------------- |
| // Thu 1970-1-1 - Sat 1970-1-3 0 |
| // Sun 1970-1-4 - Sat 1970-1-10 1 |
| // Sun 1970-1-11 - Sun 1970-1-17 2 |
| // Sun 1970-1-18 - Sun 1970-1-24 3 |
| // etc. |
| // |
| // |
| // Calendar Month Cobalt month epoch index |
| // -------------- ----------------------- |
| // January, 1970 0 |
| // February, 1970 1 |
| // March, 1970 2 |
| // etc. |
| |
| #ifndef COBALT_UTIL_DATETIME_UTIL_H_ |
| #define COBALT_UTIL_DATETIME_UTIL_H_ |
| |
| #include <atomic> |
| #include <chrono> |
| #include <cstdint> |
| |
| #include "config/metrics.pb.h" |
| |
| namespace cobalt { |
| namespace util { |
| |
| // Unix seconds differ from physical seconds on a day in which there is |
| // a leap second. |
| static const uint32_t kNumUnixSecondsPerDay = 60L * 60L * 24L; |
| |
| static const uint32_t kInvalidIndex = UINT32_MAX; |
| |
| // A CalendarDate represents a day on the calendar using normal human-readable |
| // indexing. Just as with day-index there is no well-defined mapping from an |
| // instant of time to a CalendarDate because this depends on the timezone. |
| struct CalendarDate { |
| // A number from 1 to 31. |
| uint32_t day_of_month = 1; |
| |
| // 1 = January, 2 = February, ..., 12 = December |
| uint32_t month = 1; |
| |
| // Calendar year e.g. 2016. |
| uint32_t year = 1970; |
| |
| bool operator==(const CalendarDate& other) const { |
| return (other.day_of_month == day_of_month && other.month == month && |
| other.year == year); |
| } |
| }; |
| |
| // Returns the day index corresponding to |time| in the given |time_zone| |
| // or UINT32_MAX if |time_zone| is not valid. |time| must be a Unix timestamp, |
| // that is a number of Unix seconds since the Unix epoch. |
| uint32_t TimeToDayIndex(time_t time, Metric::TimeZonePolicy time_zone); |
| |
| // Converts the given CalendarDate to a Cobalt Day Index. If the fields of |
| // calendar_date do not make sense as a real day of the calendar |
| // (for example if month=13) then the result is undefined. If the |
| // specified date is prior to January 1, 1970 or not before the year 10,000 |
| // then the result is undefined. |
| uint32_t CalendarDateToDayIndex(const CalendarDate& calendar_date); |
| |
| // Converts the given day_index to a CalendarDate, necessarily on or |
| // after January 1, 1970. |
| CalendarDate DayIndexToCalendarDate(uint32_t day_index); |
| |
| // Given a day_index returns the index of the Cobalt week epoch |
| // containing that date. |
| uint32_t DayIndexToWeekIndex(uint32_t day_index); |
| |
| // Given a CalendarDate returns the index of the Cobalt week epoch |
| // containing that date. If the fields of calendar_date do not make sense as a |
| // real day of the calendar (for example if month=13) then the result is |
| // undefined. If the specified date is prior to January 1, 1970 then the result |
| // is undefined. |
| uint32_t CalendarDateToWeekIndex(const CalendarDate& calendar_date); |
| |
| // Given the index of a Cobalt week epoch returns the CalendarDate for the first |
| // day of that week epoch. In all cases except week_index=0 the |
| // returned date will be a Sunday. If week_index=0 the returned date will |
| // be day zero: Thu 1970-1-1. |
| CalendarDate WeekIndexToCalendarDate(uint32_t week_index); |
| |
| // Given a day_index returns the index of the Cobalt month epoch |
| // containing that date. |
| uint32_t DayIndexToMonthIndex(uint32_t day_index); |
| |
| // Given a CalendarDate returns the index of the Cobalt month epoch |
| // containing that date. If the fields of |
| // calendar_date do not make sense as a real day of the calendar (for example if |
| // month=13) then the result is undefined. If the specified date is prior to |
| // January 1, 1970 then the result is undefined. |
| uint32_t CalendarDateToMonthIndex(const CalendarDate& calendar_date); |
| |
| // Given the index of a Cobalt month epoch returns the CalendarDate for the |
| // first day of that month epoch. |
| CalendarDate MonthIndexToCalendarDate(uint32_t month_index); |
| |
| // An abstract clock interface. |
| class ClockInterface { |
| public: |
| virtual int64_t CurrentTimeSeconds() = 0; |
| }; |
| |
| // An implementation of ClockInterface that uses the system clock. |
| class SystemClock : public ClockInterface { |
| public: |
| int64_t CurrentTimeSeconds() override { |
| return std::chrono::duration_cast<std::chrono::seconds>( |
| std::chrono::system_clock::now().time_since_epoch()) |
| .count(); |
| } |
| }; |
| |
| // An implementation of ClockInterface that returns a fixed, settable value. |
| class StationaryClock : public ClockInterface { |
| public: |
| StationaryClock() { current_time_seconds_ = 0; } |
| |
| int64_t CurrentTimeSeconds() override { return current_time_seconds_; } |
| |
| void set_current_time_seconds(int64_t current_time_seconds) { |
| current_time_seconds_ = current_time_seconds; |
| } |
| |
| private: |
| std::atomic<int64_t> current_time_seconds_; |
| }; |
| |
| } // namespace util |
| } // namespace cobalt |
| |
| #endif // COBALT_UTIL_DATETIME_UTIL_H_ |