// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; namespace System.Buffers.Text { public static partial class Utf8Parser { // // Roundtrippable format. One of // // 012345678901234567890123456789012 // --------------------------------- // 2017-06-12T05:30:45.7680000-07:00 // 2017-06-12T05:30:45.7680000Z (Z is short for "+00:00" but also distinguishes DateTimeKind.Utc from DateTimeKind.Local) // 2017-06-12T05:30:45.7680000 (interpreted as local time wrt to current time zone) // private static bool TryParseDateTimeOffsetO(ReadOnlySpan<byte> source, out DateTimeOffset value, out int bytesConsumed, out DateTimeKind kind) { if (source.Length < 27) { value = default; bytesConsumed = 0; kind = default; return false; } int year; { uint digit1 = source[0] - 48u; // '0' uint digit2 = source[1] - 48u; // '0' uint digit3 = source[2] - 48u; // '0' uint digit4 = source[3] - 48u; // '0' if (digit1 > 9 || digit2 > 9 || digit3 > 9 || digit4 > 9) { value = default; bytesConsumed = 0; kind = default; return false; } year = (int)(digit1 * 1000 + digit2 * 100 + digit3 * 10 + digit4); } if (source[4] != Utf8Constants.Hyphen) { value = default; bytesConsumed = 0; kind = default; return false; } int month; { uint digit1 = source[5] - 48u; // '0' uint digit2 = source[6] - 48u; // '0' if (digit1 > 9 || digit2 > 9) { value = default; bytesConsumed = 0; kind = default; return false; } month = (int)(digit1 * 10 + digit2); } if (source[7] != Utf8Constants.Hyphen) { value = default; bytesConsumed = 0; kind = default; return false; } int day; { uint digit1 = source[8] - 48u; // '0' uint digit2 = source[9] - 48u; // '0' if (digit1 > 9 || digit2 > 9) { value = default; bytesConsumed = 0; kind = default; return false; } day = (int)(digit1 * 10 + digit2); } if (source[10] != 'T') { value = default; bytesConsumed = 0; kind = default; return false; } int hour; { uint digit1 = source[11] - 48u; // '0' uint digit2 = source[12] - 48u; // '0' if (digit1 > 9 || digit2 > 9) { value = default; bytesConsumed = 0; kind = default; return false; } hour = (int)(digit1 * 10 + digit2); } if (source[13] != Utf8Constants.Colon) { value = default; bytesConsumed = 0; kind = default; return false; } int minute; { uint digit1 = source[14] - 48u; // '0' uint digit2 = source[15] - 48u; // '0' if (digit1 > 9 || digit2 > 9) { value = default; bytesConsumed = 0; kind = default; return false; } minute = (int)(digit1 * 10 + digit2); } if (source[16] != Utf8Constants.Colon) { value = default; bytesConsumed = 0; kind = default; return false; } int second; { uint digit1 = source[17] - 48u; // '0' uint digit2 = source[18] - 48u; // '0' if (digit1 > 9 || digit2 > 9) { value = default; bytesConsumed = 0; kind = default; return false; } second = (int)(digit1 * 10 + digit2); } if (source[19] != Utf8Constants.Period) { value = default; bytesConsumed = 0; kind = default; return false; } int fraction; { uint digit1 = source[20] - 48u; // '0' uint digit2 = source[21] - 48u; // '0' uint digit3 = source[22] - 48u; // '0' uint digit4 = source[23] - 48u; // '0' uint digit5 = source[24] - 48u; // '0' uint digit6 = source[25] - 48u; // '0' uint digit7 = source[26] - 48u; // '0' if (digit1 > 9 || digit2 > 9 || digit3 > 9 || digit4 > 9 || digit5 > 9 || digit6 > 9 || digit7 > 9) { value = default; bytesConsumed = 0; kind = default; return false; } fraction = (int)(digit1 * 1000000 + digit2 * 100000 + digit3 * 10000 + digit4 * 1000 + digit5 * 100 + digit6 * 10 + digit7); } byte offsetChar = (source.Length <= 27) ? default : source[27]; if (offsetChar != 'Z' && offsetChar != Utf8Constants.Plus && offsetChar != Utf8Constants.Minus) { if (!TryCreateDateTimeOffsetInterpretingDataAsLocalTime(year: year, month: month, day: day, hour: hour, minute: minute, second: second, fraction: fraction, out value)) { value = default; bytesConsumed = 0; kind = default; return false; } bytesConsumed = 27; kind = DateTimeKind.Unspecified; return true; } if (offsetChar == 'Z') { // Same as specifying an offset of "+00:00", except that DateTime's Kind gets set to UTC rather than Local if (!TryCreateDateTimeOffset(year: year, month: month, day: day, hour: hour, minute: minute, second: second, fraction: fraction, offsetNegative: false, offsetHours: 0, offsetMinutes: 0, out value)) { value = default; bytesConsumed = 0; kind = default; return false; } bytesConsumed = 28; kind = DateTimeKind.Utc; return true; } Debug.Assert(offsetChar == Utf8Constants.Plus || offsetChar == Utf8Constants.Minus); if (source.Length < 33) { value = default; bytesConsumed = 0; kind = default; return false; } int offsetHours; { uint digit1 = source[28] - 48u; // '0' uint digit2 = source[29] - 48u; // '0' if (digit1 > 9 || digit2 > 9) { value = default; bytesConsumed = 0; kind = default; return false; } offsetHours = (int)(digit1 * 10 + digit2); } if (source[30] != Utf8Constants.Colon) { value = default; bytesConsumed = 0; kind = default; return false; } int offsetMinutes; { uint digit1 = source[31] - 48u; // '0' uint digit2 = source[32] - 48u; // '0' if (digit1 > 9 || digit2 > 9) { value = default; bytesConsumed = 0; kind = default; return false; } offsetMinutes = (int)(digit1 * 10 + digit2); } if (!TryCreateDateTimeOffset(year: year, month: month, day: day, hour: hour, minute: minute, second: second, fraction: fraction, offsetNegative: offsetChar == Utf8Constants.Minus, offsetHours: offsetHours, offsetMinutes: offsetMinutes, out value)) { value = default; bytesConsumed = 0; kind = default; return false; } bytesConsumed = 33; kind = DateTimeKind.Local; return true; } } } |