| // Copyright 2016 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // 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_SRC_LIB_UTIL_DATETIME_UTIL_H_ |
| #define COBALT_SRC_LIB_UTIL_DATETIME_UTIL_H_ |
| |
| #include <atomic> |
| #include <chrono> |
| #include <cstdint> |
| |
| #include "src/public/lib/clock_interfaces.h" |
| #include "src/public/lib/statusor/statusor.h" |
| #include "src/registry/cobalt_registry.pb.h" |
| #include "src/registry/metric_definition.pb.h" |
| |
| namespace cobalt::util { |
| |
| static const uint32_t kNumUnixSecondsPerHour = 60L * 60L; |
| |
| static const uint32_t kNumHoursPerDay = 24L; |
| |
| // Unix seconds differ from physical seconds on a day in which there is |
| // a leap second. |
| static const uint32_t kNumUnixSecondsPerDay = kNumUnixSecondsPerHour * 24L; |
| |
| // The interval between hour IDs for consecutive hours, assuming no change in time zone. |
| static const uint32_t kHourIdsPerHour = 2L; |
| |
| // The interval between the first hour IDs of two consecutive days, assuming no change in time zone. |
| static const uint32_t kHourIdsPerDay = kHourIdsPerHour * kNumHoursPerDay; |
| |
| static const uint32_t kInvalidIndex = UINT32_MAX; |
| |
| static const uint32_t kDefaultCalendarYear = 1970; |
| |
| static const std::chrono::system_clock::duration kOneHour = std::chrono::hours(1); |
| static const std::chrono::system_clock::duration kOneDay = std::chrono::hours(kNumHoursPerDay); |
| |
| // 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 = kDefaultCalendarYear; |
| |
| bool operator==(const CalendarDate& other) const { |
| return (other.day_of_month == day_of_month && other.month == month && other.year == year); |
| } |
| }; |
| |
| // Returns the hour ID for a time point, with respect to the time zone specified by `metric`'s time |
| // zone policy. Prefer `TimeInfo::FromTimePoint()` when both the day index and hour ID are needed. |
| lib::statusor::StatusOr<uint32_t> TimePointToHourId( |
| std::chrono::system_clock::time_point time_point, |
| const util::CivilTimeConverterInterface& civil_time_converter, const MetricDefinition& metric); |
| |
| // Returns the day index for a time point, with respect to the time zone specified by `metric`'s |
| // time zone policy. Prefer `TimeInfo::FromTimePoint()` when both the day index and hour ID are |
| // needed. |
| lib::statusor::StatusOr<uint32_t> TimePointToDayIndex( |
| std::chrono::system_clock::time_point time_point, |
| const util::CivilTimeConverterInterface& civil_time_converter, const MetricDefinition& metric); |
| |
| // Returns the hour id for a time point, with respect to UTC. Prefer |
| // `TimeInfo::FromTimePointUtc()` when both the day index and hour ID are needed. |
| uint32_t TimePointToHourIdUtc(std::chrono::system_clock::time_point time_point); |
| |
| // Returns the day index for a time point, with respect to UTC. Prefer |
| // `TimeInfo::FromTimePointUtc()` when both the day index and hour ID are needed. |
| uint32_t TimePointToDayIndexUtc(std::chrono::system_clock::time_point time_point); |
| |
| // DEPRECATED: to be replaced by `TimePointToHourId`. |
| // Returns the hour identifier. The hour identifier is calculated as follows: |
| // |
| // (TimeToDayIndex(time, time_zone) * 48) + (tm_hour * 2) + (tm_dst ? 0 : 1) |
| // |
| // See: https://fuchsia.googlesource.com/cobalt/+/master/docs/hour_id.md |
| uint32_t TimeToHourId(time_t time, MetricDefinition::TimeZonePolicy time_zone); |
| |
| // DEPRECATED: to be replaced by `TimePointToDayIndex`. |
| // 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, MetricDefinition::TimeZonePolicy time_zone); |
| |
| // Returns the Unix time for midnight of the day with the given |day_index| |
| // in UTC. |
| time_t MidnightUtcFromDayIndex(uint32_t day_index); |
| |
| // 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 day index, returns the hour identifier for the start of that day, assuming that DST is |
| // not in force. |
| uint32_t DayIndexToHourIdNoDst(uint32_t day_index); |
| |
| // Given an hour identifier, returns the index of the Cobalt day containing that hour. |
| uint32_t HourIdToDayIndex(uint32_t hour_id); |
| |
| // 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); |
| |
| // Returns the the given time as a number of seconds since the Unix epoch. |
| int64_t ToUnixSeconds(std::chrono::system_clock::time_point t); |
| int64_t DayIndexToUnixSeconds(uint32_t day_index); |
| int64_t HourIdToUnixSeconds(uint32_t hour_id); |
| |
| // Returns the given number of seconds since the Unix epoch as a time_point. |
| std::chrono::system_clock::time_point FromUnixSeconds(int64_t seconds); |
| |
| // A struct for passing time information to methods. |
| struct TimeInfo { |
| // The day index from the epoch. May not correspond to the same day as the hour in hour_id. |
| uint32_t day_index; |
| // The hour ID. |
| // See https://fuchsia.googlesource.com/cobalt/+/master/docs/hour_id.md |
| // May not correspond to the same day as the day_index. |
| uint32_t hour_id; |
| |
| // Create a TimeInfo corresponding to the given hour_id. Both the day_index and the hour_id are |
| // set to correspond to the given hour_id. |
| static TimeInfo FromHourId(uint32_t hour_id); |
| // Create a TimeInfo corresponding to the given day_index. Both the day_index and the hour_id are |
| // set to correspond to the given day_index (hour_id is set to the ID of the first hour of the |
| // day, assuming that daylight savings time is not in force). |
| static TimeInfo FromDayIndex(uint32_t day_index); |
| |
| // Create a TimeInfo corresponding to the given time. Both the day_index and the hour_id are set |
| // to correspond to the start of the given time's period, in the time zone specified by |metric|. |
| static lib::statusor::StatusOr<TimeInfo> FromTimePoint( |
| std::chrono::system_clock::time_point time, |
| const util::CivilTimeConverterInterface& civil_time_converter, |
| const MetricDefinition& metric); |
| |
| // Create a TimeInfo corresponding to the given time with respect to UTC. Both the day_index and |
| // the hour_id are set to correspond to the start of the given time's period. |
| static TimeInfo FromTimePointUtc(std::chrono::system_clock::time_point time); |
| |
| // DEPRECATED: to be replaced by the method taking a `CivilTimeConverterInterface`. |
| // Create a TimeInfo corresponding to the given time. Both the day_index and the hour_id are set |
| // to correspond to the start of the given time's period, for the specified time zone policy. Only |
| // supports UTC and LOCAL time zone policies. |
| static TimeInfo FromTimePoint(std::chrono::system_clock::time_point time, |
| MetricDefinition::TimeZonePolicy time_zone); |
| }; |
| |
| // Stream operator useful for logging TimeInfo objects. |
| std::ostream& operator<<(std::ostream& o, const TimeInfo& a); |
| |
| } // namespace cobalt::util |
| |
| #endif // COBALT_SRC_LIB_UTIL_DATETIME_UTIL_H_ |