1
1
// This code has been automatically generated by aas-core-codegen.
2
2
// Do NOT edit or append.
3
3
4
+ #include "./BigInt.hpp"
5
+ #include "aas_core/aas_3_0/common.hpp"
4
6
#include "aas_core/aas_3_0/constants.hpp"
5
7
#include "aas_core/aas_3_0/verification.hpp"
6
8
@@ -220,9 +222,48 @@ bool MatchesXsDateTimeUtc(
220
222
}
221
223
222
224
const std::wregex kRegexDatePrefix(
223
- L"^(-?[0-9]+)-(0[1-9]|11|12 )-(0[0-9]|1[0-9]|2[0-9]|30|31)"
225
+ L"^(-?[0-9]+)-(0[1-9]|1[0-2] )-(0[0-9]|1[0-9]|2[0-9]|30|31)"
224
226
);
225
227
228
+ template<
229
+ typename T,
230
+ std::enable_if<
231
+ std::is_integral<T>::value
232
+ || std::is_same<T, BigInt>::value
233
+ >* = nullptr
234
+ >
235
+ bool IsLeapYear(T year) {
236
+ // NOTE (mristin):
237
+ // We consider the years B.C. to be one-off.
238
+ // See the note at: https://www.w3.org/TR/xmlschema-2/#dateTime:
239
+ // "'-0001' is the lexical representation of the year 1 Before Common Era
240
+ // (1 BCE, sometimes written "1 BC")."
241
+ //
242
+ // Hence, -1 year in XML is 1 BCE, which is 0 year in astronomical years.
243
+ if (year < 0) {
244
+ year = -year - 1;
245
+ }
246
+
247
+ // See: See: https://en.wikipedia.org/wiki/Leap_year#Algorithm
248
+ if (year % 4 > 0)
249
+ {
250
+ return false;
251
+ }
252
+
253
+ if (year % 100 > 0)
254
+ {
255
+ return true;
256
+ }
257
+
258
+ if (year % 400 > 0)
259
+ {
260
+ return false;
261
+ }
262
+
263
+ return true;
264
+ }
265
+
266
+
226
267
bool IsLeapYear(long long year) {
227
268
// NOTE (mristin):
228
269
// We consider the years B.C. to be one-off.
@@ -272,17 +313,15 @@ const std::map<int, int> kDaysInMonth = {
272
313
};
273
314
274
315
/**
275
- * \brief Check that \p value is a valid `xs:date`.
316
+ * \brief Check that \p value is a valid `xs:date` without the offset .
276
317
*
277
318
* Year 1 BCE is the last leap BCE year.
278
319
* See: https://www.w3.org/TR/xmlschema-2/#dateTime.
279
320
*
280
321
* \param value to be checked
281
322
* \return true if \p value is a valid `xs:date`
282
323
*/
283
- bool IsXsDate(
284
- const std::wstring& text
285
- ) {
324
+ bool IsXsDateWithoutOffset(const std::wstring& text) {
286
325
// NOTE (mristin):
287
326
// We can not use date functions from the operation system as they do not
288
327
// handle years BCE (*e.g.*, `-0003-01-02`).
@@ -301,10 +340,14 @@ bool IsXsDate(
301
340
// difficult. Hence, we sacrifice the efficiency a bit for the clearer code & code
302
341
// generation.
303
342
304
- long long year;
343
+ bool is_zero_year;
344
+ bool is_leap_year;
305
345
306
346
try {
307
- year = std::stoll(match[1].str());
347
+ const long long year = std::stoll(match[1].str());
348
+
349
+ is_zero_year = year == 0;
350
+ is_leap_year = IsLeapYear<long long>(year);
308
351
} catch (const std::invalid_argument&) {
309
352
std::wstringstream wss;
310
353
wss
@@ -315,19 +358,11 @@ bool IsXsDate(
315
358
common::WstringToUtf8(wss.str())
316
359
);
317
360
} catch (const std::out_of_range&) {
318
- std::wstringstream wss;
319
- wss
320
- << "The year is out of range for long long integers: "
321
- << match[1].str()
322
- << (
323
- "; we at aas-core-works planned to include handling of BigInt years "
324
- "in the SDK, but eventually lacked the time for it. Please let the developers "
325
- "know that you need this feature."
326
- );
327
-
328
- throw std::out_of_range(
329
- common::WstringToUtf8(wss.str())
361
+ const BigInt year(
362
+ common::WstringToUtf8(match[1].str())
330
363
);
364
+ is_zero_year = year == 0;
365
+ is_leap_year = IsLeapYear<BigInt>(std::move(year));
331
366
}
332
367
333
368
const int month = std::stoi(match[2].str());
@@ -336,7 +371,7 @@ bool IsXsDate(
336
371
// NOTE (mristin):
337
372
// We do not accept year zero, see the note at:
338
373
// https://www.w3.org/TR/xmlschema-2/#dateTime
339
- if (year == 0 ) {
374
+ if (is_zero_year ) {
340
375
return false;
341
376
}
342
377
@@ -350,7 +385,7 @@ bool IsXsDate(
350
385
351
386
const int max_days(
352
387
(month == 2)
353
- ? (IsLeapYear(year) ? 29 : 28)
388
+ ? (is_leap_year ? 29 : 28)
354
389
: kDaysInMonth.at(month)
355
390
);
356
391
@@ -386,7 +421,7 @@ bool IsXsDateTimeUtc(
386
421
// should be used here.
387
422
std::wstring date = text.substr(0, pos);
388
423
389
- return IsXsDate (date);
424
+ return IsXsDateWithoutOffset (date);
390
425
}
391
426
392
427
std::wregex ConstructMatchesMimeType() {
@@ -1610,7 +1645,7 @@ bool IsXsDateTime(
1610
1645
// should be used here.
1611
1646
std::wstring date = text.substr(0, pos);
1612
1647
1613
- return IsXsDate (date);
1648
+ return IsXsDateWithoutOffset (date);
1614
1649
}
1615
1650
1616
1651
std::wregex ConstructMatchesXsDecimal() {
@@ -2239,6 +2274,58 @@ bool MatchesXsString(
2239
2274
);
2240
2275
}
2241
2276
2277
+ bool IsXsDate(const std::wstring& text) {
2278
+ std::wsmatch match;
2279
+ const bool matched = std::regex_match(text, match, kRegexMatchesXsDate);
2280
+
2281
+ if (!matched) {
2282
+ return false;
2283
+ }
2284
+
2285
+ size_t cursor = 0;
2286
+ if (text[0] == L'-') {
2287
+ cursor = 1;
2288
+ }
2289
+
2290
+ while (std::isdigit(text[cursor])) {
2291
+ ++cursor;
2292
+ }
2293
+
2294
+ if (text[cursor] != L'-') {
2295
+ throw std::logic_error(
2296
+ common::Concat(
2297
+ "Expected a dash after a year, but got the date text: ",
2298
+ common::WstringToUtf8(text)
2299
+ )
2300
+ );
2301
+ }
2302
+ ++cursor;
2303
+
2304
+ while (std::isdigit(text[cursor])) {
2305
+ ++cursor;
2306
+ }
2307
+
2308
+ if (text[cursor] != L'-') {
2309
+ throw std::logic_error(
2310
+ common::Concat(
2311
+ "Expected a dash after a month, but got the date text: ",
2312
+ common::WstringToUtf8(text)
2313
+ )
2314
+ );
2315
+ }
2316
+ ++cursor;
2317
+
2318
+ while (std::isdigit(text[cursor])) {
2319
+ ++cursor;
2320
+ }
2321
+
2322
+ const std::wstring date_without_offset(
2323
+ text.substr(0, cursor)
2324
+ );
2325
+
2326
+ return IsXsDateWithoutOffset(date_without_offset);
2327
+ }
2328
+
2242
2329
bool IsXsDouble(const std::wstring& value) {
2243
2330
// NOTE (mristin):
2244
2331
// We need to check explicitly for the regular expression since
0 commit comments