Time Shield Library
C++ library for working with time
Loading...
Searching...
No Matches
time_parser.hpp
Go to the documentation of this file.
1#pragma once
2#ifndef _TIME_SHIELD_TIME_PARSER_HPP_INCLUDED
3#define _TIME_SHIELD_TIME_PARSER_HPP_INCLUDED
4
10
11#include "enums.hpp"
12#include "constants.hpp"
13#include "date_time_struct.hpp"
14#include "time_zone_struct.hpp"
15#include "validation.hpp"
16#include "time_conversions.hpp"
17#include <regex>
18#include <algorithm>
19#include <locale>
20#include <array>
21#include <stdexcept>
22#include <sstream>
23
24namespace time_shield {
25
57
63 template<class T = Month>
64 T get_month_number(const std::string& month) {
65 if (month.empty()) throw std::invalid_argument("Invalid month name");
66
67 std::string month_copy = month;
68 std::transform(month_copy.begin(), month_copy.end(), month_copy.begin(), [](char &ch) {
69 return std::use_facet<std::ctype<char>>(std::locale()).tolower(ch);
70 });
71 month_copy[0] = toupper(month_copy[0]);
72
73 static const std::array<std::string, 12> short_names = {
74 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
75 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
76 };
77 static const std::array<std::string, 12> full_names = {
78 "January", "February", "March", "April", "May", "June",
79 "July", "August", "September", "October", "November", "December"
80 };
81
82 for(int i = 0; i < MONTHS_PER_YEAR; ++i) {
83 if (month == short_names[i] || month == full_names[i]) {
84 return static_cast<T>(i + 1);
85 }
86 }
87 throw std::invalid_argument("Invalid month name");
88 }
89
92 template<class T = Month>
93 T month_of_year(const std::string& month) {
94 return get_month_number(month);
95 }
96
97//------------------------------------------------------------------------------
98
104 template<class T = Month>
105 bool try_get_month_number(const std::string& month, T& value) {
106 if (month.empty()) return false;
107
108 std::string month_copy = month;
109 std::transform(month_copy.begin(), month_copy.end(), month_copy.begin(), [](char &ch) {
110 return std::use_facet<std::ctype<char>>(std::locale()).tolower(ch);
111 });
112 month_copy[0] = toupper(month_copy[0]);
113
114 static const std::array<std::string, MONTHS_PER_YEAR> short_names = {
115 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
116 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
117 };
118 static const std::array<std::string, MONTHS_PER_YEAR> full_names = {
119 "January", "February", "March", "April", "May", "June",
120 "July", "August", "September", "October", "November", "December"
121 };
122
123 for (int i = 0; i < MONTHS_PER_YEAR; ++i) {
124 if (month_copy == short_names[i] || month_copy == full_names[i]) {
125 value = static_cast<T>(i + 1);
126 return true;
127 }
128 }
129 return false;
130 }
131
134 template<class T = Month>
135 bool get_month_number(const std::string& month, T& value) {
136 return try_get_month_number(month, value);
137 }
138
141 template<class T = Month>
142 bool month_of_year(const std::string& month, T& value) {
143 return try_get_month_number(month, value);
144 }
145
146//------------------------------------------------------------------------------
147
154 bool parse_time_zone(const std::string& tz_str, TimeZoneStruct &tz) {
155 if (tz_str.empty()) {
156 tz.hour = 0;
157 tz.min = 0;
158 tz.is_positive = true;
159 return true;
160 }
161 if (tz_str == "Z") {
162 tz.hour = 0;
163 tz.min = 0;
164 tz.is_positive = true;
165 return true;
166 }
167 tz.is_positive = (tz_str[0] == '+');
168 tz.hour = std::stoi(tz_str.substr(1, 2));
169 tz.min = std::stoi(tz_str.substr(4, 2));
170 return is_valid_time_zone(tz);
171 }
172
175 inline bool parse_tz(const std::string& tz_str, TimeZoneStruct &tz) {
176 return parse_time_zone(tz_str, tz);
177 }
178
179//------------------------------------------------------------------------------
180
189 const std::string& input,
190 DateTimeStruct &dt,
191 TimeZoneStruct &tz) {
192 // Регулярное выражение для даты в формате ISO8601
193 static const std::regex date_regex(R"((\d{4})[-\/\.](\d{2})[-\/\.](\d{2}))");
194 std::smatch date_match;
195
196 // Регулярное выражение для времени в формате ISO8601 с часовым поясом и без
197 static const std::regex time_regex(R"((\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?(Z|[+-]\d{2}:\d{2})?)");
198 std::smatch time_match;
199
201 tz = create_time_zone_struct(0, 0);
202
203 // Парсинг даты
204 if (std::regex_search(input, date_match, date_regex)) {
205 dt.year = std::stoll(date_match[1].str());
206 dt.mon = std::stoi(date_match[2].str());
207 dt.day = std::stoi(date_match[3].str());
208 } else {
209 return false;
210 }
211
212 // Парсинг времени и часового пояса
213 if (std::regex_search(input, time_match, time_regex)) {
214 dt.hour = std::stoi(time_match[1].str());
215 dt.min = std::stoi(time_match[2].str());
216 dt.sec = std::stoi(time_match[3].str());
217 if (time_match[4].matched) {
218 dt.ms = std::stoi(time_match[4].str());
219 }
220 if (time_match[5].matched) {
221 if (!parse_time_zone(time_match[5].str(), tz)) return false;
222 }
223 return is_valid_date_time(dt);
224 }
225 return true;
226 }
227
233 inline bool str_to_ts(const std::string &str, ts_t& ts) {
236 if (!parse_iso8601(str, dt, tz)) return false;
237 try {
238 ts = to_timestamp(dt) + to_offset(tz);
239 return true;
240 } catch(...) {}
241 return false;
242 }
243
249 inline bool str_to_ts_ms(const std::string &str, ts_ms_t& ts) {
252 if (!parse_iso8601(str, dt, tz)) return false;
253 try {
255 return true;
256 } catch(...) {}
257 return false;
258 }
259
265 inline bool str_to_fts(const std::string &str, fts_t& ts) {
268 if (!parse_iso8601(str, dt, tz)) return false;
269 try {
270 ts = to_ftimestamp(dt) + static_cast<fts_t>(to_offset(tz));
271 return true;
272 } catch(...) {}
273 return false;
274 }
275
281 inline ts_t ts(const std::string& str) {
282 ts_t ts = 0;
283 str_to_ts(str, ts);
284 return ts;
285 }
286
292 inline ts_ms_t ts_ms(const std::string& str) {
293 ts_ms_t ts = 0;
294 str_to_ts_ms(str, ts);
295 return ts;
296 }
297
303 inline fts_t fts(const std::string& str) {
304 fts_t ts = 0;
305 str_to_fts(str, ts);
306 return ts;
307 }
308
309 //--------------------------------------------------------------------------
310
322 template<class T = int>
323 inline bool sec_of_day(const std::string& str, T& sec) {
324 if (str.empty()) return false;
325
326 const char* p = str.c_str();
327 int parts[3] = {0, 0, 0}; // hour, minute, second
328 int idx = 0;
329
330 while (*p && idx < 3) {
331 // Parse integer
332 int value = 0;
333 bool has_digit = false;
334
335 while (*p >= '0' && *p <= '9') {
336 has_digit = true;
337 value = value * 10 + (*p - '0');
338 ++p;
339 }
340
341 if (!has_digit) return false;
342 parts[idx++] = value;
343
344 // Expect colon or end
345 if (*p == ':') {
346 ++p;
347 } else if (*p == '\0') {
348 break;
349 } else {
350 return false; // unexpected character
351 }
352 }
353
354 if (idx == 0) return false;
355 if (!is_valid_time(parts[0], parts[1], parts[2])) return false;
356
357 sec = static_cast<T>(sec_of_day(parts[0], parts[1], parts[2]));
358 return true;
359 }
360
371 template<class T = int>
372 inline T sec_of_day(const std::string& str) {
373 T value{};
374 if (sec_of_day(str, value))
375 return value;
376 return static_cast<T>(SEC_PER_DAY);
377 }
378
379
385 inline ts_t ts(const char *str) {
386 ts_t ts = 0;
387 str_to_ts(str, ts);
388 return ts;
389 }
390
396 inline ts_ms_t ts_ms(const char *str) {
397 ts_ms_t ts = 0;
398 str_to_ts_ms(str, ts);
399 return ts;
400 }
401
407 inline fts_t fts(const char *str) {
408 fts_t ts = 0;
409 str_to_fts(str, ts);
410 return ts;
411 }
412
414
415};
416
417#endif // _TIME_SHIELD_TIME_PARSER_HPP_INCLUDED
Header file with time-related constants.
Header for date and time structure and related functions.
Header file with enumerations for weekdays, months, and other time-related categories.
const int64_t MONTHS_PER_YEAR
Months per year.
constexpr int64_t SEC_PER_DAY
Seconds per day.
Definition constants.hpp:76
TIME_SHIELD_CONSTEXPR const ts_t to_timestamp_ms(const T &date_time)
Alias for dt_to_timestamp_ms function.
TIME_SHIELD_CONSTEXPR ts_t ts(year_t year, int month, int day)
Alias for to_timestamp.
TIME_SHIELD_CONSTEXPR const T month_of_year(ts_t ts) noexcept
Get the month of the year.
constexpr fts_t to_ftimestamp(const T &date_time)
Alias for dt_to_ftimestamp.
constexpr const T sec_of_day(ts_t ts=ts()) noexcept
Get the second of the day.
constexpr T1 sec_to_ms(T2 ts) noexcept
Converts a timestamp from seconds to milliseconds.
TIME_SHIELD_CONSTEXPR const ts_t to_timestamp(const T &date_time)
Alias for dt_to_timestamp function.
bool str_to_ts_ms(const std::string &str, ts_ms_t &ts)
Convert an ISO8601 string to a millisecond timestamp (ts_ms_t).
bool parse_iso8601(const std::string &input, DateTimeStruct &dt, TimeZoneStruct &tz)
Parse a date and time string in ISO8601 format.
bool try_get_month_number(const std::string &month, T &value)
Get the month number by name, with output parameter.
T get_month_number(const std::string &month)
Get the month number by name.
bool str_to_ts(const std::string &str, ts_t &ts)
Convert an ISO8601 string to a timestamp (ts_t).
bool str_to_fts(const std::string &str, fts_t &ts)
Convert an ISO8601 string to a floating-point timestamp (fts_t).
bool parse_time_zone(const std::string &tz_str, TimeZoneStruct &tz)
Parse a time zone string into a TimeZoneStruct.
bool parse_tz(const std::string &tz_str, TimeZoneStruct &tz)
Alias for parse_time_zone function.
const tz_t to_offset(const TimeZoneStruct &tz)
Alias for time_zone_struct_to_offset function.
const DateTimeStruct create_date_time_struct(int64_t year, int mon=1, int day=1, int hour=0, int min=0, int sec=0, int ms=0)
Creates a DateTimeStruct instance.
const TimeZoneStruct create_time_zone_struct(int hour, int min, bool is_positive=true)
Creates a TimeZoneStruct instance.
int64_t ts_t
Unix timestamp in seconds since 1970‑01‑01T00:00:00Z.
Definition types.hpp:45
int64_t ts_ms_t
Unix timestamp in milliseconds since epoch.
Definition types.hpp:46
double fts_t
Floating-point timestamp (fractional seconds since epoch).
Definition types.hpp:48
const ts_t ts() noexcept
Get the current UTC timestamp in seconds.
const ts_ms_t ts_ms() noexcept
Get the current UTC timestamp in milliseconds.
const fts_t fts() noexcept
Get the current UTC timestamp in floating-point seconds.
TIME_SHIELD_CONSTEXPR bool is_valid_time_zone(T hour, T min) noexcept
Check if the time zone is valid.
TIME_SHIELD_CONSTEXPR bool is_valid_time(T1 hour, T1 min, T1 sec, T2 ms=0) noexcept
Checks the correctness of the specified time.
TIME_SHIELD_CONSTEXPR bool is_valid_date_time(T1 year, T2 month, T2 day, T2 hour=0, T2 min=0, T2 sec=0, T3 ms=0) noexcept
Checks the correctness of a date and time.
Main namespace for the Time Shield library.
Structure to represent date and time.
int ms
Millisecond component of time (0-999)
int hour
Hour component of time (0-23)
int64_t year
Year component of the date.
int day
Day component of the date (1-31).
int min
Minute component of time (0-59)
int mon
Month component of the date (1-12).
int sec
Second component of time (0-59)
Structure to represent time zone information.
int hour
Hour component of time (0-23)
int min
Minute component of time (0-59)
bool is_positive
True if the time zone offset is positive, false if negative.
Header file for time conversion functions.
Header for time zone structure and related functions.
Header file with time-related validation functions.