docs: write std::chrono durations as unit/value objects; reword a title with escaped quotes (#5911)
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
1 parent
ffd4242dc2
commit
fe231dc692
4 files changed
+55
-9
No files matched your search
@@ -1,9 +1,38 @@
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
// the name of a period; extend the list for the periods you use
|
||||
template <typename Period> const char* unit_name();
|
||||
template <> const char* unit_name<std::nano>()
|
||||
{
|
||||
return "ns";
|
||||
}
|
||||
template <> const char* unit_name<std::micro>()
|
||||
{
|
||||
return "us";
|
||||
}
|
||||
template <> const char* unit_name<std::milli>()
|
||||
{
|
||||
return "ms";
|
||||
}
|
||||
template <> const char* unit_name<std::ratio<1>>()
|
||||
{
|
||||
return "s";
|
||||
}
|
||||
template <> const char* unit_name<std::ratio<60>>()
|
||||
{
|
||||
return "min";
|
||||
}
|
||||
template <> const char* unit_name<std::ratio<3600>>()
|
||||
{
|
||||
return "h";
|
||||
}
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
template <typename Rep, typename Period>
|
||||
@@ -11,12 +40,16 @@ struct adl_serializer<std::chrono::duration<Rep, Period>>
|
||||
{
|
||||
static void to_json(json& j, const std::chrono::duration<Rep, Period>& d)
|
||||
{
|
||||
j = d.count();
|
||||
j = {{"unit", unit_name<Period>()}, {"value", d.count()}};
|
||||
}
|
||||
|
||||
static void from_json(const json& j, std::chrono::duration<Rep, Period>& d)
|
||||
{
|
||||
d = std::chrono::duration<Rep, Period>(j.get<Rep>());
|
||||
if (j.at("unit").get<std::string>() != unit_name<Period>())
|
||||
{
|
||||
throw std::invalid_argument("unexpected unit " + j.at("unit").dump());
|
||||
}
|
||||
d = std::chrono::duration<Rep, Period>(j.at("value").get<Rep>());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -41,11 +74,21 @@ int main()
|
||||
|
||||
std::cout << std::boolalpha;
|
||||
|
||||
// the unit is not part of the JSON value
|
||||
// the unit is part of the JSON value
|
||||
const json timeout = milliseconds(1500);
|
||||
std::cout << "duration: " << timeout << '\n';
|
||||
std::cout << "as milliseconds: " << timeout.get<milliseconds>().count() << '\n';
|
||||
|
||||
// reading with a different unit is rejected
|
||||
try
|
||||
{
|
||||
timeout.get<seconds>();
|
||||
}
|
||||
catch (const std::invalid_argument& e)
|
||||
{
|
||||
std::cout << "error: " << e.what() << '\n';
|
||||
}
|
||||
|
||||
// a system_clock time point is the time since the Unix epoch
|
||||
const time_point<system_clock, milliseconds> t(milliseconds(1700000000123));
|
||||
const json stamp = t;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
duration: 1500
|
||||
duration: {"unit":"ms","value":1500}
|
||||
as milliseconds: 1500
|
||||
time point: 1700000000123
|
||||
error: unexpected unit "ms"
|
||||
time point: {"unit":"ms","value":1700000000123}
|
||||
round trip: true
|
||||
@@ -92,8 +92,10 @@ to choose the alternative.
|
||||
|
||||
## `std::chrono`
|
||||
|
||||
A duration is written as its count and read back with the same representation and period. The **unit is not part of
|
||||
the JSON value**, so document it, for example in the member name (`timeout_ms`):
|
||||
A duration is written as an object with the keys `unit` and `value`, for example `{"unit": "ms", "value": 1500}`, so
|
||||
the JSON value is self-describing. The serializer names the unit of the period (`ns`, `us`, `ms`, `s`, `min`, `h`;
|
||||
extend the list for other periods), and the deserializer rejects a value whose unit differs from the requested
|
||||
duration type instead of silently misreading it:
|
||||
|
||||
??? example "Example: serialize durations and system_clock time points"
|
||||
|
||||
@@ -107,7 +109,7 @@ the JSON value**, so document it, for example in the member name (`timeout_ms`):
|
||||
--8<-- "examples/type_recipes_chrono.output"
|
||||
```
|
||||
|
||||
A `system_clock::time_point` with millisecond precision is written as the number of milliseconds since the Unix epoch.
|
||||
A `system_clock::time_point` with millisecond precision is written as the duration since the Unix epoch, that is, as an object with `unit` and `value`.
|
||||
The time point serializer is limited to `system_clock`,
|
||||
because the epoch of other clocks (for example `steady_clock`) has no meaning outside the running program.
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@ This error indicates a syntax error while deserializing a JSON text. The error m
|
||||
- Make sure the input is correctly read. Try to write the input to standard output to check if, for instance, the input file was successfully opened.
|
||||
- Paste the input to a JSON validator like <https://jsonlint.com> or a tool like [jq](https://jqlang.github.io/jq/).
|
||||
|
||||
??? info "Parsing a file fails at line 1, column 1 (or \"unexpected end of input\")"
|
||||
??? info "Parsing a file fails at line 1, column 1 (unexpected end of input)"
|
||||
|
||||
The messages `attempting to parse an empty input` (since version 3.11.3) and `unexpected end of input` (also the message of
|
||||
earlier versions for an empty input) at the very start of the input mean
|
||||
|
||||
Reference in new issue
Block a user