ritsuko
Helper utilities for ArtifactDB C++ code
Loading...
Searching...
No Matches
is_date_time.hpp
Go to the documentation of this file.
1#ifndef RITSUKO_IS_DATE_TIME_HPP
2#define RITSUKO_IS_DATE_TIME_HPP
3
4#include <cctype>
5#include <cstdlib>
6#include <iostream>
7
13namespace ritsuko {
14
23inline bool is_date_prefix(const char* ptr) {
24 for (size_t p = 0; p < 4; ++p) {
25 if (!std::isdigit(ptr[p])) {
26 return false;
27 }
28 }
29
30 if (ptr[4] != '-') {
31 return false;
32 }
33
34 for (size_t p = 5; p <= 6; ++p) {
35 if (!std::isdigit(ptr[p])) {
36 return false;
37 }
38 }
39 if (ptr[5] == '1') {
40 if (ptr[6] > '2') {
41 return false;
42 }
43 } else if (ptr[5] != '0') {
44 return false;
45 }
46
47 if (ptr[7] != '-') {
48 return false;
49 }
50
51 for (size_t p = 8; p <= 9; ++p) {
52 if (!std::isdigit(ptr[p])) {
53 return false;
54 }
55 }
56 if (ptr[8] == '3') {
57 if (ptr[9] > '1') {
58 return false;
59 }
60 } else if (ptr[8] > '3') {
61 return false;
62 }
63
64 return true;
65}
66
73inline bool is_date(const char* ptr, size_t len) {
74 if (len != 10) {
75 return false;
76 }
77 return is_date_prefix(ptr);
78}
79
83inline bool okay_hours(const char* ptr, size_t offset) {
84 for (size_t i = 0; i < 2; ++i) {
85 if (!std::isdigit(ptr[offset + i])) {
86 return false;
87 }
88 }
89
90 if (ptr[offset] == '2') {
91 if (ptr[offset + 1] > '4') {
92 return false;
93 }
94 } else if (ptr[offset] > '2') {
95 return false;
96 }
97
98 return true;
99}
100
101inline bool okay_minutes(const char* ptr, size_t offset) {
102 for (size_t i = 0; i < 2; ++i) {
103 if (!std::isdigit(ptr[offset + i])) {
104 return false;
105 }
106 }
107
108 if (ptr[offset] > '5') {
109 return false;
110 }
111
112 return true;
113}
114
115inline bool okay_seconds(const char* ptr, size_t offset) {
116 for (size_t i = 0; i < 2; ++i) {
117 if (!std::isdigit(ptr[offset + i])) {
118 return false;
119 }
120 }
121
122 if (ptr[offset] == '6') { // allow for leap seconds.
123 if (ptr[offset + 1] > '0') {
124 return false;
125 }
126 } else if (ptr[offset] > '5') {
127 return false;
128 }
129
130 return true;
131}
147inline bool is_rfc3339_suffix(const char* ptr, size_t len) {
148 if (ptr[0] != 'T') {
149 return false;
150 }
151
152 // Checking the time.
153 if (!okay_hours(ptr, 1)) {
154 return false;
155 }
156 if (ptr[3] != ':') {
157 return false;
158 }
159 if (!okay_minutes(ptr, 4)) {
160 return false;
161 }
162 if (ptr[6] != ':') {
163 return false;
164 }
165 if (!okay_seconds(ptr, 7)) {
166 return false;
167 }
168
169 size_t shift = 0;
170 bool zero_fraction = true;
171 if (ptr[9] == '.') { // handling fractional seconds; must have one digit.
172 constexpr size_t start = 10;
173 size_t counter = start;
174 while (counter < len && std::isdigit(ptr[counter])) {
175 if (ptr[counter] != '0') {
176 zero_fraction = false;
177 }
178 ++counter;
179 }
180 if (counter == start) {
181 return false;
182 }
183 shift = counter - start + 1; // +1 to account for the period.
184 }
185
186 // Checking special case of 24:00:00.
187 if (ptr[1] == '2' && ptr[2] == '4') {
188 if (ptr[4] != '0' || ptr[5] != '0' || ptr[7] != '0' || ptr[8] != '0' || !zero_fraction) {
189 return false;
190 }
191 }
192
193 // Checking special case of leap years.
194 if (ptr[7] == '6' && ptr[8] == '0') {
195 if (!zero_fraction) {
196 return false;
197 }
198 }
199
200 // Now checking the timezone.
201 size_t tz_start = 9 + shift;
202 if (tz_start >= len) {
203 return false;
204 }
205 if (ptr[tz_start] == 'Z') {
206 return (len == tz_start + 1);
207 }
208
209 if (len != tz_start + 6) {
210 return false;
211 }
212 if (ptr[tz_start] != '+' && ptr[tz_start] != '-') {
213 return false;
214 }
215 if (!okay_hours(ptr, tz_start + 1)) {
216 return false;
217 }
218 if (ptr[tz_start + 3] != ':') {
219 return false;
220 }
221 if (!okay_minutes(ptr, tz_start + 4)) {
222 return false;
223 }
224
225 return true;
226}
227
237inline bool is_rfc3339(const char* ptr, size_t len) {
238 if (len < 20) { // YYYY-MM-DDTHH:MM:SSZ is the shortest format.
239 return false;
240 }
241
242 if (!is_date_prefix(ptr)) {
243 return false;
244 }
245
246 // Skip the characters associated with the date.
247 return is_rfc3339_suffix(ptr + 10, len - 10);
248}
249
250}
251
252#endif
Assorted helper functions for parsing and validation.
Definition choose_missing_placeholder.hpp:15
bool is_date_prefix(const char *ptr)
Definition is_date_time.hpp:23
bool is_rfc3339(const char *ptr, size_t len)
Definition is_date_time.hpp:237
bool is_rfc3339_suffix(const char *ptr, size_t len)
Definition is_date_time.hpp:147
bool is_date(const char *ptr, size_t len)
Definition is_date_time.hpp:73