Files
oemcrypto/util/include/wv_date_time.h
2025-05-22 16:33:29 -07:00

224 lines
8.2 KiB
C++

// Copyright 2025 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
#ifndef WVCDM_UTIL_DATE_TIME_H_
#define WVCDM_UTIL_DATE_TIME_H_
#include <stdint.h>
#include <chrono>
#include <optional>
#include <ostream>
#include <string>
#include "wv_class_utils.h"
#include "wv_duration.h"
#include "wv_timestamp.h"
namespace wvutil {
// The DateTime class represents a time point measured in UTC
// Gregorian calendar dates and 24-hour timekeeping system.
//
// Internally, the time is measured in Unix Time (milliseconds
// since January 1st, 1970 (epoch)).
//
// For the CDM, we are not concerned about time points before
// January 1st, 1970; this class does not support negative epoch
// seconds. In addition, zero is treated as a special value
// which indicates an uninitialized time point.
//
// Min DateTime: 1970-01-01 00:00:00.001 (epoch ms = 1)
// Max DateTime: 9999-12-31 23:59:59.999 (epoch ms = 253402300799999)
//
// Converting from Unix Time to datetime components is a potentially
// expensive operation for their amount of utility; to reduce this
// overhead date components are calculated once per change, and stored
// individually.
//
// For testing, use the DateTime::Builder class for create DateTime
// instances from their individual components.
//
// The DateTime class provides a PrintTo()/ToString() method which
// returns an initialized DateTime in ISO 8601 format without timezone
// indicator and with milliseconds only being printed if non-zero.
// Use DateTime::Formatter for specific formatting needs.
class DateTime {
public:
constexpr DateTime() = default; // Uninitialized DateTime.
WVCDM_CONSTEXPR_DEFAULT_COPY_AND_MOVE(DateTime);
private:
// Note: This private section is needed here.
// clang++ with -Wundefined-inline will complain about certain
// inline members not being declared before use in other inline
// methods.
template <class ToDuration>
constexpr ToDuration EpochFloor() const {
return std::chrono::floor<ToDuration>(epoch_milliseconds());
}
public:
static DateTime FromTimestamp(const Timestamp& timestamp);
// Create a DateTime instance from Unix Time in epoch seconds.
// Optionally allowed to include |millisecond| (0 to 999).
// If |epoch_seconds| or |millisecond| are invalid values, then an
// uninitlaized DateTime instance is returned.
static DateTime FromUnixSeconds(uint64_t epoch_seconds,
uint32_t milliseconds = 0) {
return FromTimestamp(
Timestamp::FromUnixSeconds(epoch_seconds, milliseconds));
}
static DateTime FromUnixSeconds(const Seconds& epoch_seconds,
uint32_t milliseconds = 0) {
return FromTimestamp(
Timestamp::FromUnixSeconds(epoch_seconds, milliseconds));
}
// Create a DateTime instance from Unix Time in epoch milliseconds.
// If |epoch_milliseconds| is an invalid value (zero), then an
// uninitlaized DateTime instance is returned.
static DateTime FromUnixMilliseconds(uint64_t epoch_milliseconds) {
return FromTimestamp(Timestamp::FromUnixMilliseconds(epoch_milliseconds));
}
static DateTime FromUnixMilliseconds(const Milliseconds& epoch_milliseconds) {
return FromTimestamp(Timestamp::FromUnixMilliseconds(epoch_milliseconds));
}
// Obtain the minimum and maximum representable DateTime.
static DateTime Min() { return FromTimestamp(Timestamp::Min()); }
static DateTime Max() { return FromTimestamp(Timestamp::Max()); }
constexpr const Timestamp& timestamp() const { return timestamp_; }
// == Epoch Accessors ==
constexpr Seconds epoch_seconds() const { return timestamp_.epoch_seconds(); }
constexpr Milliseconds epoch_milliseconds() const {
return timestamp_.epoch_milliseconds();
}
// == Component Accessors ==
// Year on Gregorian calendar (1970 - 9999; 0 if unset)
constexpr uint32_t year() const { return year_; }
// Month of the year (January = 1, December = 12; 0 if unset)
constexpr uint32_t month() const { return month_; }
// Day of the month (1 - 28/29/30/31; 0 if unset)
constexpr uint32_t day() const { return day_; }
// Day of the year (1 - 365/366; 0 if unset)
constexpr uint32_t day_of_year() const { return day_of_year_; }
// Day of the week (1 (Sunday) - 7 (Saturday); 0 if unset)
constexpr uint32_t day_of_week() const { return day_of_week_; }
// Time component accessors.
// Hour of day (0 - 23; 0 if unset)
constexpr uint32_t hour() const {
if (!IsSet()) return 0;
return static_cast<uint32_t>(
(EpochFloor<Hours>() - EpochFloor<Days>()).count());
}
// Minute of hour (0 - 59; 0 if unset)
constexpr uint32_t minute() const {
if (!IsSet()) return 0;
return static_cast<uint32_t>(
(EpochFloor<Minutes>() - EpochFloor<Hours>()).count());
}
// Second of minute (0 - 59; 0 if unset)
constexpr uint32_t second() const {
if (!IsSet()) return 0;
return static_cast<uint32_t>(
(EpochFloor<Seconds>() - EpochFloor<Minutes>()).count());
}
// Millisecond of second (0 - 999; 0 if unset)
constexpr uint32_t millisecond() const { return timestamp_.milliseconds(); }
// Checks if the DateTime instance is set.
constexpr bool IsSet() const { return timestamp_.IsSet(); }
constexpr explicit operator bool() const { return IsSet(); }
constexpr void Clear() {
timestamp_.Clear();
ClearComponents();
}
// == Comparison Operators ==
constexpr bool IsEqualTo(const DateTime& other) const {
return timestamp_.IsEqualTo(other.timestamp_);
}
constexpr int64_t CompareTo(const DateTime& other) const {
return timestamp_.CompareTo(other.timestamp_);
}
WVCDM_DEFINE_CONSTEXPR_EQ_AND_CMP_OPERATORS(DateTime);
constexpr bool IsEqualTo(const Timestamp& other) const {
return timestamp_.IsEqualTo(other);
}
constexpr int64_t CompareTo(const Timestamp& other) const {
return timestamp_.CompareTo(other);
}
WVCDM_DEFINE_CONSTEXPR_EQ_AND_CMP_OPERATORS(Timestamp);
// == Duration Operators ==
// Duration-based addition/subtraction operations.
// Returns a new DateTime instance with time point adjusted by
// the provided Duration.
// If current DateTime instance is unset, or if result value
// is outside the range of valid DateTime values, then an unset
// DateTime is returned.
DateTime operator+(const Duration& duration) const;
DateTime operator-(const Duration& duration) const;
// DateTime difference.
// Returns the duration between the two provided DateTime
// instances.
// If either DateTime instance is unset, then the resulting
// Duration is zero.
Duration operator-(const DateTime& other) const;
// Duration-based increment/decrement operators.
// Increment or decrement the DateTime by the provided Duration
// amount.
// If current DateTime instance is unset, then no action will
// occur. If result value is outside the range of valid DateTime
// values, then DateTime will be unset.
DateTime& operator+=(const Duration& duration);
DateTime& operator-=(const Duration& duration);
// For initialized DateTime instances, returns the datetime
// in ISO 8601 format. Milliseconds are only printed
// if non-zero.
// An uninitialized DateTime will return an empty string.
// Ex:
// Without milli: 2024-01-19T14:49:13Z
// With milli: 2024-01-19T14:49:13.507Z
// Use DateTime::Formatter for more formatting options.
bool PrintTo(std::ostream* out) const;
std::string ToString() const;
private:
// Special constructor.
explicit DateTime(const Timestamp& timestamp);
// Attempts to calculate subcomponents.
// Failure to calculate subcomponents will clear |timestamp_|.
void UpdateTimestamp(const Timestamp& new_timestamp);
constexpr void ClearComponents() {
year_ = month_ = day_ = day_of_year_ = day_of_week_ = 0;
}
// Source of truth for DateTime class.
Timestamp timestamp_;
// Components (derived from |timestamp_|).
uint16_t year_ = 0;
uint8_t month_ = 0;
uint8_t day_ = 0;
uint16_t day_of_year_ = 0;
uint8_t day_of_week_ = 0;
}; // class DateTime
// == GTest Printer ==
void PrintTo(const DateTime& date_time, std::ostream* out);
} // namespace wvutil
#endif // WVCDM_UTIL_DATE_TIME_H_