DocWire SDK
DocWire SDK: Deterministic, auditable, and secure data processing in C++20. On-premise by default. No compromises on computational speed.
Loading...
Searching...
No Matches
convert_chrono.h
1/*********************************************************************************************************************************************/
2/* DocWire SDK: Award-winning modern data processing in C++20. SourceForge Community Choice & Microsoft support. AI-driven processing. */
3/* Supports nearly 100 data formats, including email boxes and OCR. Boost efficiency in text extraction, web data extraction, data mining, */
4/* document analysis. Offline processing possible for security and confidentiality */
5/* */
6/* Copyright (c) SILVERCODERS Ltd, http://silvercoders.com */
7/* Project homepage: https://github.com/docwire/docwire */
8/* */
9/* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-DocWire-Commercial */
10/*********************************************************************************************************************************************/
11
12#ifndef DOCWIRE_CONVERT_CHRONO_H
13#define DOCWIRE_CONVERT_CHRONO_H
14
15#include "convert_base.h"
16#include <chrono>
17#include <optional>
18#include <string>
19#include "with_date_format.h"
20#include "convert_numeric.h"
21#include "log_scope.h"
22
23namespace docwire::convert
24{
25
26namespace detail
27{
28
29inline bool try_to_int(std::string_view sv, int& out) noexcept
30{
31 if (auto val = try_to<int>(sv))
32 {
33 out = *val;
34 return true;
35 }
36 return false;
37}
38
39inline std::optional<std::chrono::sys_seconds> create_sys_seconds(int year, int month, int day, int hour, int minute, int second) noexcept
40{
41 using namespace std::chrono;
42
43 const year_month_day ymd{std::chrono::year{year}, std::chrono::month{static_cast<unsigned>(month)}, std::chrono::day{static_cast<unsigned>(day)}};
44 if (!ymd.ok())
45 return std::nullopt;
46
47 if (hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 60)
48 return std::nullopt;
49
50 return sys_days{ymd} + hours{hour} + minutes{minute} + seconds{second};
51}
52
53inline std::optional<std::chrono::sys_seconds> parse_iso8601(std::string_view s) noexcept
54{
55 int y, m, d, h, min, sec;
56 // ISO 8601: YYYY-MM-DDTHH:MM:SS
57 if (s.length() >= 19 &&
58 try_to_int(s.substr(0, 4), y) && s[4] == '-' &&
59 try_to_int(s.substr(5, 2), m) && s[7] == '-' &&
60 try_to_int(s.substr(8, 2), d) && s[10] == 'T' &&
61 try_to_int(s.substr(11, 2), h) && s[13] == ':' &&
62 try_to_int(s.substr(14, 2), min) && s[16] == ':' &&
63 try_to_int(s.substr(17, 2), sec))
64 return create_sys_seconds(y, m, d, h, min, sec);
65 return std::nullopt;
66}
67
68inline std::optional<std::chrono::sys_seconds> parse_openoffice_legacy(std::string_view s) noexcept
69{
70 int y, m, d, h, min, sec;
71 // OpenOffice legacy: YYYYMMDD;HHMMSSff (fractional seconds 'ff' are ignored)
72 if (s.length() >= 17 &&
73 try_to_int(s.substr(0, 4), y) &&
74 try_to_int(s.substr(4, 2), m) &&
75 try_to_int(s.substr(6, 2), d) && s[8] == ';' &&
76 try_to_int(s.substr(9, 2), h) &&
77 try_to_int(s.substr(11, 2), min) &&
78 try_to_int(s.substr(13, 2), sec))
79 return create_sys_seconds(y, m, d, h, min, sec);
80 return std::nullopt;
81}
82
83inline std::optional<std::chrono::sys_seconds> parse_asn1(std::string_view s) noexcept
84{
85 int y, m, d, h, min, sec;
86 // ASN.1 format: YYYYMMDDHHmmSS
87 if (s.length() >= 14 &&
88 try_to_int(s.substr(0, 4), y) &&
89 try_to_int(s.substr(4, 2), m) &&
90 try_to_int(s.substr(6, 2), d) &&
91 try_to_int(s.substr(8, 2), h) &&
92 try_to_int(s.substr(10, 2), min) &&
93 try_to_int(s.substr(12, 2), sec))
94 return create_sys_seconds(y, m, d, h, min, sec);
95 return std::nullopt;
96}
97
98} // namespace detail
99
103inline std::optional<std::chrono::sys_seconds> convert_impl(with::date_format::iso8601 s, dest_type_tag<std::chrono::sys_seconds>) noexcept
104{
105 DOCWIRE_LOG_SCOPE(s);
106 return detail::parse_iso8601(s.v);
107}
108
111inline std::optional<std::chrono::sys_seconds> convert_impl(with::date_format::openoffice_legacy s, dest_type_tag<std::chrono::sys_seconds>) noexcept
112{
113 DOCWIRE_LOG_SCOPE(s);
114 return detail::parse_openoffice_legacy(s.v);
115}
116
119inline std::optional<std::chrono::sys_seconds> convert_impl(with::date_format::asn1 s, dest_type_tag<std::chrono::sys_seconds>) noexcept
120{
121 DOCWIRE_LOG_SCOPE(s);
122 return detail::parse_asn1(s.v);
123}
124
125// Formatting sys_seconds to string
129inline std::optional<std::string> convert_impl(std::chrono::sys_seconds tp, dest_type_tag<std::string>) noexcept
130{
131 auto ymd = std::chrono::year_month_day{std::chrono::floor<std::chrono::days>(tp)};
132 auto time = std::chrono::hh_mm_ss{tp - std::chrono::floor<std::chrono::days>(tp)};
133
134 auto to_string_padded = [](int value) {
135 return (value < 10 ? "0" : "") + std::to_string(value);
136 };
137
138 return std::to_string(static_cast<int>(ymd.year())) + '-' +
139 to_string_padded(static_cast<unsigned>(ymd.month())) + '-' +
140 to_string_padded(static_cast<unsigned>(ymd.day())) + ' ' +
141 to_string_padded(time.hours().count()) + ':' +
142 to_string_padded(time.minutes().count()) + ':' +
143 to_string_padded(time.seconds().count());
144}
145
146} // namespace docwire::convert
147
148#endif // DOCWIRE_CONVERT_CHRONO_H
Namespace for type conversion utilities.
std::optional< std::chrono::sys_seconds > convert_impl(with::date_format::iso8601 s, dest_type_tag< std::chrono::sys_seconds >) noexcept
Converts an ISO 8601 date string to sys_seconds.
constexpr std::optional< To > try_to(const From &from) noexcept
Tries to convert a value of type From to type To.
A tag type used for dispatching convert_impl overloads based on the destination type.
ISO 8601 format (e.g., "2023-10-27T10:00:00").