224 lines
8.2 KiB
C++
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_
|