blob: bfb59669d7e27e249731069962a2a1b9274b317b [file] [log] [blame]
// 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_