1 // =================================
   2 // Copyright (c) 2024 Seppo Laakko
   3 // Distributed under the MIT license
   4 // =================================
   5 
   6 using System.Concepts;
   7 
   8 namespace System
   9 {
  10     public string ToString<IU>(I x) where I is SignedInteger and U is UnsignedInteger and ExplicitlyConvertible<IU> and ExplicitlyConvertible<Ubyte>
  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<Ubyte>
  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<intuint>(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<longulong>(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(f15);
  93     }
  94 
  95     public string ToString(float fint maxNumDecimals)
  96     {
  97         return ToString<float>(f0maxNumDecimals);
  98     }
  99 
 100     public string ToString(double xint maxNumDecimals)
 101     {
 102         return ToString<double>(x0maxNumDecimals);
 103     }
 104 
 105     public string ToString(double x)
 106     {
 107         return ToString(x15);
 108     }
 109 
 110     public string ToString<T>(T xint minNumDecimalsint 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<Ubyte>
 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(x0);
 251     }
 252 
 253     [nodiscard]
 254     public Result<string> ToOctalString(ulong xint 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& sT& 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& sT& 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& sT& 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& sT& 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.000000exponent));
 532         }
 533         return true;
 534     }
 535 
 536     public bool ParseSByte(const string& ssbyte& x)
 537     {
 538         return ParseSigned<sbyte>(sx);
 539     }
 540 
 541     [nodiscard]
 542     public Result<sbyte> ParseSByte(const string& s)
 543     {
 544         sbyte x;
 545         if (ParseSByte(sx))
 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& sbyte& x)
 559     {
 560         return ParseUnsigned<byte>(sx);
 561     }
 562 
 563     [nodiscard]
 564     public Result<byte> ParseByte(const string& s)
 565     {
 566         byte x;
 567         if (ParseByte(sx))
 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& sshort& x)
 581     {
 582         return ParseSigned<short>(sx);
 583     }
 584 
 585     [nodiscard]
 586     public Result<short> ParseShort(const string& s)
 587     {
 588         short x;
 589         if (ParseShort(sx))
 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& sushort& x)
 603     {
 604         return ParseUnsigned<ushort>(sx);
 605     }
 606 
 607     [nodiscard]
 608     public Result<ushort> ParseUShort(const string& s)
 609     {
 610         ushort x;
 611         if (ParseUShort(sx))
 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& sint& x)
 625     {
 626         return ParseSigned<int>(sx);
 627     }
 628 
 629     [nodiscard]
 630     public Result<int> ParseInt(const string& s)
 631     {
 632         int x;
 633         if (ParseInt(sx))
 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& suint& x)
 647     {
 648         return ParseUnsigned<uint>(sx);
 649     }
 650 
 651     [nodiscard]
 652     public Result<uint> ParseUInt(const string& s)
 653     {
 654         uint x;
 655         if (ParseUInt(sx))
 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& slong& x)
 669     {
 670         return ParseSigned<long>(sx);
 671     }
 672 
 673     [nodiscard]
 674     public Result<long> ParseLong(const string& s)
 675     {
 676         long x;
 677         if (ParseLong(sx))
 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& sulong& x)
 691     {
 692         return ParseUnsigned<ulong>(sx);
 693     }
 694 
 695     [nodiscard]
 696     public Result<ulong> ParseULong(const string& s)
 697     {
 698         ulong x;
 699         if (ParseULong(sx))
 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& sfloat& x)
 713     {
 714         return ParseFloating<float>(sx);
 715     }
 716 
 717     [nodiscard]
 718     public Result<float> ParseFloat(const string& s)
 719     {
 720         float x;
 721         if (ParseFloat(sx))
 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& sdouble& x)
 735     {
 736         return ParseFloating<double>(sx);
 737     }
 738 
 739     [nodiscard]
 740     public Result<double> ParseDouble(const string& s)
 741     {
 742         double x;
 743         if (ParseDouble(sx))
 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& sbool& 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(sx))
 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& sbyte& x)
 793     {
 794         return ParseHex<byte>(sx);
 795     }
 796 
 797     [nodiscard]
 798     public Result<byte> ParseHexByte(const string& s)
 799     {
 800         byte x;
 801         if (ParseHexByte(sx))
 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& sushort& x)
 815     {
 816         return ParseHex<ushort>(sx);
 817     }
 818 
 819     [nodiscard]
 820     public Result<ushort> ParseHexUShort(const string& s)
 821     {
 822         ushort x;
 823         if (ParseHexUShort(sx))
 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& suint& x)
 837     {
 838         return ParseHex<uint>(sx);
 839     }
 840 
 841     [nodiscard]
 842     public Result<uint> ParseHexUInt(const string& s)
 843     {
 844         uint x;
 845         if (ParseHexUInt(sx))
 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& sulong& x)
 859     {
 860         return ParseHex<ulong>(sx);
 861     }
 862 
 863     [nodiscard]
 864     public Result<ulong> ParseHexULong(const string& s)
 865     {
 866         ulong x;
 867         if (ParseHexULong(sx))
 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& sulong& 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(sx))
 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& dateStrDate& date)
 915     {
 916         int dateEnd = 0;
 917         return ParseDate(dateStrdatedateEnd);
 918     }
 919 
 920     public bool ParseDate(const string& dateStrDate& dateint& dateEnd)
 921     {
 922         short year;
 923         if (dateStr.Length() < 4 + 2 + 2)
 924         {
 925             return false;
 926         }
 927         if (!ParseShort(dateStr.Substring(04)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(monthStart2)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(dayStart2)day))
 960         {
 961             return false;
 962         }
 963         if (day < 1 || day > 31)
 964         {
 965             return false;
 966         }
 967         dateEnd = dayStart + 2;
 968         date = Date(yearcast<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(sdate))
 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& dateTimeStrDateTime& dateTime)
 986     {
 987         Date date;
 988         int dateEnd = 0;
 989         if (!ParseDate(dateTimeStrdatedateEnd))
 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(hoursStart2)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(minsStart2)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(secsStart2)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(datetotalSecs);
1045         return true;
1046     }
1047 
1048     [nodiscard]
1049     public Result<DateTime> ParseDateTime(const string& s)
1050     {
1051         DateTime dateTime;
1052         if (!ParseDateTime(sdateTime))
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     }