[/
    Copyright (c) 2019-2024 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
   
    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
]

[section:time_types Time types: date, datetime and time]
[nochunk]

The [reflink date], [reflink datetime] and [reflink time] provide
support for MySQL's native date and time types. This section expands
on how to use them.

[heading The date type]

[reflink date] represents MySQL __DATE__ in C++. `date` holds the year, month and day components of a date,
without any time zone information.
It is a type close to the protocol, rather than a vocabulary type. The main reason for using `date` instead
of a `std::chrono::time_point` type is that, under certain configurations, MySQL allows storing invalid
dates, such as `2020-00-01`. These are not representable as a `std::chrono::time_point`.
Unless dealing with these special values, we recommend converting `date`s to a `time_point` before using them.

Since `date` represents a local time point, `std::chrono::local_time` is the most accurate representation for it.
If your compiler supports C++20 calendar types (as per `__cpp_lib_chrono >= 201907L`), you can use
[refmem date as_local_time_point] to perform the cast:

[time_types_date_as_local_time_point]

If the date is not valid, `as_time_point` will throw an exception.

You can query whether a `date` contains a valid date or not using [refmem date valid]:

[time_types_date_valid]

You can combine it with [refmem date get_local_time_point], which performs an unchecked
conversion:

[time_types_date_get_local_time_point]

[note
  Using `std::chrono` time zone functionality under MSVC can cause your tooling to report
  memory leaks. This is [@https://github.com/microsoft/STL/issues/2047 an issue in MSVC's standard library].
  See [@https://github.com/microsoft/STL/issues/2504 this suggestion] for a possible workaround.
]

If your compiler doesn't support local times, you can use [refmem date get_time_point]
or [refmem date as_time_point], instead. These return [refmem date time_point] objects,
which are `time_points` that use the system clock. These time points should be interpreted
as local times, rather than UTC:

[time_types_date_as_time_point]





[heading The datetime type]

[reflink datetime] represents MySQL __DATETIME__ and __TIMESTAMP__ in C++. `datetime` represents a broken time point,
having year, month, day, hour, minute, second and microsecond.

The `datetime` object doesn't carry any time zone information with it. The time zone semantics
depend on the actual MySQL type:

* __DATETIME__ is a "naive" time point object. It represents a time point without any time zone
  information at all. It is up to the user to interpret which time zone the object is in.
* When a __TIMESTAMP__ object is inserted, it is interpreted  to be in the connection's local time zone,
  as given by the __time_zone__ variable, and converted to UTC for storage. When retrieved, it is converted back
  to the time zone indicated by __time_zone__. The retrieved value of a `TIMESTAMP`
  field is thus a time point in some local time zone, dictated by the current
  __time_zone__ variable. As this variable can be changed programmatically from SQL, without
  the library knowing it, we represent `TIMESTAMP`'s using the `datetime` object, which doesn't include time zone information.

MySQL also accepts invalid datetimes (like `2020-00-10 10:20:59.000000`).

As with `date`, you can use [refmem datetime as_local_time_point], [refmemunq datetime get_local_time_point]
and [refmemunq datetime valid] (or [refmemunq datetime as_time_point] and [refmemunq datetime get_time_point],
if your compiler doesn't support C++20 calendar types):

[time_types_datetime]



[heading TIMESTAMP considerations]

When using `TIMESTAMP`, we recommend setting the __time_zone__ session variable to a known value. To illustrate this,
consider an event-logging system with the following table definition:

[time_types_timestamp_setup]

We will be inserting events with an explicit timestamp. We may also want to retrieve events with
a timestamp filter. This is what our prepared statements would look like:

[time_types_timestamp_stmts]

These statements may be run from different parts of our code, or even from different applications.
To get consistent results, we must make sure that the time zones used during insertion and retrieval are the same.
By default, __time_zone__ gets set to `SYSTEM`, which will use the server's time zone settings.
This is not what we want here, so let's change it:

[time_types_timestamp_set_time_zone]

With this, the insertion code can look like:

[time_types_timestamp_insert]

The querying code would be:

[time_types_timestamp_select]
    
If you don't set __time_zone__, you may apparently get the right results if you run
both insertions and queries from clients that don't set `time_zone` and the server doesn't
change its configuration. However, relying on this will make your applications brittle, so we
don't recommend it.


[heading The TIME type]

The __TIME__ type is a signed duration with a resolution of one microsecond.
It is represented using the [reflink time] type, an alias for a
`std::chrono::duration` specialization with microseconds as period.


[endsect]
