Skip to content

Commit 56475b0

Browse files
authored
DateTime: API review feedback (#938)
1 parent 2ce6e28 commit 56475b0

File tree

4 files changed

+394
-238
lines changed

4 files changed

+394
-238
lines changed

sdk/core/azure-core/inc/azure/core/datetime.hpp

Lines changed: 141 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
#pragma once
1010

11-
#include <stdexcept>
11+
#include <chrono>
1212
#include <string>
1313

1414
namespace Azure { namespace Core {
@@ -17,28 +17,25 @@ namespace Azure { namespace Core {
1717
*/
1818
class DateTime {
1919
public:
20-
/// A type that represents tick spans.
21-
typedef uint64_t IntervalType;
22-
23-
private:
24-
// Number of seconds between 01-01-1970 and 01-01-1601.
25-
static constexpr IntervalType WindowsToPosixOffsetSeconds = 11644473600LL;
20+
/**
21+
* @brief Units of measurement the difference between instances of @DateTime.
22+
*/
23+
// 1 == 100 ns (1 / 10,000,000 of a second, 7 fractional digits).
24+
typedef std::chrono::duration<int64_t, std::ratio<1, 10000000>> Duration;
2625

27-
public:
2826
/**
29-
* @brief Defines the format applied to the fraction part from any @DateFormat
30-
*
27+
* @brief Defines the format applied to the fraction part of any @DateTime.
3128
*/
3229
enum class TimeFractionFormat
3330
{
34-
/// Decimals are not included when there are no decimals in the source Datetime and any zeros
35-
/// from the right are also removed.
31+
/// Include only meaningful fractional time digits, up to and excluding trailing zeroes.
3632
DropTrailingZeros,
3733

38-
/// Decimals are included for any Datetime.
34+
/// Include all the fractional time digits up to maximum precision, even if the entire value
35+
/// is zero.
3936
AllDigits,
4037

41-
/// Decimals are removed for any Datetime.
38+
/// Drop all the fractional time digits.
4239
Truncate
4340
};
4441

@@ -50,170 +47,193 @@ namespace Azure { namespace Core {
5047
/// RFC 1123.
5148
Rfc1123,
5249

53-
/// ISO 8601.
54-
Iso8601,
50+
/// RFC 3339.
51+
Rfc3339,
5552
};
5653

5754
/**
5855
* @brief Get the current UTC time.
5956
*/
60-
static DateTime UtcNow();
61-
62-
/// An invalid UTC timestamp value.
63-
static constexpr IntervalType UtcTimestampInvalid = static_cast<IntervalType>(-1);
64-
65-
/**
66-
* @brief Get seconds since Unix/POSIX time epoch at `01-01-1970 00:00:00`.
67-
* If time is before epoch, @UtcTimestampInvalid is returned.
68-
*/
69-
static IntervalType UtcTimestamp()
70-
{
71-
auto const seconds = UtcNow().ToInterval() / WindowsToPosixOffsetSeconds;
72-
return (seconds >= WindowsToPosixOffsetSeconds) ? (seconds - WindowsToPosixOffsetSeconds)
73-
: UtcTimestampInvalid;
74-
}
57+
static DateTime Now();
7558

7659
/**
77-
* @brief Construct an uninitialized (!@IsInitialized()) instance of @DateTime.
60+
* @brief Construct an instance of @DateTime.
61+
*
62+
* @param year Year.
63+
* @param month Month.
64+
* @param day Day.
65+
* @param hour Hour.
66+
* @param minute Minute.
67+
* @param second Seconds.
68+
*
69+
* @throw std::invalid_argument If any parameter is invalid.
7870
*/
79-
DateTime() : m_interval(0) {}
71+
explicit DateTime(
72+
int16_t year,
73+
int8_t month = 1,
74+
int8_t day = 1,
75+
int8_t hour = 0,
76+
int8_t minute = 0,
77+
int8_t second = 0);
8078

8179
/**
8280
* @brief Create @DateTime from a string representing time in UTC in the specified format.
8381
*
84-
* @param timeString A string with the date and time.
85-
* @param format A format to which /p timeString adheres to.
82+
* @param dateTime A string with the date and time.
83+
* @param format A format to which \p dateTime string adheres to.
8684
*
87-
* @return @DateTime that was constructed from the \p timeString; Uninitialized
88-
* (!@IsInitialized()) @DateTime if parsing \p timeString was not successful.
85+
* @return @DateTime that was constructed from the \p dateTime string.
8986
*
90-
* @throw DateTimeException If \p format is not recognized.
87+
* @throw std::invalid_argument If \p format is not recognized, or if parsing error.
9188
*/
92-
static DateTime FromString(
93-
std::string const& timeString,
94-
DateFormat format = DateFormat::Rfc1123);
89+
static DateTime Parse(std::string const& dateTime, DateFormat format);
9590

9691
private:
9792
/**
9893
* @brief Get a string representation of the @DateTime.
9994
*
10095
* @param format The representation format to use.
10196
* @param fractionFormat The format for the fraction part of the Datetime. Only supported by
102-
* ISO8601
97+
* RFC 3339.
10398
*
104-
* @throw DateTimeException If year exceeds 9999, or if \p format is not recognized.
99+
* @throw std::length_error If year exceeds 9999, or if \p format is not recognized.
105100
*/
106-
std::string ToString(DateFormat format, TimeFractionFormat fractionFormat) const;
101+
std::string GetString(DateFormat format, TimeFractionFormat fractionFormat) const;
107102

108103
public:
109104
/**
110105
* @brief Get a string representation of the @DateTime.
111106
*
112107
* @param format The representation format to use.
113108
*
114-
* @throw DateTimeException If year exceeds 9999, or if \p format is not recognized.
109+
* @throw std::length_error If year exceeds 9999, or if \p format is not recognized.
115110
*/
116-
std::string ToString(DateFormat format = DateFormat::Rfc1123) const
111+
std::string GetString(DateFormat format) const
117112
{
118-
return ToString(format, TimeFractionFormat::DropTrailingZeros);
113+
return GetString(format, TimeFractionFormat::DropTrailingZeros);
119114
};
120115

121116
/**
122-
* @brief Get a string representation of the @DateTime formated with ISO8601.
117+
* @brief Get a string representation of the @DateTime formatted with RFC 3339.
123118
*
124-
* @param fractionFormat The format that is applied to the fraction part from the ISO8601 date.
119+
* @param fractionFormat The format that is applied to the fraction part from the RFC 3339 date.
125120
*
126-
* @throw DateTimeException If year exceeds 9999, or if \p fractionFormat is not recognized.
121+
* @throw std::length_error If year exceeds 9999.
122+
* @throw std::invalid_argument If \p format is not recognized.
127123
*/
128-
std::string ToIso8601String(TimeFractionFormat fractionFormat) const
124+
std::string GetRfc3339String(TimeFractionFormat fractionFormat) const
129125
{
130-
return ToString(DateFormat::Iso8601, fractionFormat);
126+
return GetString(DateFormat::Rfc3339, fractionFormat);
131127
};
132128

133-
/// Get the integral time value.
134-
IntervalType ToInterval() const { return m_interval; }
135-
136-
/// Subtract an interval from @DateTime.
137-
DateTime operator-(IntervalType value) const { return DateTime(m_interval - value); }
129+
/**
130+
* @brief Add \p duration to this @DateTime.
131+
* @param duration @Duration to add.
132+
* @return Reference to this @DateTime.
133+
*/
134+
DateTime& operator+=(Duration const& duration)
135+
{
136+
m_since1601 += duration;
137+
return *this;
138+
}
138139

139-
/// Add an interval to @DateTime.
140-
DateTime operator+(IntervalType value) const { return DateTime(m_interval + value); }
140+
/**
141+
* @brief Subtract \p duration from this @DateTime.
142+
* @param duration @Duration to subtract from this @DateTime.
143+
* @return Reference to this @DateTime.
144+
*/
145+
DateTime& operator-=(Duration const& duration)
146+
{
147+
m_since1601 -= duration;
148+
return *this;
149+
}
141150

142-
/// Compare two instances of @DateTime for equality.
143-
bool operator==(DateTime dt) const { return m_interval == dt.m_interval; }
151+
/**
152+
* @brief Subtract @Duration from @DateTime.
153+
* @param duration @Duration to subtract from this @DateTime.
154+
* @return New DateTime representing subtraction result.
155+
*/
156+
DateTime operator-(Duration const& duration) const { return DateTime(m_since1601 - duration); }
144157

145-
/// Compare two instances of @DateTime for inequality.
146-
bool operator!=(const DateTime& dt) const { return !(*this == dt); }
158+
/**
159+
* @brief Add @Duration to @DateTime.
160+
* @param duration @Duration to add to this @DateTime.
161+
* @return New DateTime representing addition result.
162+
*/
163+
DateTime operator+(Duration const& duration) const { return DateTime(m_since1601 + duration); }
147164

148-
/// Compare the chronological order of two @DateTime instances.
149-
bool operator>(const DateTime& dt) const { return this->m_interval > dt.m_interval; }
165+
/**
166+
* @brief Get @Duration between two instances of @DateTime.
167+
* @param other @DateTime to subtract from this @DateTime.
168+
* @return @Duration between this @DateTime and the \p other.
169+
*/
170+
Duration operator-(DateTime const& other) const { return m_since1601 - other.m_since1601; }
150171

151-
/// Compare the chronological order of two @DateTime instances.
152-
bool operator<(const DateTime& dt) const { return this->m_interval < dt.m_interval; }
172+
/**
173+
* @brief Compare with \p other @DateTime for equality.
174+
* @param other Other @DateTime to compare with.
175+
* @return `true` if @DateTime instances are equal, `false` otherwise.
176+
*/
177+
constexpr bool operator==(DateTime const& other) const
178+
{
179+
return m_since1601 == other.m_since1601;
180+
}
153181

154-
/// Compare the chronological order of two @DateTime instances.
155-
bool operator>=(const DateTime& dt) const { return this->m_interval >= dt.m_interval; }
182+
/**
183+
* @brief Compare with \p other @DateTime for inequality.
184+
* @param other Other @DateTime to compare with.
185+
* @return `true` if @DateTime instances are not equal, `false` otherwise.
186+
*/
187+
constexpr bool operator!=(const DateTime& other) const { return !(*this == other); }
156188

157-
/// Compare the chronological order of two @DateTime instances.
158-
bool operator<=(const DateTime& dt) const { return this->m_interval <= dt.m_interval; }
189+
/**
190+
* @brief Check if \p other @DateTime precedes this @DateTime chronologically.
191+
* @param other @DateTime to compare with.
192+
* @return `true` if the \p other @DateTime precedes this, `false` otherwise.
193+
*/
194+
constexpr bool operator>(const DateTime& other) const { return !(*this <= other); }
159195

160-
/// Create an interval from milliseconds.
161-
static IntervalType FromMilliseconds(unsigned int milliseconds)
196+
/**
197+
* @brief Check if \p other @DateTime is chronologically after this @DateTime.
198+
* @param other @DateTime to compare with.
199+
* @return `true` if the \p other @DateTime is chonologically after this @DateTime, `false`
200+
* otherwise.
201+
*/
202+
constexpr bool operator<(const DateTime& other) const
162203
{
163-
return milliseconds * TicksPerMillisecond;
204+
return this->m_since1601 < other.m_since1601;
164205
}
165206

166-
/// Create an interval from seconds.
167-
static IntervalType FromSeconds(unsigned int seconds) { return seconds * TicksPerSecond; }
168-
169-
/// Create an interval from minutes.
170-
static IntervalType FromMinutes(unsigned int minutes) { return minutes * TicksPerMinute; }
171-
172-
/// Create an interval from hours.
173-
static IntervalType FromHours(unsigned int hours) { return hours * TicksPerHour; }
207+
/**
208+
* @brief Check if \p other @DateTime precedes this @DateTime chronologically, or is equal to
209+
* it.
210+
* @param other @DateTime to compare with.
211+
* @return `true` if the \p other @DateTime precedes or is equal to this @DateTime, `false`
212+
* otherwise.
213+
*/
214+
constexpr bool operator>=(const DateTime& other) const { return !(*this < other); }
174215

175-
/// Create an interval from days.
176-
static IntervalType FromDays(unsigned int days) { return days * TicksPerDay; }
216+
/**
217+
* @brief Check if \p other @DateTime is chronologically after or equal to this @DateTime.
218+
* @param other @DateTime to compare with.
219+
* @return `true` if the \p other @DateTime is chonologically after or equal to this @DateTime,
220+
* `false` otherwise.
221+
*/
222+
constexpr bool operator<=(const DateTime& other) const
223+
{
224+
return (*this == other) || (*this < other);
225+
}
177226

178-
/// Checks whether this instance of @DateTime is initialized.
179-
bool IsInitialized() const { return m_interval != 0; }
227+
/**
228+
* @brief Get this @DateTime representation as a @Duration from the start of the
229+
* implementation-defined epoch.
230+
* @return @Duration since the start of the implementation-defined epoch.
231+
*/
232+
constexpr explicit operator Duration() const { return m_since1601; }
180233

181234
private:
182-
friend IntervalType operator-(DateTime t1, DateTime t2);
183-
184-
static constexpr IntervalType TicksPerMillisecond = static_cast<IntervalType>(10000);
185-
static constexpr IntervalType TicksPerSecond = 1000 * TicksPerMillisecond;
186-
static constexpr IntervalType TicksPerMinute = 60 * TicksPerSecond;
187-
static constexpr IntervalType TicksPerHour = 60 * TicksPerMinute;
188-
static constexpr IntervalType TicksPerDay = 24 * TicksPerHour;
189-
190235
// Private constructor. Use static methods to create an instance.
191-
DateTime(IntervalType interval) : m_interval(interval) {}
192-
193-
// Storing as hundreds of nanoseconds 10e-7, i.e. 1 here equals 100ns.
194-
IntervalType m_interval;
195-
};
196-
197-
inline DateTime::IntervalType operator-(DateTime t1, DateTime t2)
198-
{
199-
auto diff = (t1.m_interval - t2.m_interval);
200-
201-
// Round it down to seconds
202-
diff /= DateTime::TicksPerSecond;
203-
204-
return static_cast<DateTime::IntervalType>(diff);
205-
}
206-
207-
/**
208-
* @brief An exception that gets thrown when @DateTime error occurs.
209-
*/
210-
class DateTimeException : public std::runtime_error {
211-
public:
212-
/**
213-
* @brief Construct with message string.
214-
*
215-
* @param msg Message string.
216-
*/
217-
explicit DateTimeException(std::string const& msg) : std::runtime_error(msg) {}
236+
explicit DateTime(Duration const& since1601) : m_since1601(since1601) {}
237+
Duration m_since1601;
218238
};
219239
}} // namespace Azure::Core

0 commit comments

Comments
 (0)