1
2
3
4
5
6 using System.Concepts;
7
8 namespace System
9 {
10 public string ToString<I, U>(I x) where I is SignedInteger and U is UnsignedInteger and ExplicitlyConvertible<I, U> and ExplicitlyConvertible<U, byte>
11 {
12 string s;
13 U u = 0u;
14 bool neg = x < 0;
15 if (neg)
16 {
17 u = -cast<U>(x);
18 }
19 else
20 {
21 u = cast<U>(x);
22 }
23 do
24 {
25 s.Append(cast<char>(cast<byte>('0') + cast<byte>(u % 10u)));
26 u = u / 10u;
27 }
28 while (u != 0u);
29 if (neg)
30 {
31 s.Append('-');
32 }
33 Reverse(s.Begin(), s.End());
34 return s;
35 }
36
37 public string ToString<U>(U x) where U is UnsignedInteger and ExplicitlyConvertible<U, byte>
38 {
39 string s;
40 do
41 {
42 s.Append(cast<char>(cast<byte>('0') + cast<byte>(x % 10u)));
43 x = x / 10u;
44 }
45 while (x != 0u);
46 Reverse(s.Begin(), s.End());
47 return s;
48 }
49
50 public string ToString(sbyte x)
51 {
52 return ToString(cast<int>(x));
53 }
54
55 public string ToString(byte x)
56 {
57 return ToString(cast<uint>(x));
58 }
59
60 public string ToString(short x)
61 {
62 return ToString(cast<int>(x));
63 }
64
65 public string ToString(ushort x)
66 {
67 return ToString(cast<uint>(x));
68 }
69
70 public string ToString(int x)
71 {
72 return ToString<int, uint>(x);
73 }
74
75 public string ToString(uint x)
76 {
77 return ToString<uint>(x);
78 }
79
80 public string ToString(long x)
81 {
82 return ToString<long, ulong>(x);
83 }
84
85 public string ToString(ulong x)
86 {
87 return ToString<ulong>(x);
88 }
89
90 public string ToString(float f)
91 {
92 return ToString(f, 15);
93 }
94
95 public string ToString(float f, int maxNumDecimals)
96 {
97 return ToString<float>(f, 0, maxNumDecimals);
98 }
99
100 public string ToString(double x, int maxNumDecimals)
101 {
102 return ToString<double>(x, 0, maxNumDecimals);
103 }
104
105 public string ToString(double x)
106 {
107 return ToString(x, 15);
108 }
109
110 public string ToString<T>(T x, int minNumDecimals, int maxNumDecimals)
111 {
112 string result;
113 if (x < 0)
114 {
115 x = -x;
116 result.Append('-');
117 }
118 result.Append(ToString(cast<int>(x)));
119 T d = x - cast<int>(x);
120 if (d > 0 || minNumDecimals > 0)
121 {
122 result.Append('.');
123 for (int i = 0; (d > 0 || i < minNumDecimals) && i < maxNumDecimals; ++i;)
124 {
125 d = 10 * d;
126 int digit = cast<int>(d) % 10;
127 result.Append(cast<char>(cast<int>('0') + digit));
128 d = d - cast<int>(d);
129 }
130 }
131 return result;
132 }
133
134 public string ToString(char c)
135 {
136 return string(c);
137 }
138
139 [nodiscard]
140 public Result<string> ToString(wchar c)
141 {
142 wstring s(c);
143 auto result = ToUtf8(s);
144 if (result.Error())
145 {
146 return Result<string>(ErrorId(result.GetErrorId()));
147 }
148 return Result<string>(result.Value());
149 }
150
151 [nodiscard]
152 public Result<string> ToString(uchar c)
153 {
154 ustring s(c);
155 auto result = ToUtf8(s);
156 if (result.Error())
157 {
158 return Result<string>(ErrorId(result.GetErrorId()));
159 }
160 return Result<string>(result.Value());
161 }
162
163 public string ToString(bool b)
164 {
165 if (b)
166 {
167 return "true";
168 }
169 return "false";
170 }
171
172 [nodiscard]
173 public inline Result<char> HexChar(byte nibble)
174 {
175 if ((nibble & ~15u) != 0u)
176 {
177 int errorId = RtmAllocateError("HexChar: invalid parameter");
178 return Result<char>(ErrorId(errorId));
179 }
180 const char* hex = "0123456789ABCDEF";
181 return Result<char>(hex[nibble]);
182 }
183
184 [nodiscard]
185 public Result<string> ToHexString<U>(U x) where U is UnsignedInteger and ExplicitlyConvertible<U, byte>
186 {
187 string s;
188 long n = sizeof(x);
189 for (long i = 0; i < n; ++i;)
190 {
191 byte b = cast<byte>(x & 255u);
192 auto low = HexChar(b & 15u);
193 if (low.Error())
194 {
195 return Result<string>(ErrorId(low.GetErrorId()));
196 }
197 s.Append(low.Value());
198 auto high = HexChar(b >> 4u);
199 if (high.Error())
200 {
201 return Result<string>(ErrorId(high.GetErrorId()));
202 }
203 s.Append(high.Value());
204 x = x >> 8u;
205 }
206 Reverse(s.Begin(), s.End());
207 return Result<string>(s);
208 }
209
210 [nodiscard]
211 public Result<string> ToHexString(byte b)
212 {
213 string s;
214 auto high = HexChar(b >> 4u);
215 if (high.Error())
216 {
217 return Result<string>(ErrorId(high.GetErrorId()));
218 }
219 s.Append(high.Value());
220 auto low = HexChar(b & 15u);
221 if (low.Error())
222 {
223 return Result<string>(ErrorId(low.GetErrorId()));
224 }
225 s.Append(low.Value());
226 return Result<string>(s);
227 }
228
229 [nodiscard]
230 public Result<string> ToHexString(ushort u)
231 {
232 return ToHexString<ushort>(u);
233 }
234
235 [nodiscard]
236 public Result<string> ToHexString(uint u)
237 {
238 return ToHexString<uint>(u);
239 }
240
241 [nodiscard]
242 public Result<string> ToHexString(ulong u)
243 {
244 return ToHexString<ulong>(u);
245 }
246
247 [nodiscard]
248 public Result<string> ToOctalString(ulong x)
249 {
250 return ToOctalString(x, 0);
251 }
252
253 [nodiscard]
254 public Result<string> ToOctalString(ulong x, int minDigits)
255 {
256 if (minDigits < 0)
257 {
258 int errorId = RtmAllocateError("ToOctalString: minDigits is negative");
259 return Result<string>(ErrorId(errorId));
260 }
261 string s;
262 ++minDigits;
263 do
264 {
265 s.Append(cast<char>(cast<int>(x & 7u) + cast<int>('0')));
266 x = x >> 3u;
267 if (minDigits > 0)
268 {
269 --minDigits;
270 }
271 }
272 while (minDigits != 0 || x != 0u);
273 if (s[s.Length() - 1] != '0')
274 {
275 s.Append('0');
276 }
277 Reverse(s.Begin(), s.End());
278 return s;
279 }
280
281 public bool ParseSigned<T>(const string& s, T& x) where T is SignedInteger
282 {
283 x = cast<T>(0);
284 if (s.IsEmpty()) return false;
285 bool negative = false;
286 int state = 0;
287 for (char c : s)
288 {
289 switch (state)
290 {
291 case 0:
292 {
293 if (c == '+')
294 {
295 state = 1;
296 }
297 else if (c == '-')
298 {
299 negative = true;
300 state = 1;
301 }
302 else if (c >= '0' && c <= '9')
303 {
304 x = cast<T>(c) - cast<T>('0');
305 state = 1;
306 }
307 else
308 {
309 return false;
310 }
311 break;
312 }
313 case 1:
314 {
315 if (c >= '0' && c <= '9')
316 {
317 x = 10 * x + cast<T>(c) - cast<T>('0');
318 }
319 else
320 {
321 return false;
322 }
323 break;
324 }
325 }
326 }
327 if (state != 1)
328 {
329 return false;
330 }
331 else
332 {
333 if (negative)
334 {
335 x = -x;
336 }
337 return true;
338 }
339 }
340
341 public bool ParseUnsigned<T>(const string& s, T& x) where T is UnsignedInteger
342 {
343 x = cast<T>(0u);
344 if (s.IsEmpty())
345 {
346 return false;
347 }
348 int state = 0;
349 for (char c : s)
350 {
351 switch (state)
352 {
353 case 0:
354 {
355 if (c == '+')
356 {
357 state = 1;
358 }
359 else if (c >= '0' && c <= '9')
360 {
361 x = cast<T>(c) - cast<T>('0');
362 state = 1;
363 }
364 else
365 {
366 return false;
367 }
368 break;
369 }
370 case 1:
371 {
372 if (c >= '0' && c <= '9')
373 {
374 x = 10u * x + cast<T>(c) - cast<T>('0');
375 }
376 else
377 {
378 return false;
379 }
380 break;
381 }
382 }
383 }
384 if (state != 1)
385 {
386 return false;
387 }
388 return true;
389 }
390
391 public bool ParseHex<T>(const string& s, T& x) where T is UnsignedInteger
392 {
393 x = cast<T>(0u);
394 if (s.IsEmpty())
395 {
396 return false;
397 }
398 for (char c : s)
399 {
400 if (c >= '0' && c <= '9')
401 {
402 x = 16u * x + (cast<T>(c) - cast<T>('0'));
403 }
404 else if (c >= 'a' && c <= 'f')
405 {
406 x = 16u * x + 10u + (cast<T>(c) - cast<T>('a'));
407 }
408 else if (c >= 'A' && c <= 'F')
409 {
410 x = 16u * x + 10u + (cast<T>(c) - cast<T>('A'));
411 }
412 else
413 {
414 return false;
415 }
416 }
417 return true;
418 }
419
420 public bool ParseFloating<T>(const string& s, T& x)
421 {
422 x = cast<T>(0.000000);
423 if (s.IsEmpty())
424 {
425 return false;
426 }
427 bool negative = false;
428 int start = 0;
429 if (s[0] == '+')
430 {
431 ++start;
432 }
433 else if (s[0] == '-')
434 {
435 negative = true;
436 ++start;
437 }
438 int state = 0;
439 T d = cast<T>(10.000000);
440 int exponent = 0;
441 bool negativeExponent = false;
442 long n = s.Length();
443 for (long i = start; i < n; ++i;)
444 {
445 char c = s[i];
446 switch (state)
447 {
448 case 0:
449 {
450 if (c >= '0' && c <= '9')
451 {
452 x = 10 * x + (cast<int>(c) - cast<int>('0'));
453 }
454 else if (c == '.')
455 {
456 state = 1;
457 }
458 else if (c == 'e' || c == 'E')
459 {
460 state = 2;
461 }
462 else
463 {
464 return false;
465 }
466 break;
467 }
468 case 1:
469 {
470 if (c >= '0' && c <= '9')
471 {
472 x = x + (cast<int>(c) - cast<int>('0')) / d;
473 d = 10 * d;
474 }
475 else if (c == 'e' || c == 'E')
476 {
477 state = 2;
478 }
479 else
480 {
481 return false;
482 }
483 break;
484 }
485 case 2:
486 {
487 if (c == '+')
488 {
489 state = 3;
490 }
491 else if (c == '-')
492 {
493 negativeExponent = true;
494 state = 3;
495 }
496 else if (c >= '0' && c <= '9')
497 {
498 exponent = cast<int>(c) - cast<int>('0');
499 state = 3;
500 }
501 else
502 {
503 return false;
504 }
505 break;
506 }
507 case 3:
508 {
509 if (c >= '0' && c <= '9')
510 {
511 exponent = 10 * exponent + (cast<int>(c) - cast<int>('0'));
512 }
513 else
514 {
515 return false;
516 }
517 break;
518 }
519 }
520 }
521 if (negative)
522 {
523 x = -x;
524 }
525 if (exponent != 0)
526 {
527 if (negativeExponent)
528 {
529 exponent = -exponent;
530 }
531 x = x * cast<T>(Pow(10.000000, exponent));
532 }
533 return true;
534 }
535
536 public bool ParseSByte(const string& s, sbyte& x)
537 {
538 return ParseSigned<sbyte>(s, x);
539 }
540
541 [nodiscard]
542 public Result<sbyte> ParseSByte(const string& s)
543 {
544 sbyte x;
545 if (ParseSByte(s, x))
546 {
547 return Result<sbyte>(x);
548 }
549 else
550 {
551 string errorMessage = "cannot parse sbyte from string \'" + s + "\'";
552 int errorId = RtmAllocateError(errorMessage.Chars());
553 return Result<sbyte>(ErrorId(errorId));
554 }
555 return Result<sbyte>(0);
556 }
557
558 public bool ParseByte(const string& s, byte& x)
559 {
560 return ParseUnsigned<byte>(s, x);
561 }
562
563 [nodiscard]
564 public Result<byte> ParseByte(const string& s)
565 {
566 byte x;
567 if (ParseByte(s, x))
568 {
569 return Result<byte>(x);
570 }
571 else
572 {
573 string errorMessage = "cannot parse byte from string \'" + s + "\'";
574 int errorId = RtmAllocateError(errorMessage.Chars());
575 return Result<byte>(ErrorId(errorId));
576 }
577 return Result<byte>(0u);
578 }
579
580 public bool ParseShort(const string& s, short& x)
581 {
582 return ParseSigned<short>(s, x);
583 }
584
585 [nodiscard]
586 public Result<short> ParseShort(const string& s)
587 {
588 short x;
589 if (ParseShort(s, x))
590 {
591 return Result<short>(x);
592 }
593 else
594 {
595 string errorMessage = "cannot parse short from string \'" + s + "\'";
596 int errorId = RtmAllocateError(errorMessage.Chars());
597 return Result<short>(ErrorId(errorId));
598 }
599 return Result<short>(0);
600 }
601
602 public bool ParseUShort(const string& s, ushort& x)
603 {
604 return ParseUnsigned<ushort>(s, x);
605 }
606
607 [nodiscard]
608 public Result<ushort> ParseUShort(const string& s)
609 {
610 ushort x;
611 if (ParseUShort(s, x))
612 {
613 return Result<ushort>(x);
614 }
615 else
616 {
617 string errorMessage = "cannot parse ushort from string \'" + s + "\'";
618 int errorId = RtmAllocateError(errorMessage.Chars());
619 return Result<ushort>(ErrorId(errorId));
620 }
621 return Result<ushort>(0u);
622 }
623
624 public bool ParseInt(const string& s, int& x)
625 {
626 return ParseSigned<int>(s, x);
627 }
628
629 [nodiscard]
630 public Result<int> ParseInt(const string& s)
631 {
632 int x;
633 if (ParseInt(s, x))
634 {
635 return Result<int>(x);
636 }
637 else
638 {
639 string errorMessage = "cannot parse int from string \'" + s + "\'";
640 int errorId = RtmAllocateError(errorMessage.Chars());
641 return Result<int>(ErrorId(errorId));
642 }
643 return Result<int>(0);
644 }
645
646 public bool ParseUInt(const string& s, uint& x)
647 {
648 return ParseUnsigned<uint>(s, x);
649 }
650
651 [nodiscard]
652 public Result<uint> ParseUInt(const string& s)
653 {
654 uint x;
655 if (ParseUInt(s, x))
656 {
657 return Result<uint>(x);
658 }
659 else
660 {
661 string errorMessage = "cannot parse uint from string \'" + s + "\'";
662 int errorId = RtmAllocateError(errorMessage.Chars());
663 return Result<uint>(ErrorId(errorId));
664 }
665 return Result<uint>(0u);
666 }
667
668 public bool ParseLong(const string& s, long& x)
669 {
670 return ParseSigned<long>(s, x);
671 }
672
673 [nodiscard]
674 public Result<long> ParseLong(const string& s)
675 {
676 long x;
677 if (ParseLong(s, x))
678 {
679 return Result<long>(x);
680 }
681 else
682 {
683 string errorMessage = "cannot parse long from string \'" + s + "\'";
684 int errorId = RtmAllocateError(errorMessage.Chars());
685 return Result<long>(ErrorId(errorId));
686 }
687 return Result<long>(0);
688 }
689
690 public bool ParseULong(const string& s, ulong& x)
691 {
692 return ParseUnsigned<ulong>(s, x);
693 }
694
695 [nodiscard]
696 public Result<ulong> ParseULong(const string& s)
697 {
698 ulong x;
699 if (ParseULong(s, x))
700 {
701 return Result<ulong>(x);
702 }
703 else
704 {
705 string errorMessage = "cannot parse ulong from string \'" + s + "\'";
706 int errorId = RtmAllocateError(errorMessage.Chars());
707 return Result<ulong>(ErrorId(errorId));
708 }
709 return Result<ulong>(0u);
710 }
711
712 public bool ParseFloat(const string& s, float& x)
713 {
714 return ParseFloating<float>(s, x);
715 }
716
717 [nodiscard]
718 public Result<float> ParseFloat(const string& s)
719 {
720 float x;
721 if (ParseFloat(s, x))
722 {
723 return Result<float>(x);
724 }
725 else
726 {
727 string errorMessage = "cannot parse float from string \'" + s + "\'";
728 int errorId = RtmAllocateError(errorMessage.Chars());
729 return Result<float>(ErrorId(errorId));
730 }
731 return Result<float>(0.000000f);
732 }
733
734 public bool ParseDouble(const string& s, double& x)
735 {
736 return ParseFloating<double>(s, x);
737 }
738
739 [nodiscard]
740 public Result<double> ParseDouble(const string& s)
741 {
742 double x;
743 if (ParseDouble(s, x))
744 {
745 return Result<double>(x);
746 }
747 else
748 {
749 string errorMessage = "cannot parse double from string \'" + s + "\'";
750 int errorId = RtmAllocateError(errorMessage.Chars());
751 return Result<double>(ErrorId(errorId));
752 }
753 return Result<double>(0.000000);
754 }
755
756 public bool ParseBool(const string& s, bool& x)
757 {
758 if (s == "true")
759 {
760 x = true;
761 return true;
762 }
763 else if (s == "false")
764 {
765 x = false;
766 return true;
767 }
768 else
769 {
770 x = false;
771 return false;
772 }
773 }
774
775 [nodiscard]
776 public Result<bool> ParseBool(const string& s)
777 {
778 bool x;
779 if (ParseBool(s, x))
780 {
781 return Result<bool>(x);
782 }
783 else
784 {
785 string errorMessage = "cannot parse bool from string \'" + s + "\'";
786 int errorId = RtmAllocateError(errorMessage.Chars());
787 return Result<bool>(ErrorId(errorId));
788 }
789 return Result<bool>(false);
790 }
791
792 public bool ParseHexByte(const string& s, byte& x)
793 {
794 return ParseHex<byte>(s, x);
795 }
796
797 [nodiscard]
798 public Result<byte> ParseHexByte(const string& s)
799 {
800 byte x;
801 if (ParseHexByte(s, x))
802 {
803 return Result<byte>(x);
804 }
805 else
806 {
807 string errorMessage = "cannot parse hex byte from string \'" + s + "\'";
808 int errorId = RtmAllocateError(errorMessage.Chars());
809 return Result<byte>(ErrorId(errorId));
810 }
811 return Result<byte>(0u);
812 }
813
814 public bool ParseHexUShort(const string& s, ushort& x)
815 {
816 return ParseHex<ushort>(s, x);
817 }
818
819 [nodiscard]
820 public Result<ushort> ParseHexUShort(const string& s)
821 {
822 ushort x;
823 if (ParseHexUShort(s, x))
824 {
825 return Result<ushort>(x);
826 }
827 else
828 {
829 string errorMessage = "cannot parse hex ushort from string \'" + s + "\'";
830 int errorId = RtmAllocateError(errorMessage.Chars());
831 return Result<ushort>(ErrorId(errorId));
832 }
833 return Result<ushort>(0u);
834 }
835
836 public bool ParseHexUInt(const string& s, uint& x)
837 {
838 return ParseHex<uint>(s, x);
839 }
840
841 [nodiscard]
842 public Result<uint> ParseHexUInt(const string& s)
843 {
844 uint x;
845 if (ParseHexUInt(s, x))
846 {
847 return Result<uint>(x);
848 }
849 else
850 {
851 string errorMessage = "cannot parse hex uint from string \'" + s + "\'";
852 int errorId = RtmAllocateError(errorMessage.Chars());
853 return Result<uint>(ErrorId(errorId));
854 }
855 return Result<uint>(0u);
856 }
857
858 public bool ParseHexULong(const string& s, ulong& x)
859 {
860 return ParseHex<ulong>(s, x);
861 }
862
863 [nodiscard]
864 public Result<ulong> ParseHexULong(const string& s)
865 {
866 ulong x;
867 if (ParseHexULong(s, x))
868 {
869 return Result<ulong>(x);
870 }
871 else
872 {
873 string errorMessage = "cannot parse hex ulong from string \'" + s + "\'";
874 int errorId = RtmAllocateError(errorMessage.Chars());
875 return Result<ulong>(ErrorId(errorId));
876 }
877 return Result<ulong>(0u);
878 }
879
880 public bool ParseOctal(const string& s, ulong& x)
881 {
882 x = 0u;
883 for (char c : s)
884 {
885 if (c >= '0' && c <= '7')
886 {
887 x = 8u * x + cast<ulong>(cast<int>(c) - cast<int>('0'));
888 }
889 else
890 {
891 return false;
892 }
893 }
894 return true;
895 }
896
897 [nodiscard]
898 public Result<ulong> ParseOctal(const string& s)
899 {
900 ulong x = 0u;
901 if (ParseOctal(s, x))
902 {
903 return Result<ulong>(x);
904 }
905 else
906 {
907 string errorMessage = "cannot parse octal from string \'" + s + "\'";
908 int errorId = RtmAllocateError(errorMessage.Chars());
909 return Result<ulong>(ErrorId(errorId));
910 }
911 return Result<ulong>(0u);
912 }
913
914 public bool ParseDate(const string& dateStr, Date& date)
915 {
916 int dateEnd = 0;
917 return ParseDate(dateStr, date, dateEnd);
918 }
919
920 public bool ParseDate(const string& dateStr, Date& date, int& dateEnd)
921 {
922 short year;
923 if (dateStr.Length() < 4 + 2 + 2)
924 {
925 return false;
926 }
927 if (!ParseShort(dateStr.Substring(0, 4), year))
928 {
929 return false;
930 }
931 int monthStart = 4;
932 if (dateStr[4] == '-')
933 {
934 ++monthStart;
935 }
936 if (dateStr.Length() < monthStart + 2)
937 {
938 return false;
939 }
940 sbyte month;
941 if (!ParseSByte(dateStr.Substring(monthStart, 2), month))
942 {
943 return false;
944 }
945 if (month < 1 || month > 12)
946 {
947 return false;
948 }
949 int dayStart = monthStart + 2;
950 if (dateStr[dayStart] == '-')
951 {
952 ++dayStart;
953 }
954 if (dateStr.Length() < dayStart + 2)
955 {
956 return false;
957 }
958 sbyte day;
959 if (!ParseSByte(dateStr.Substring(dayStart, 2), day))
960 {
961 return false;
962 }
963 if (day < 1 || day > 31)
964 {
965 return false;
966 }
967 dateEnd = dayStart + 2;
968 date = Date(year, cast<Month>(month), day);
969 return true;
970 }
971
972 [nodiscard]
973 public Result<Date> ParseDate(const string& s)
974 {
975 Date date;
976 if (!ParseDate(s, date))
977 {
978 string errorMessage = "cannot parse date from string \'" + s + "\': not in format YYYY-MM-DD or YYYYMMDD";
979 int errorId = RtmAllocateError(errorMessage.Chars());
980 return Result<Date>(ErrorId(errorId));
981 }
982 return Result<Date>(date);
983 }
984
985 public bool ParseDateTime(const string& dateTimeStr, DateTime& dateTime)
986 {
987 Date date;
988 int dateEnd = 0;
989 if (!ParseDate(dateTimeStr, date, dateEnd))
990 {
991 return false;
992 }
993 int hours = 0;
994 int mins = 0;
995 int secs = 0;
996 if (dateTimeStr.Length() > dateEnd)
997 {
998 if (dateTimeStr[dateEnd] == 'T')
999 {
1000 int hoursStart = dateEnd + 1;
1001 if (!ParseInt(dateTimeStr.Substring(hoursStart, 2), hours))
1002 {
1003 return false;
1004 }
1005 if (hours < 0 || hours > 24)
1006 {
1007 return false;
1008 }
1009 if (dateTimeStr.Length() > hoursStart + 2)
1010 {
1011 int minsStart = hoursStart + 2;
1012 if (dateTimeStr[minsStart] == ':')
1013 {
1014 ++minsStart;
1015 }
1016 if (!ParseInt(dateTimeStr.Substring(minsStart, 2), mins))
1017 {
1018 return false;
1019 }
1020 if (mins < 0 || mins >= 60)
1021 {
1022 return false;
1023 }
1024 if (dateTimeStr.Length() > minsStart + 2)
1025 {
1026 int secsStart = minsStart + 2;
1027 if (dateTimeStr[secsStart] == ':')
1028 {
1029 ++secsStart;
1030 }
1031 if (!ParseInt(dateTimeStr.Substring(secsStart, 2), secs))
1032 {
1033 return false;
1034 }
1035 if (secs < 0 || secs > 60)
1036 {
1037 return false;
1038 }
1039 }
1040 }
1041 }
1042 }
1043 int totalSecs = hours * 3600 + mins * 60 + secs;
1044 dateTime = DateTime(date, totalSecs);
1045 return true;
1046 }
1047
1048 [nodiscard]
1049 public Result<DateTime> ParseDateTime(const string& s)
1050 {
1051 DateTime dateTime;
1052 if (!ParseDateTime(s, dateTime))
1053 {
1054 string errorMessage = "cannot parse date time from string \'" + s + "\': not in format YYYY[-]MM[-]DD or YYYY[-]MM[-]DDTHH[[:]MM[[:]SS]]";
1055 int errorId = RtmAllocateError(errorMessage.Chars());
1056 return Result<DateTime>(ErrorId(errorId));
1057 }
1058 return Result<DateTime>(dateTime);
1059 }