Lightweight 0.20261105.1
Loading...
Searching...
No Matches
SqlDateTime.hpp
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4
5#include "../SqlColumnTypeDefinitions.hpp"
6#include "Core.hpp"
7#include "SqlDate.hpp"
8#include "SqlTime.hpp"
9
10#include <algorithm>
11#include <chrono>
12#include <cstddef>
13#include <cstring>
14#include <format>
15#include <memory>
16#include <ranges>
17#include <string_view>
18#include <vector>
19
20#include <sql.h>
21#include <sqlext.h>
22#include <sqltypes.h>
23
24namespace Lightweight
25{
26
27/// Represents a date and time to efficiently write to or read from a database.
28///
29/// @see SqlDate, SqlTime
30/// @ingroup DataTypes
32{
33 /// The native C++ type representing a date-time value.
34 using native_type = std::chrono::system_clock::time_point;
35 /// The duration type used for arithmetic operations.
36 using duration_type = std::chrono::system_clock::duration;
37
38 /// Returns the current date and time.
39 [[nodiscard]] static LIGHTWEIGHT_FORCE_INLINE SqlDateTime Now() noexcept
40 {
41 return SqlDateTime { std::chrono::system_clock::now() };
42 }
43
44#if !defined(LIGHTWEIGHT_CXX26_REFLECTION)
45 /// Return the current date and time in UTC.
46 [[nodiscard]] static LIGHTWEIGHT_FORCE_INLINE SqlDateTime NowUTC() noexcept
47 {
48 // `std::chrono::system_clock` already represents Unix time (UTC, no leap seconds) and is what
49 // `SqlDateTime` stores, so it yields the correct UTC value directly and identically on every
50 // platform. We deliberately avoid `utc_clock::now().time_since_epoch()` here: it counts leap
51 // seconds, so reinterpreting that duration as a `system_clock::time_point` would shift the value
52 // ~27s into the future, and `utc_clock` is unavailable on libc++ without a built-in tz database
53 // (the Homebrew toolchain on macOS) — both branches would otherwise disagree.
54 return SqlDateTime { std::chrono::system_clock::now() };
55 }
56#endif
57
58 /// Default constructor.
59 constexpr SqlDateTime() noexcept = default;
60 /// Default move constructor.
61 constexpr SqlDateTime(SqlDateTime&&) noexcept = default;
62 /// Default move assignment operator.
63 constexpr SqlDateTime& operator=(SqlDateTime&&) noexcept = default;
64 /// Default copy constructor.
65 constexpr SqlDateTime(SqlDateTime const&) noexcept = default;
66 /// Default copy assignment operator.
67 constexpr SqlDateTime& operator=(SqlDateTime const& other) noexcept = default;
68 constexpr ~SqlDateTime() noexcept = default;
69
70 /// Three-way comparison operator.
71 constexpr std::weak_ordering operator<=>(SqlDateTime const& other) const noexcept
72 {
73 return value() <=> other.value();
74 }
75 /// Equality comparison operator.
76 constexpr bool operator==(SqlDateTime const& other) const noexcept
77 {
78 return (*this <=> other) == std::weak_ordering::equivalent;
79 }
80
81 /// Inequality comparison operator.
82 constexpr bool operator!=(SqlDateTime const& other) const noexcept
83 {
84 return !(*this == other);
85 }
86
87 /// Constructs a date and time from individual components.
88 LIGHTWEIGHT_FORCE_INLINE constexpr SqlDateTime(std::chrono::year_month_day ymd,
89 std::chrono::hh_mm_ss<duration_type> time) noexcept:
90 sqlValue {
91 .year = (SQLSMALLINT) (int) ymd.year(),
92 .month = (SQLUSMALLINT) (unsigned) ymd.month(),
93 .day = (SQLUSMALLINT) (unsigned) ymd.day(),
94 .hour = (SQLUSMALLINT) time.hours().count(),
95 .minute = (SQLUSMALLINT) time.minutes().count(),
96 .second = (SQLUSMALLINT) time.seconds().count(),
97 .fraction =
98 (SQLUINTEGER) (std::chrono::duration_cast<std::chrono::nanoseconds>(time.to_duration()).count() / 100) * 100,
99 }
100 {
101 }
102
103 /// Constructs a date and time from individual components.
104 LIGHTWEIGHT_FORCE_INLINE constexpr SqlDateTime(
105 std::chrono::year year,
106 std::chrono::month month,
107 std::chrono::day day,
108 std::chrono::hours hour,
109 std::chrono::minutes minute,
110 std::chrono::seconds second,
111 std::chrono::nanoseconds nanosecond = std::chrono::nanoseconds(0)) noexcept:
112 sqlValue {
113 .year = (SQLSMALLINT) (int) year,
114 .month = (SQLUSMALLINT) (unsigned) month,
115 .day = (SQLUSMALLINT) (unsigned) day,
116 .hour = (SQLUSMALLINT) hour.count(),
117 .minute = (SQLUSMALLINT) minute.count(),
118 .second = (SQLUSMALLINT) second.count(),
119 .fraction = (SQLUINTEGER) (nanosecond.count() / 100) * 100,
120 }
121 {
122 }
123
124 /// Constructs a date and time from a time point.
125 LIGHTWEIGHT_FORCE_INLINE constexpr SqlDateTime(std::chrono::system_clock::time_point value) noexcept:
127 {
128 }
129
130 // NOLINTBEGIN(readability-identifier-naming)
131
132 /// Returns the year of this date-time object.
133 [[nodiscard]] constexpr LIGHTWEIGHT_FORCE_INLINE std::chrono::year year() const noexcept
134 {
135 return std::chrono::year(static_cast<int>(sqlValue.year));
136 }
137
138 /// Returns the month of this date-time object.
139 [[nodiscard]] constexpr LIGHTWEIGHT_FORCE_INLINE std::chrono::month month() const noexcept
140 {
141 return std::chrono::month(static_cast<unsigned>(sqlValue.month));
142 }
143
144 /// Returns the day of this date-time object.
145 [[nodiscard]] constexpr LIGHTWEIGHT_FORCE_INLINE std::chrono::day day() const noexcept
146 {
147 return std::chrono::day(static_cast<unsigned>(sqlValue.day));
148 }
149
150 /// Returns the hour of this date-time object.
151 [[nodiscard]] constexpr LIGHTWEIGHT_FORCE_INLINE std::chrono::hours hour() const noexcept
152 {
153 return std::chrono::hours(static_cast<unsigned>(sqlValue.hour));
154 }
155
156 /// Returns the minute of this date-time object.
157 [[nodiscard]] constexpr LIGHTWEIGHT_FORCE_INLINE std::chrono::minutes minute() const noexcept
158 {
159 return std::chrono::minutes(static_cast<unsigned>(sqlValue.minute));
160 }
161
162 /// Returns the second of this date-time object.
163 [[nodiscard]] constexpr LIGHTWEIGHT_FORCE_INLINE std::chrono::seconds second() const noexcept
164 {
165 return std::chrono::seconds(static_cast<unsigned>(sqlValue.second));
166 }
167
168 /// Returns the nanosecond of this date-time object.
169 [[nodiscard]] constexpr LIGHTWEIGHT_FORCE_INLINE std::chrono::nanoseconds nanosecond() const noexcept
170 {
171 return std::chrono::nanoseconds(static_cast<unsigned>(sqlValue.fraction));
172 }
173
174 // NOLINTEND(readability-identifier-naming)
175
176 /// Converts this SqlDateTime to its native time_point representation.
177 LIGHTWEIGHT_FORCE_INLINE constexpr operator native_type() const noexcept
178 {
179 return value();
180 }
181
182 /// @brief Constructs only a date from a SQL date-time structure.
183 [[nodiscard]] constexpr LIGHTWEIGHT_FORCE_INLINE SqlDate Date() const noexcept
184 {
185 return SqlDate { year(), month(), day() };
186 }
187
188 /// @brief Constructs only a time from a SQL date-time structure.
189 [[nodiscard]] constexpr LIGHTWEIGHT_FORCE_INLINE SqlTime Time() const noexcept
190 {
191 return SqlTime { std::chrono::hours { hour() },
192 std::chrono::minutes { minute() },
193 std::chrono::seconds { second() },
194 std::chrono::microseconds { std::chrono::duration_cast<std::chrono::microseconds>(nanosecond()) } };
195 }
196
197 /// Converts a native time_point to the underlying SQL timestamp structure.
198 static LIGHTWEIGHT_FORCE_INLINE SQL_TIMESTAMP_STRUCT constexpr ConvertToSqlValue(native_type value) noexcept
199 {
200 using namespace std::chrono;
201 auto const totalDays = floor<days>(value);
202 auto const ymd = year_month_day { totalDays };
203 auto const hms =
204 hh_mm_ss<duration_type> { std::chrono::duration_cast<duration_type>(floor<nanoseconds>(value - totalDays)) };
205 return ConvertToSqlValue(ymd, hms);
206 }
207
208 /// Converts year_month_day and hh_mm_ss components to the underlying SQL timestamp structure.
209 static LIGHTWEIGHT_FORCE_INLINE SQL_TIMESTAMP_STRUCT constexpr ConvertToSqlValue(
210 std::chrono::year_month_day ymd, std::chrono::hh_mm_ss<duration_type> hms) noexcept
211 {
212 // clang-format off
213 // NB: The fraction field is in 100ns units.
214 return SQL_TIMESTAMP_STRUCT {
215 .year = (SQLSMALLINT) (int) ymd.year(),
216 .month = (SQLUSMALLINT) (unsigned) ymd.month(),
217 .day = (SQLUSMALLINT) (unsigned) ymd.day(),
218 .hour = (SQLUSMALLINT) hms.hours().count(),
219 .minute = (SQLUSMALLINT) hms.minutes().count(),
220 .second = (SQLUSMALLINT) hms.seconds().count(),
221 .fraction = (SQLUINTEGER) (((static_cast<unsigned long long>(std::chrono::duration_cast<std::chrono::nanoseconds>(hms.to_duration()).count()) % 1'000'000'000LLU) / 100) * 100)
222 };
223 // clang-format on
224 }
225
226 /// Converts a SQL timestamp structure to the native time_point representation.
227 static LIGHTWEIGHT_FORCE_INLINE native_type constexpr ConvertToNative(SQL_TIMESTAMP_STRUCT const& time) noexcept
228 {
229 // clang-format off
230 using namespace std::chrono;
231 auto const ymd = year_month_day { std::chrono::year { time.year } / std::chrono::month { time.month } / std::chrono::day { time.day } };
232 auto const hms = hh_mm_ss<duration_type> {
233 duration_cast<duration_type>(
234 hours { time.hour }
235 + minutes { time.minute }
236 + seconds { time.second }
237 + nanoseconds { time.fraction }
238 )
239 };
240 return sys_days { ymd } + hms.to_duration();
241 // clang-format on
242 }
243
244 /// Returns the current date and time.
245 [[nodiscard]] constexpr LIGHTWEIGHT_FORCE_INLINE native_type value() const noexcept
246 {
248 }
249
250 /// Adds a duration to this date-time.
251 LIGHTWEIGHT_FORCE_INLINE SqlDateTime& operator+=(duration_type duration) noexcept
252 {
253 *this = SqlDateTime { value() + duration };
254 return *this;
255 }
256
257 /// Subtracts a duration from this date-time.
258 LIGHTWEIGHT_FORCE_INLINE SqlDateTime& operator-=(duration_type duration) noexcept
259 {
260 *this = SqlDateTime { value() - duration };
261 return *this;
262 }
263
264 friend LIGHTWEIGHT_FORCE_INLINE SqlDateTime operator+(SqlDateTime dateTime, duration_type duration) noexcept
265 {
266 return SqlDateTime { dateTime.value() + duration };
267 }
268
269 friend LIGHTWEIGHT_FORCE_INLINE SqlDateTime operator-(SqlDateTime dateTime, duration_type duration) noexcept
270 {
271 return SqlDateTime { dateTime.value() - duration };
272 }
273
274 /// Holds the underlying SQL timestamp structure.
275 SQL_TIMESTAMP_STRUCT sqlValue {};
276};
277
278} // namespace Lightweight
279
280template <>
281struct std::formatter<Lightweight::SqlDateTime>: std::formatter<std::string>
282{
283 LIGHTWEIGHT_FORCE_INLINE auto format(Lightweight::SqlDateTime const& value, std::format_context& ctx) const
284 -> std::format_context::iterator
285 {
286 // This can be used manually to format the date and time inside sql query builder,
287 // that is why we need to use iso standard 8601, also millisecond precision is used for the formatting
288 //
289 // internally fraction is stored in nanoseconds, here we need to get it in milliseconds
290 auto const milliseconds = value.sqlValue.fraction / 1'000'000;
291 return std::formatter<std::string>::format(std::format("{:04}-{:02}-{:02}T{:02}:{:02}:{:02}.{:03}",
292 value.sqlValue.year,
293 value.sqlValue.month,
294 value.sqlValue.day,
295 value.sqlValue.hour,
296 value.sqlValue.minute,
297 value.sqlValue.second,
298 milliseconds),
299 ctx);
300 }
301};
302
303template <>
304struct std::formatter<std::optional<Lightweight::SqlDateTime>>: std::formatter<std::string>
305{
306 LIGHTWEIGHT_FORCE_INLINE auto format(std::optional<Lightweight::SqlDateTime> const& value,
307 std::format_context& ctx) const -> std::format_context::iterator
308 {
309 if (!value.has_value())
310 return std::formatter<std::string>::format("nullopt", ctx);
311 return std::formatter<std::string>::format(std::format("{}", value.value()), ctx);
312 }
313};
314
315namespace Lightweight
316{
317
318template <>
319struct SqlDataBinder<SqlDateTime::native_type>
320{
321 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN GetColumn(SQLHSTMT stmt,
322 SQLUSMALLINT column,
324 SQLLEN* indicator,
325 SqlDataBinderCallback const& /*cb*/) noexcept
326 {
327 SQL_TIMESTAMP_STRUCT sqlValue {};
328 auto const rc = SQLGetData(stmt, column, SQL_C_TYPE_TIMESTAMP, &sqlValue, sizeof(sqlValue), indicator);
329 if (SQL_SUCCEEDED(rc))
330 *result = SqlDateTime::ConvertToNative(sqlValue);
331 return rc;
332 }
333};
334
335namespace detail
336{
337 /// Whether the statement runs on the legacy in-box SQL Server ODBC driver (SQLSRV32.DLL).
338 ///
339 /// That driver predates `datetime2`: it rejects the 27/7 timestamp binding with HY104, and it cannot
340 /// describe a parameter once another one is bound, so date-times bind there as `datetime` (23/3).
341 [[nodiscard]] inline bool IsLegacySqlServerDriver(SqlDataBinderCallback const& cb) noexcept
342 {
343 using namespace std::string_view_literals;
344 return cb.ServerType() == SqlServerType::MICROSOFT_SQL && cb.DriverName() == "SQLSRV32.DLL"sv;
345 }
346
347 /// The layout of the parameter array that is being bound.
348 struct SqlParameterArrayLayout
349 {
350 /// The byte distance from one row's value to the next.
351 std::size_t rowStride {};
352 /// The number of rows.
353 std::size_t rowCount {};
354 };
355
356 /// Reads the layout of the parameter array the statement is bound with.
357 ///
358 /// @param stmt The statement whose parameters are being bound.
359 /// @param valueSize The size of one value, which is the stride of a column-wise array.
360 /// @param columnWiseRowCount The row count of a column-wise (or single-row) binding.
361 /// @return The row size and parameter set size of a row-wise binding, otherwise the column-wise layout.
362 [[nodiscard]] inline SqlParameterArrayLayout CurrentParameterArrayLayout(SQLHSTMT stmt,
363 std::size_t valueSize,
364 std::size_t columnWiseRowCount) noexcept
365 {
366 auto bindType = SQLULEN { SQL_PARAM_BIND_BY_COLUMN };
367 if (!SQL_SUCCEEDED(SQLGetStmtAttr(stmt, SQL_ATTR_PARAM_BIND_TYPE, &bindType, 0, nullptr))
368 || bindType == SQL_PARAM_BIND_BY_COLUMN)
369 return { .rowStride = valueSize, .rowCount = columnWiseRowCount };
370
371 auto parameterSetSize = SQLULEN { 1 };
372 if (!SQL_SUCCEEDED(SQLGetStmtAttr(stmt, SQL_ATTR_PARAMSET_SIZE, &parameterSetSize, 0, nullptr)))
373 parameterSetSize = 1;
374 return { .rowStride = static_cast<std::size_t>(bindType), .rowCount = static_cast<std::size_t>(parameterSetSize) };
375 }
376
377 /// Binds the timestamps at @p first as `datetime` (23/3) for the legacy in-box SQL Server ODBC driver.
378 ///
379 /// The driver rejects fractions finer than the bound scale, so this binds a copy truncated to whole
380 /// milliseconds, laid out like the source and kept alive until the statement has executed.
381 ///
382 /// @param stmt The statement to bind to.
383 /// @param column The 1-based parameter index.
384 /// @param first The first row's timestamp.
385 /// @param layout The stride and row count of the timestamps starting at @p first.
386 /// @param cb The data binder callback that keeps the copy alive.
387 /// @param indicators The NULL indicators, or @c nullptr when no value is NULL.
388 /// @return The ODBC return code of the bind.
389 [[nodiscard]] inline SQLRETURN BindLegacySqlServerDateTimes(SQLHSTMT stmt,
390 SQLUSMALLINT column,
391 SQL_TIMESTAMP_STRUCT const* first,
392 SqlParameterArrayLayout const& layout,
393 SqlDataBinderCallback& cb,
394 SQLLEN* indicators) noexcept
395 {
396 constexpr auto NanosecondsPerMillisecond = SQLUINTEGER { 1'000'000 };
397 auto const rowCount = (std::max) (layout.rowCount, std::size_t { 1 });
398 auto const staged =
399 std::make_shared<std::vector<std::byte>>(((rowCount - 1) * layout.rowStride) + sizeof(SQL_TIMESTAMP_STRUCT));
400 auto const* sourceBytes = reinterpret_cast<std::byte const*>(first);
401 for (auto const row: std::views::iota(std::size_t { 0 }, rowCount))
402 {
403 // Copied bytewise, since the NULL row of an optional holds no value to read through.
404 auto value = SQL_TIMESTAMP_STRUCT {};
405 std::memcpy(&value, sourceBytes + (row * layout.rowStride), sizeof(value));
406 value.fraction -= value.fraction % NanosecondsPerMillisecond;
407 std::memcpy(staged->data() + (row * layout.rowStride), &value, sizeof(value));
408 }
409 cb.PlanPostExecuteCallback([staged]() {});
410
411 return SQLBindParameter(stmt,
412 column,
413 SQL_PARAM_INPUT,
414 SQL_C_TIMESTAMP,
415 SQL_TYPE_TIMESTAMP,
416 23,
417 3,
418 static_cast<SQLPOINTER>(staged->data()),
419 sizeof(SQL_TIMESTAMP_STRUCT),
420 indicators);
421 }
422} // namespace detail
423
424template <>
425struct LIGHTWEIGHT_API SqlDataBinder<SqlDateTime>
426{
427 static constexpr auto ColumnType = SqlColumnTypeDefinitions::DateTime {};
428
429 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN InputParameter(SQLHSTMT stmt,
430 SQLUSMALLINT column,
431 SqlDateTime const& value,
432 SqlDataBinderCallback& cb) noexcept
433 {
434 // A row-wise batch binds row 0 through here, so the layout comes from the statement.
435 if (detail::IsLegacySqlServerDriver(cb))
436 return detail::BindLegacySqlServerDateTimes(
437 stmt, column, &value.sqlValue, detail::CurrentParameterArrayLayout(stmt, sizeof(value), 1), cb, nullptr);
438
439 return SQLBindParameter(stmt,
440 column,
441 SQL_PARAM_INPUT,
442 SQL_C_TIMESTAMP,
443 SQL_TYPE_TIMESTAMP,
444 27,
445 7,
446 (SQLPOINTER) &value.sqlValue,
447 sizeof(value),
448 nullptr);
449 }
450
451 /// Binds an array of timestamps as an input parameter for native (row-wise or column-wise) batch
452 /// execution. @p values points at the first element; the driver strides by the statement's
453 /// SQL_ATTR_PARAM_BIND_TYPE. @p indicators optionally supplies per-row NULL flags.
454 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN BatchInputParameter(SQLHSTMT stmt,
455 SQLUSMALLINT column,
456 SqlDateTime const* values,
457 size_t rowCount,
458 SqlDataBinderCallback& cb,
459 SQLLEN* indicators = nullptr) noexcept
460 {
461 if (detail::IsLegacySqlServerDriver(cb))
462 {
463 auto const layout = detail::SqlParameterArrayLayout {
464 .rowStride = detail::CurrentParameterArrayLayout(stmt, sizeof(*values), rowCount).rowStride,
465 .rowCount = rowCount,
466 };
467 return detail::BindLegacySqlServerDateTimes(stmt, column, &values->sqlValue, layout, cb, indicators);
468 }
469
470 return SQLBindParameter(stmt,
471 column,
472 SQL_PARAM_INPUT,
473 SQL_C_TIMESTAMP,
474 SQL_TYPE_TIMESTAMP,
475 27,
476 7,
477 (SQLPOINTER) &values->sqlValue,
478 sizeof(*values),
479 indicators);
480 }
481
482 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN OutputColumn(
483 SQLHSTMT stmt, SQLUSMALLINT column, SqlDateTime* result, SQLLEN* indicator, SqlDataBinderCallback& /*cb*/) noexcept
484 {
485 // TODO: handle indicator to check for NULL values
486 *indicator = sizeof(result->sqlValue);
487 return SQLBindCol(stmt, column, SQL_C_TYPE_TIMESTAMP, &result->sqlValue, 0, indicator);
488 }
489
490 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN GetColumn(SQLHSTMT stmt,
491 SQLUSMALLINT column,
492 SqlDateTime* result,
493 SQLLEN* indicator,
494 SqlDataBinderCallback const& /*cb*/) noexcept
495 {
496 return SQLGetData(stmt, column, SQL_C_TYPE_TIMESTAMP, &result->sqlValue, sizeof(result->sqlValue), indicator);
497 }
498
499 static LIGHTWEIGHT_FORCE_INLINE std::string Inspect(SqlDateTime const& value) noexcept
500 {
501 return std::format("{}", value);
502 }
503};
504
505template <>
506inline constexpr bool SqlIsNativeRowBindableValue<SqlDateTime> = true;
507
508} // namespace Lightweight
constexpr LIGHTWEIGHT_FORCE_INLINE std::chrono::year year() const noexcept
Returns the year of this date-time object.
constexpr LIGHTWEIGHT_FORCE_INLINE std::chrono::day day() const noexcept
Returns the day of this date-time object.
static LIGHTWEIGHT_FORCE_INLINE SQL_TIMESTAMP_STRUCT constexpr ConvertToSqlValue(std::chrono::year_month_day ymd, std::chrono::hh_mm_ss< duration_type > hms) noexcept
Converts year_month_day and hh_mm_ss components to the underlying SQL timestamp structure.
static LIGHTWEIGHT_FORCE_INLINE SqlDateTime Now() noexcept
Returns the current date and time.
constexpr bool operator==(SqlDateTime const &other) const noexcept
Equality comparison operator.
LIGHTWEIGHT_FORCE_INLINE constexpr SqlDateTime(std::chrono::system_clock::time_point value) noexcept
Constructs a date and time from a time point.
constexpr LIGHTWEIGHT_FORCE_INLINE SqlDate Date() const noexcept
Constructs only a date from a SQL date-time structure.
LIGHTWEIGHT_FORCE_INLINE constexpr SqlDateTime(std::chrono::year year, std::chrono::month month, std::chrono::day day, std::chrono::hours hour, std::chrono::minutes minute, std::chrono::seconds second, std::chrono::nanoseconds nanosecond=std::chrono::nanoseconds(0)) noexcept
Constructs a date and time from individual components.
std::chrono::system_clock::time_point native_type
The native C++ type representing a date-time value.
constexpr LIGHTWEIGHT_FORCE_INLINE std::chrono::month month() const noexcept
Returns the month of this date-time object.
SQL_TIMESTAMP_STRUCT sqlValue
Holds the underlying SQL timestamp structure.
constexpr LIGHTWEIGHT_FORCE_INLINE std::chrono::seconds second() const noexcept
Returns the second of this date-time object.
constexpr LIGHTWEIGHT_FORCE_INLINE std::chrono::hours hour() const noexcept
Returns the hour of this date-time object.
std::chrono::system_clock::duration duration_type
The duration type used for arithmetic operations.
constexpr LIGHTWEIGHT_FORCE_INLINE std::chrono::minutes minute() const noexcept
Returns the minute of this date-time object.
LIGHTWEIGHT_FORCE_INLINE SqlDateTime & operator-=(duration_type duration) noexcept
Subtracts a duration from this date-time.
constexpr LIGHTWEIGHT_FORCE_INLINE std::chrono::nanoseconds nanosecond() const noexcept
Returns the nanosecond of this date-time object.
constexpr SqlDateTime() noexcept=default
Default constructor.
LIGHTWEIGHT_FORCE_INLINE constexpr SqlDateTime(std::chrono::year_month_day ymd, std::chrono::hh_mm_ss< duration_type > time) noexcept
Constructs a date and time from individual components.
static LIGHTWEIGHT_FORCE_INLINE SqlDateTime NowUTC() noexcept
Return the current date and time in UTC.
constexpr LIGHTWEIGHT_FORCE_INLINE SqlTime Time() const noexcept
Constructs only a time from a SQL date-time structure.
static LIGHTWEIGHT_FORCE_INLINE SQL_TIMESTAMP_STRUCT constexpr ConvertToSqlValue(native_type value) noexcept
Converts a native time_point to the underlying SQL timestamp structure.
LIGHTWEIGHT_FORCE_INLINE SqlDateTime & operator+=(duration_type duration) noexcept
Adds a duration to this date-time.
constexpr LIGHTWEIGHT_FORCE_INLINE native_type value() const noexcept
Returns the current date and time.
constexpr bool operator!=(SqlDateTime const &other) const noexcept
Inequality comparison operator.
static LIGHTWEIGHT_FORCE_INLINE native_type constexpr ConvertToNative(SQL_TIMESTAMP_STRUCT const &time) noexcept
Converts a SQL timestamp structure to the native time_point representation.