Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
769b74ad
Commit
769b74ad
authored
Jun 09, 2023
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Integrate review feedback
parent
e576f54e
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
75 additions
and
53 deletions
+75
-53
CHANGELOG.md
CHANGELOG.md
+5
-5
libcaf_core/caf/chrono.hpp
libcaf_core/caf/chrono.hpp
+17
-10
libcaf_core/caf/detail/parse.hpp
libcaf_core/caf/detail/parse.hpp
+1
-1
libcaf_core/src/chrono.cpp
libcaf_core/src/chrono.cpp
+14
-12
libcaf_core/test/chrono.cpp
libcaf_core/test/chrono.cpp
+38
-25
No files found.
CHANGELOG.md
View file @
769b74ad
...
...
@@ -24,11 +24,11 @@ is based on [Keep a Changelog](https://keepachangelog.com).
### Added
-
We have added new utilities in
`caf::chrono`
for making it easier to handle
ISO 8601 timestamps. The new function
`std::chrono::to_string`
converts system
time to an ISO timestamp. For reading an ISO timestamp, CAF now provides the
class
`caf::chrono::datetime`
. It can parse ISO-formatted strings via
`parse`
(or
`datetime::from_string`
) and convert them to a local representation via
-
Add new utilities in
`caf::chrono`
for making it easier to handle ISO 8601
timestamps. The new function
`std::chrono::to_string`
converts system time to
an ISO timestamp. For reading an ISO timestamp, CAF now provides the class
`caf::chrono::datetime`
. It can parse ISO-formatted strings via
`parse`
(or
`datetime::from_string`
) and convert them to a local representation via
`to_local_time`
. Please refer to the class documentation for more details.
## [0.19.1] - 2023-05-01
...
...
libcaf_core/caf/chrono.hpp
View file @
769b74ad
...
...
@@ -109,24 +109,16 @@ public:
/// Returns whether this object is equal to `other`.
bool
equals
(
const
datetime
&
other
)
const
noexcept
;
/// Parses a date and time string in ISO 8601 format.
/// @param str The string to parse.
/// @returns The parsed date and time.
error
parse
(
std
::
string_view
str
);
/// Convenience function for converting a string to a `datetime` object.
static
expected
<
datetime
>
from_string
(
std
::
string_view
str
);
/// Parses a date and time string in ISO 8601 format.
/// @param ps The parser state to use.
void
parse
(
string_parser_state
&
ps
);
/// Overrides the current date and time with the values from `x`.
void
value
(
const
datetime
&
x
)
noexcept
{
*
this
=
x
;
}
/// Converts this object to a time_point object with given Duration type.
/// @pre `valid()` returns `true`.
template
<
class
Duration
=
std
::
chrono
::
system_clock
::
duration
>
auto
to_local_time
()
const
noexcept
{
// TODO: consider using year_month_day once we have C++20.
...
...
@@ -143,6 +135,8 @@ private:
time_t
to_time_t
()
const
noexcept
;
};
// -- free functions -----------------------------------------------------------
/// @relates datetime
inline
bool
operator
==
(
const
datetime
&
x
,
const
datetime
&
y
)
noexcept
{
return
x
.
equals
(
y
);
...
...
@@ -153,7 +147,20 @@ inline bool operator!=(const datetime& x, const datetime& y) noexcept {
return
!
(
x
==
y
);
}
/// Parses a date and time string in ISO 8601 format.
/// @param str The string to parse.
/// @param dest The output parameter for the parsed date and time.
/// @returns An error code if parsing failed.
/// @relates datetime
CAF_CORE_EXPORT
error
parse
(
std
::
string_view
str
,
datetime
&
dest
);
/// Parses a date and time string in ISO 8601 format.
/// @param ps The parser state to use.
/// @param dest The output parameter for the parsed date and time.
/// @relates datetime
CAF_CORE_EXPORT
void
parse
(
string_parser_state
&
ps
,
datetime
&
dest
);
/// @relates datetime
std
::
string
to_string
(
const
datetime
&
x
);
CAF_CORE_EXPORT
std
::
string
to_string
(
const
datetime
&
x
);
}
// namespace caf::chrono
libcaf_core/caf/detail/parse.hpp
View file @
769b74ad
...
...
@@ -188,7 +188,7 @@ template <class Duration>
void
parse
(
string_parser_state
&
ps
,
std
::
chrono
::
time_point
<
std
::
chrono
::
system_clock
,
Duration
>&
x
)
{
chrono
::
datetime
dt
;
dt
.
parse
(
ps
);
parse
(
ps
,
dt
);
if
(
ps
.
code
!=
pec
::
success
)
return
;
x
=
dt
.
to_local_time
<
Duration
>
();
...
...
libcaf_core/src/chrono.cpp
View file @
769b74ad
...
...
@@ -85,7 +85,7 @@ char* print_localtime_fraction(char* pos, int val) noexcept {
char
*
print_localtime_impl
(
char
*
buf
,
size_t
buf_size
,
time_t
ts
,
int
ns
)
noexcept
{
// Max size of a timestamp is
29
bytes: "2019-12-31T23:59:59.111222333+01:00".
// Max size of a timestamp is
35
bytes: "2019-12-31T23:59:59.111222333+01:00".
// We need at least 36 bytes to store the timestamp and the null terminator.
CAF_ASSERT
(
buf_size
>=
36
);
// Read the time into a tm struct and print year plus time using strftime.
...
...
@@ -210,23 +210,25 @@ time_t datetime::to_time_t() const noexcept {
return
tm_to_time_t
(
time_buf
)
-
utc_offset
.
value_or
(
0
);
}
error
datetime
::
parse
(
std
::
string_view
str
)
{
string_parser_state
ps
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_timestamp
(
ps
,
*
this
);
return
ps
.
code
;
}
void
datetime
::
parse
(
string_parser_state
&
ps
)
{
detail
::
parser
::
read_timestamp
(
ps
,
*
this
);
}
expected
<
datetime
>
datetime
::
from_string
(
std
::
string_view
str
)
{
datetime
tmp
;
if
(
auto
err
=
tmp
.
parse
(
str
))
if
(
auto
err
=
parse
(
str
,
tmp
))
return
err
;
return
tmp
;
}
// -- free functions -----------------------------------------------------------
error
parse
(
std
::
string_view
str
,
datetime
&
dest
)
{
string_parser_state
ps
{
str
.
begin
(),
str
.
end
()};
detail
::
parser
::
read_timestamp
(
ps
,
dest
);
return
ps
.
code
;
}
void
parse
(
string_parser_state
&
ps
,
datetime
&
dest
)
{
detail
::
parser
::
read_timestamp
(
ps
,
dest
);
}
std
::
string
to_string
(
const
datetime
&
x
)
{
std
::
string
result
;
result
.
reserve
(
32
);
...
...
libcaf_core/test/chrono.cpp
View file @
769b74ad
...
...
@@ -17,12 +17,12 @@ TEST_CASE("a default constructed date and time is invalid") {
CHECK
(
!
x
.
valid
());
}
SCENARIO
(
"a date and time can be parsed from
a string
"
)
{
SCENARIO
(
"a date and time can be parsed from
strings
"
)
{
GIVEN
(
"a valid date and time string with no UTC time zone information"
)
{
WHEN
(
"parsing the string"
)
{
THEN
(
"the date and time is valid and has an UTC offset is nullopt"
)
{
datetime
x
;
CHECK_EQ
(
x
.
parse
(
"2021-02-03T14:25:36"
),
none
);
CHECK_EQ
(
parse
(
"2021-02-03T14:25:36"
,
x
),
none
);
CHECK
(
x
.
valid
());
CHECK_EQ
(
x
.
year
,
2021
);
CHECK_EQ
(
x
.
month
,
2
);
...
...
@@ -39,7 +39,7 @@ SCENARIO("a date and time can be parsed from a string") {
WHEN
(
"parsing the string"
)
{
THEN
(
"the date and time is valid and has an UTC offset of 0"
)
{
datetime
x
;
CHECK_EQ
(
x
.
parse
(
"2021-02-03T14:25:36Z"
),
none
);
CHECK_EQ
(
parse
(
"2021-02-03T14:25:36Z"
,
x
),
none
);
CHECK
(
x
.
valid
());
CHECK_EQ
(
x
.
year
,
2021
);
CHECK_EQ
(
x
.
month
,
2
);
...
...
@@ -56,7 +56,7 @@ SCENARIO("a date and time can be parsed from a string") {
WHEN
(
"parsing the string"
)
{
THEN
(
"the date and time is valid and has the specified UTC offset"
)
{
datetime
x
;
CHECK_EQ
(
x
.
parse
(
"2021-02-03T14:25:36+02:00"
),
none
);
CHECK_EQ
(
parse
(
"2021-02-03T14:25:36+02:00"
,
x
),
none
);
CHECK
(
x
.
valid
());
CHECK_EQ
(
x
.
year
,
2021
);
CHECK_EQ
(
x
.
month
,
2
);
...
...
@@ -73,7 +73,7 @@ SCENARIO("a date and time can be parsed from a string") {
WHEN
(
"parsing the string"
)
{
THEN
(
"the date and time is valid and has the specified UTC offset"
)
{
datetime
x
;
CHECK_EQ
(
x
.
parse
(
"2021-02-03T14:25:36-01:30"
),
none
);
CHECK_EQ
(
parse
(
"2021-02-03T14:25:36-01:30"
,
x
),
none
);
CHECK
(
x
.
valid
());
CHECK_EQ
(
x
.
year
,
2021
);
CHECK_EQ
(
x
.
month
,
2
);
...
...
@@ -88,13 +88,12 @@ SCENARIO("a date and time can be parsed from a string") {
}
}
// Same as above, but with milliseconds.
SCENARIO
(
"a date and time with milliseconds can be parsed from a string"
)
{
SCENARIO
(
"a date and time with fractional seconds can be parsed from strings"
)
{
GIVEN
(
"a valid date and time string with no UTC time zone information"
)
{
WHEN
(
"parsing the string"
)
{
THEN
(
"the date and time is valid and has an UTC offset is nullopt"
)
{
datetime
x
;
CHECK_EQ
(
x
.
parse
(
"2021-02-03T14:25:36.000"
),
none
);
CHECK_EQ
(
parse
(
"2021-02-03T14:25:36.000"
,
x
),
none
);
CHECK
(
x
.
valid
());
CHECK_EQ
(
x
.
year
,
2021
);
CHECK_EQ
(
x
.
month
,
2
);
...
...
@@ -111,7 +110,7 @@ SCENARIO("a date and time with milliseconds can be parsed from a string") {
WHEN
(
"parsing the string"
)
{
THEN
(
"the date and time is valid and has an UTC offset of 0"
)
{
datetime
x
;
CHECK_EQ
(
x
.
parse
(
"2021-02-03T14:25:36.012Z"
),
none
);
CHECK_EQ
(
parse
(
"2021-02-03T14:25:36.012Z"
,
x
),
none
);
CHECK
(
x
.
valid
());
CHECK_EQ
(
x
.
year
,
2021
);
CHECK_EQ
(
x
.
month
,
2
);
...
...
@@ -128,7 +127,7 @@ SCENARIO("a date and time with milliseconds can be parsed from a string") {
WHEN
(
"parsing the string"
)
{
THEN
(
"the date and time is valid and has the specified UTC offset"
)
{
datetime
x
;
CHECK_EQ
(
x
.
parse
(
"2021-02-03T14:25:36.123+02:00"
),
none
);
CHECK_EQ
(
parse
(
"2021-02-03T14:25:36.123+02:00"
,
x
),
none
);
CHECK
(
x
.
valid
());
CHECK_EQ
(
x
.
year
,
2021
);
CHECK_EQ
(
x
.
month
,
2
);
...
...
@@ -145,7 +144,7 @@ SCENARIO("a date and time with milliseconds can be parsed from a string") {
WHEN
(
"parsing the string"
)
{
THEN
(
"the date and time is valid and has the specified UTC offset"
)
{
datetime
x
;
CHECK_EQ
(
x
.
parse
(
"2021-02-03T14:25:36.999-01:30"
),
none
);
CHECK_EQ
(
parse
(
"2021-02-03T14:25:36.999-01:30"
,
x
),
none
);
CHECK
(
x
.
valid
());
CHECK_EQ
(
x
.
year
,
2021
);
CHECK_EQ
(
x
.
month
,
2
);
...
...
@@ -163,14 +162,14 @@ SCENARIO("a date and time with milliseconds can be parsed from a string") {
TEST_CASE
(
"the parser refuses invalid date time values"
)
{
datetime
x
;
auto
invalid
=
make_error
(
pec
::
invalid_argument
);
CHECK_EQ
(
x
.
parse
(
"2021-02-29T01:00:00"
),
invalid
);
// Not a leap year.
CHECK_EQ
(
x
.
parse
(
"2021-00-10T01:00:00"
),
invalid
);
// Month < 1.
CHECK_EQ
(
x
.
parse
(
"2021-13-10T01:00:00"
),
invalid
);
// Month > 12.
CHECK_EQ
(
x
.
parse
(
"2021-01-00T01:00:00"
),
invalid
);
// Day < 1.
CHECK_EQ
(
x
.
parse
(
"2021-01-32T01:00:00"
),
invalid
);
// Day > 31.
CHECK_EQ
(
x
.
parse
(
"2021-01-01T24:00:00"
),
invalid
);
// Hour > 23.
CHECK_EQ
(
x
.
parse
(
"2021-01-01T00:60:00"
),
invalid
);
// Minute > 56
.
CHECK_EQ
(
x
.
parse
(
"2021-01-01T00:00:60"
),
invalid
);
// Second > 56
.
CHECK_EQ
(
parse
(
"2021-02-29T01:00:00"
,
x
),
invalid
);
// Not a leap year.
CHECK_EQ
(
parse
(
"2021-00-10T01:00:00"
,
x
),
invalid
);
// Month < 1.
CHECK_EQ
(
parse
(
"2021-13-10T01:00:00"
,
x
),
invalid
);
// Month > 12.
CHECK_EQ
(
parse
(
"2021-01-00T01:00:00"
,
x
),
invalid
);
// Day < 1.
CHECK_EQ
(
parse
(
"2021-01-32T01:00:00"
,
x
),
invalid
);
// Day > 31.
CHECK_EQ
(
parse
(
"2021-01-01T24:00:00"
,
x
),
invalid
);
// Hour > 23.
CHECK_EQ
(
parse
(
"2021-01-01T00:60:00"
,
x
),
invalid
);
// Minute > 59
.
CHECK_EQ
(
parse
(
"2021-01-01T00:00:60"
,
x
),
invalid
);
// Second > 59
.
}
SCENARIO
(
"to_string produces valid input for parse"
)
{
...
...
@@ -188,7 +187,7 @@ SCENARIO("to_string produces valid input for parse") {
auto
x_str
=
to_string
(
x
);
CHECK_EQ
(
x_str
,
"1999-09-09T09:09:09.009"
);
auto
y
=
datetime
{};
CHECK_EQ
(
y
.
parse
(
x_str
),
none
);
CHECK_EQ
(
parse
(
x_str
,
y
),
none
);
CHECK_EQ
(
x
,
y
);
CHECK_EQ
(
x_str
,
to_string
(
y
));
}
...
...
@@ -209,7 +208,7 @@ SCENARIO("to_string produces valid input for parse") {
auto
x_str
=
to_string
(
x
);
CHECK_EQ
(
x_str
,
"2010-10-10T10:10:10.099Z"
);
auto
y
=
datetime
{};
CHECK_EQ
(
y
.
parse
(
x_str
),
none
);
CHECK_EQ
(
parse
(
x_str
,
y
),
none
);
CHECK_EQ
(
x
,
y
);
CHECK_EQ
(
x_str
,
to_string
(
y
));
}
...
...
@@ -230,7 +229,7 @@ SCENARIO("to_string produces valid input for parse") {
auto
x_str
=
to_string
(
x
);
CHECK_EQ
(
x_str
,
"2211-11-11T11:11:11.999+01:30"
);
auto
y
=
datetime
{};
CHECK_EQ
(
y
.
parse
(
x_str
),
none
);
CHECK_EQ
(
parse
(
x_str
,
y
),
none
);
CHECK_EQ
(
x
,
y
);
CHECK_EQ
(
x_str
,
to_string
(
y
));
}
...
...
@@ -251,7 +250,7 @@ SCENARIO("to_string produces valid input for parse") {
auto
x_str
=
to_string
(
x
);
CHECK_EQ
(
x_str
,
"1122-12-12T12:12:12.999-01:30"
);
auto
y
=
datetime
{};
CHECK_EQ
(
y
.
parse
(
x_str
),
none
);
CHECK_EQ
(
parse
(
x_str
,
y
),
none
);
CHECK_EQ
(
x
,
y
);
CHECK_EQ
(
x_str
,
to_string
(
y
));
}
...
...
@@ -352,11 +351,11 @@ TEST_CASE("the fractional component may have 1-9 digits") {
TEST_CASE
(
"chrono::to_string generates valid input for datetime::parse"
)
{
// We know neither the local timezone nor what the system clock returns, so we
// can only check that the string is valid by parsing it again.
/* std::chrono time point */
{
{
// std::chrono time point
auto
str
=
chrono
::
to_string
(
std
::
chrono
::
system_clock
::
now
());
CHECK
(
datetime
::
from_string
(
str
));
}
/* caf::timestamp */
{
{
// caf::timestamp
auto
str
=
chrono
::
to_string
(
make_timestamp
());
CHECK
(
datetime
::
from_string
(
str
));
}
...
...
@@ -369,3 +368,17 @@ TEST_CASE("chrono::to_string and chrono::print generate the same string") {
chrono
::
print
(
str2
,
ts
);
CHECK_EQ
(
str1
,
str2
);
}
TEST_CASE
(
"two timestamps with the same time point are equal"
)
{
auto
from_string
=
[](
std
::
string_view
str
)
{
return
datetime
::
from_string
(
str
);
};
CHECK_EQ
(
from_string
(
"2021-02-03T14:25:36Z"
),
from_string
(
"2021-02-03T14:25:36+00:00"
));
CHECK_EQ
(
from_string
(
"2021-02-03T14:25:36Z"
),
from_string
(
"2021-02-03T15:25:36+01:00"
));
CHECK_EQ
(
from_string
(
"2021-02-03T14:25:36Z"
),
from_string
(
"2021-02-03T13:25:36-01:00"
));
CHECK_EQ
(
from_string
(
"2021-02-03T15:25:36+01:00"
),
from_string
(
"2021-02-03T13:25:36-01:00"
));
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment