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:
Niels Lohmann authored and GitHub committed 2026-10-25 12:07:32 +01:00
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
+5 -3
View File
@@ -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.
+1 -1
View File
@@ -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