5#include "../SqlColumnTypeDefinitions.hpp"
41 return SqlDateTime { std::chrono::system_clock::now() };
44#if !defined(LIGHTWEIGHT_CXX26_REFLECTION)
54 return SqlDateTime { std::chrono::system_clock::now() };
71 constexpr std::weak_ordering operator<=>(
SqlDateTime const& other) const noexcept
78 return (*this <=> other) == std::weak_ordering::equivalent;
84 return !(*
this == other);
88 LIGHTWEIGHT_FORCE_INLINE
constexpr SqlDateTime(std::chrono::year_month_day ymd,
89 std::chrono::hh_mm_ss<duration_type> time)
noexcept:
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(),
98 (SQLUINTEGER) (std::chrono::duration_cast<std::chrono::nanoseconds>(time.to_duration()).count() / 100) * 100,
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:
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,
125 LIGHTWEIGHT_FORCE_INLINE
constexpr SqlDateTime(std::chrono::system_clock::time_point
value)
noexcept:
133 [[nodiscard]]
constexpr LIGHTWEIGHT_FORCE_INLINE std::chrono::year
year() const noexcept
135 return std::chrono::year(
static_cast<int>(
sqlValue.year));
139 [[nodiscard]]
constexpr LIGHTWEIGHT_FORCE_INLINE std::chrono::month
month() const noexcept
141 return std::chrono::month(
static_cast<unsigned>(
sqlValue.month));
145 [[nodiscard]]
constexpr LIGHTWEIGHT_FORCE_INLINE std::chrono::day
day() const noexcept
147 return std::chrono::day(
static_cast<unsigned>(
sqlValue.day));
151 [[nodiscard]]
constexpr LIGHTWEIGHT_FORCE_INLINE std::chrono::hours
hour() const noexcept
153 return std::chrono::hours(
static_cast<unsigned>(
sqlValue.hour));
157 [[nodiscard]]
constexpr LIGHTWEIGHT_FORCE_INLINE std::chrono::minutes
minute() const noexcept
159 return std::chrono::minutes(
static_cast<unsigned>(
sqlValue.minute));
163 [[nodiscard]]
constexpr LIGHTWEIGHT_FORCE_INLINE std::chrono::seconds
second() const noexcept
165 return std::chrono::seconds(
static_cast<unsigned>(
sqlValue.second));
169 [[nodiscard]]
constexpr LIGHTWEIGHT_FORCE_INLINE std::chrono::nanoseconds
nanosecond() const noexcept
171 return std::chrono::nanoseconds(
static_cast<unsigned>(
sqlValue.fraction));
177 LIGHTWEIGHT_FORCE_INLINE
constexpr operator native_type() const noexcept
183 [[nodiscard]]
constexpr LIGHTWEIGHT_FORCE_INLINE
SqlDate Date() const noexcept
189 [[nodiscard]]
constexpr LIGHTWEIGHT_FORCE_INLINE
SqlTime Time() const noexcept
192 std::chrono::minutes {
minute() },
193 std::chrono::seconds {
second() },
194 std::chrono::microseconds { std::chrono::duration_cast<std::chrono::microseconds>(
nanosecond()) } };
200 using namespace std::chrono;
201 auto const totalDays = floor<days>(
value);
202 auto const ymd = year_month_day { totalDays };
204 hh_mm_ss<duration_type> { std::chrono::duration_cast<duration_type>(floor<nanoseconds>(
value - totalDays)) };
210 std::chrono::year_month_day ymd, std::chrono::hh_mm_ss<duration_type> hms)
noexcept
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)
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>(
235 + minutes { time.minute }
236 + seconds { time.second }
237 + nanoseconds { time.fraction }
240 return sys_days { ymd } + hms.to_duration();
271 return SqlDateTime { dateTime.value() - duration };
281struct std::formatter<Lightweight::SqlDateTime>: std::formatter<std::string>
284 -> std::format_context::iterator
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}",
293 value.sqlValue.month,
296 value.sqlValue.minute,
297 value.sqlValue.second,
304struct std::formatter<std::optional<Lightweight::SqlDateTime>>: std::formatter<std::string>
306 LIGHTWEIGHT_FORCE_INLINE
auto format(std::optional<Lightweight::SqlDateTime>
const& value,
307 std::format_context& ctx)
const -> std::format_context::iterator
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);
319struct SqlDataBinder<SqlDateTime::native_type>
321 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN GetColumn(SQLHSTMT stmt,
325 SqlDataBinderCallback
const& )
noexcept
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))
341 [[nodiscard]]
inline bool IsLegacySqlServerDriver(SqlDataBinderCallback
const& cb)
noexcept
343 using namespace std::string_view_literals;
344 return cb.ServerType() == SqlServerType::MICROSOFT_SQL && cb.DriverName() ==
"SQLSRV32.DLL"sv;
348 struct SqlParameterArrayLayout
351 std::size_t rowStride {};
353 std::size_t rowCount {};
362 [[nodiscard]]
inline SqlParameterArrayLayout CurrentParameterArrayLayout(SQLHSTMT stmt,
363 std::size_t valueSize,
364 std::size_t columnWiseRowCount)
noexcept
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 };
371 auto parameterSetSize = SQLULEN { 1 };
372 if (!SQL_SUCCEEDED(SQLGetStmtAttr(stmt, SQL_ATTR_PARAMSET_SIZE, ¶meterSetSize, 0,
nullptr)))
373 parameterSetSize = 1;
374 return { .rowStride =
static_cast<std::size_t
>(bindType), .rowCount =
static_cast<std::size_t
>(parameterSetSize) };
389 [[nodiscard]]
inline SQLRETURN BindLegacySqlServerDateTimes(SQLHSTMT stmt,
391 SQL_TIMESTAMP_STRUCT
const* first,
392 SqlParameterArrayLayout
const& layout,
393 SqlDataBinderCallback& cb,
394 SQLLEN* indicators)
noexcept
396 constexpr auto NanosecondsPerMillisecond = SQLUINTEGER { 1'000'000 };
397 auto const rowCount = (std::max) (layout.rowCount, std::size_t { 1 });
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))
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));
409 cb.PlanPostExecuteCallback([staged]() {});
411 return SQLBindParameter(stmt,
418 static_cast<SQLPOINTER
>(staged->data()),
419 sizeof(SQL_TIMESTAMP_STRUCT),
425struct LIGHTWEIGHT_API SqlDataBinder<SqlDateTime>
427 static constexpr auto ColumnType = SqlColumnTypeDefinitions::DateTime {};
429 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN InputParameter(SQLHSTMT stmt,
431 SqlDateTime
const& value,
432 SqlDataBinderCallback& cb)
noexcept
435 if (detail::IsLegacySqlServerDriver(cb))
436 return detail::BindLegacySqlServerDateTimes(
437 stmt, column, &value.sqlValue, detail::CurrentParameterArrayLayout(stmt,
sizeof(value), 1), cb,
nullptr);
439 return SQLBindParameter(stmt,
446 (SQLPOINTER) &value.sqlValue,
454 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN BatchInputParameter(SQLHSTMT stmt,
456 SqlDateTime
const* values,
458 SqlDataBinderCallback& cb,
459 SQLLEN* indicators =
nullptr) noexcept
461 if (detail::IsLegacySqlServerDriver(cb))
463 auto const layout = detail::SqlParameterArrayLayout {
464 .rowStride = detail::CurrentParameterArrayLayout(stmt,
sizeof(*values), rowCount).rowStride,
465 .rowCount = rowCount,
467 return detail::BindLegacySqlServerDateTimes(stmt, column, &values->sqlValue, layout, cb, indicators);
470 return SQLBindParameter(stmt,
477 (SQLPOINTER) &values->sqlValue,
482 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN OutputColumn(
483 SQLHSTMT stmt, SQLUSMALLINT column, SqlDateTime* result, SQLLEN* indicator, SqlDataBinderCallback& )
noexcept
486 *indicator =
sizeof(result->sqlValue);
487 return SQLBindCol(stmt, column, SQL_C_TYPE_TIMESTAMP, &result->sqlValue, 0, indicator);
490 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN GetColumn(SQLHSTMT stmt,
494 SqlDataBinderCallback
const& )
noexcept
496 return SQLGetData(stmt, column, SQL_C_TYPE_TIMESTAMP, &result->sqlValue,
sizeof(result->sqlValue), indicator);
499 static LIGHTWEIGHT_FORCE_INLINE std::string Inspect(SqlDateTime
const& value)
noexcept
501 return std::format(
"{}", value);
506inline constexpr bool SqlIsNativeRowBindableValue<SqlDateTime> =
true;
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.