| 911 | } // namespace |
| 912 | |
| 913 | Timestamp fromTimestampString(const char* str, size_t len, bool* nullOutput) { |
| 914 | size_t pos; |
| 915 | int64_t daysSinceEpoch; |
| 916 | int64_t microsSinceMidnight; |
| 917 | |
| 918 | auto result = tryParseDateString( |
| 919 | str, |
| 920 | len, |
| 921 | pos, |
| 922 | daysSinceEpoch, |
| 923 | #ifndef SPARK_COMPATIBLE |
| 924 | ParseMode::kNonStrict); |
| 925 | #else |
| 926 | ParseMode::kNonStrict | ParseMode::kNonStandardCast); |
| 927 | #endif |
| 928 | if (result != DateParseResult::kSuccess) { |
| 929 | if (nullOutput != nullptr) { |
| 930 | *nullOutput = true; |
| 931 | return Timestamp{}; |
| 932 | } else { |
| 933 | parserError(str, len); |
| 934 | } |
| 935 | } |
| 936 | |
| 937 | if (pos == len) { |
| 938 | // No time: only a date. |
| 939 | return fromDatetime(daysSinceEpoch, 0); |
| 940 | } |
| 941 | |
| 942 | // Try to parse a time field. |
| 943 | if (str[pos] == ' ' || str[pos] == 'T') { |
| 944 | pos++; |
| 945 | } |
| 946 | |
| 947 | size_t timePos = 0; |
| 948 | if (!tryParseTimeString( |
| 949 | str + pos, |
| 950 | len - pos, |
| 951 | timePos, |
| 952 | microsSinceMidnight, |
| 953 | #ifndef SPARK_COMPATIBLE |
| 954 | ParseMode::kNonStrict)) { |
| 955 | #else |
| 956 | ParseMode::kNonStrict | ParseMode::kNonStandardCast)) { |
| 957 | #endif |
| 958 | if (nullOutput != nullptr) { |
| 959 | *nullOutput = true; |
| 960 | return Timestamp{}; |
| 961 | } else { |
| 962 | parserError(str, len); |
| 963 | } |
| 964 | } |
| 965 | |
| 966 | pos += timePos; |
| 967 | auto timestamp = fromDatetime(daysSinceEpoch, microsSinceMidnight); |
| 968 | |
| 969 | if (pos < len) { |
| 970 | // Skip a "Z" at the end (as per the ISO 8601 specs). |
nothing calls this directly
no test coverage detected