Skip to main content

arrow_cast/
parse.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! [`Parser`] implementations for converting strings to Arrow types
19//!
20//! Used by the CSV and JSON readers to convert strings to Arrow types
21use arrow_array::ArrowNativeTypeOp;
22use arrow_array::timezone::Tz;
23use arrow_array::types::*;
24use arrow_buffer::ArrowNativeType;
25use arrow_schema::ArrowError;
26use chrono::prelude::*;
27use half::f16;
28use std::str::FromStr;
29
30/// Parse nanoseconds from the first `N` values in digits, subtracting the offset `O`
31#[inline]
32fn parse_nanos<const N: usize, const O: u8>(digits: &[u8]) -> u32 {
33    digits[..N]
34        .iter()
35        .fold(0_u32, |acc, v| acc * 10 + v.wrapping_sub(O) as u32)
36        * 10_u32.pow((9 - N) as _)
37}
38
39/// Helper for parsing RFC3339 timestamps
40struct TimestampParser {
41    /// The timestamp bytes to parse minus `b'0'`
42    ///
43    /// This makes interpretation as an integer inexpensive
44    digits: [u8; 32],
45    /// A mask containing a `1` bit where the corresponding byte is a valid ASCII digit
46    mask: u32,
47}
48
49impl TimestampParser {
50    fn new(bytes: &[u8]) -> Self {
51        let mut digits = [0; 32];
52        let mut mask = 0;
53
54        // Treating all bytes the same way, helps LLVM vectorise this correctly
55        for (idx, (o, i)) in digits.iter_mut().zip(bytes).enumerate() {
56            *o = i.wrapping_sub(b'0');
57            mask |= ((*o < 10) as u32) << idx
58        }
59
60        Self { digits, mask }
61    }
62
63    /// Returns true if the byte at `idx` in the original string equals `b`
64    fn test(&self, idx: usize, b: u8) -> bool {
65        self.digits[idx] == b.wrapping_sub(b'0')
66    }
67
68    /// Parses a date of the form `1997-01-31`
69    fn date(&self) -> Option<NaiveDate> {
70        if self.mask & 0b1111111111 != 0b1101101111 || !self.test(4, b'-') || !self.test(7, b'-') {
71            return None;
72        }
73
74        let year = self.digits[0] as u16 * 1000
75            + self.digits[1] as u16 * 100
76            + self.digits[2] as u16 * 10
77            + self.digits[3] as u16;
78
79        let month = self.digits[5] * 10 + self.digits[6];
80        let day = self.digits[8] * 10 + self.digits[9];
81
82        NaiveDate::from_ymd_opt(year as _, month as _, day as _)
83    }
84
85    /// Parses a time of any of forms
86    /// - `09:26:56`
87    /// - `09:26:56.123`
88    /// - `09:26:56.123456`
89    /// - `09:26:56.123456789`
90    /// - `092656`
91    ///
92    /// Returning the end byte offset
93    fn time(&self) -> Option<(NaiveTime, usize)> {
94        // Make a NaiveTime handling leap seconds
95        let time = |hour, min, sec, nano| match sec {
96            60 => {
97                let nano = 1_000_000_000 + nano;
98                NaiveTime::from_hms_nano_opt(hour as _, min as _, 59, nano)
99            }
100            _ => NaiveTime::from_hms_nano_opt(hour as _, min as _, sec as _, nano),
101        };
102
103        match (self.mask >> 11) & 0b11111111 {
104            // 09:26:56
105            0b11011011 if self.test(13, b':') && self.test(16, b':') => {
106                let hour = self.digits[11] * 10 + self.digits[12];
107                let minute = self.digits[14] * 10 + self.digits[15];
108                let second = self.digits[17] * 10 + self.digits[18];
109
110                match self.test(19, b'.') {
111                    true => {
112                        let digits = (self.mask >> 20).trailing_ones();
113                        let nanos = match digits {
114                            0 => return None,
115                            1 => parse_nanos::<1, 0>(&self.digits[20..21]),
116                            2 => parse_nanos::<2, 0>(&self.digits[20..22]),
117                            3 => parse_nanos::<3, 0>(&self.digits[20..23]),
118                            4 => parse_nanos::<4, 0>(&self.digits[20..24]),
119                            5 => parse_nanos::<5, 0>(&self.digits[20..25]),
120                            6 => parse_nanos::<6, 0>(&self.digits[20..26]),
121                            7 => parse_nanos::<7, 0>(&self.digits[20..27]),
122                            8 => parse_nanos::<8, 0>(&self.digits[20..28]),
123                            _ => parse_nanos::<9, 0>(&self.digits[20..29]),
124                        };
125                        Some((time(hour, minute, second, nanos)?, 20 + digits as usize))
126                    }
127                    false => Some((time(hour, minute, second, 0)?, 19)),
128                }
129            }
130            // 092656
131            0b111111 => {
132                let hour = self.digits[11] * 10 + self.digits[12];
133                let minute = self.digits[13] * 10 + self.digits[14];
134                let second = self.digits[15] * 10 + self.digits[16];
135                let time = time(hour, minute, second, 0)?;
136                Some((time, 17))
137            }
138            _ => None,
139        }
140    }
141}
142
143/// Accepts a string and parses it relative to the provided `timezone`
144///
145/// In addition to RFC3339 / ISO8601 standard timestamps, it also
146/// accepts strings that use a space ` ` to separate the date and time
147/// as well as strings that have no explicit timezone offset.
148///
149/// Examples of accepted inputs:
150/// * `1997-01-31T09:26:56.123Z`        # RCF3339
151/// * `1997-01-31T09:26:56.123-05:00`   # RCF3339
152/// * `1997-01-31 09:26:56.123-05:00`   # close to RCF3339 but with a space rather than T
153/// * `2023-01-01 04:05:06.789 -08`     # close to RCF3339, no fractional seconds or time separator
154/// * `1997-01-31T09:26:56.123`         # close to RCF3339 but no timezone offset specified
155/// * `1997-01-31 09:26:56.123`         # close to RCF3339 but uses a space and no timezone offset
156/// * `1997-01-31 09:26:56`             # close to RCF3339, no fractional seconds
157/// * `1997-01-31 092656`               # close to RCF3339, no fractional seconds
158/// * `1997-01-31 092656+04:00`         # close to RCF3339, no fractional seconds or time separator
159/// * `1997-01-31`                      # close to RCF3339, only date no time
160///
161/// [IANA timezones] are only supported if the `arrow-array/chrono-tz` feature is enabled
162///
163/// * `2023-01-01 040506 America/Los_Angeles`
164///
165/// If a timestamp is ambiguous, for example as a result of daylight-savings time, an error
166/// will be returned
167///
168/// Some formats supported by PostgresSql <https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-DATETIME-TIME-TABLE>
169/// are not supported, like
170///
171/// * "2023-01-01 04:05:06.789 +07:30:00",
172/// * "2023-01-01 040506 +07:30:00",
173/// * "2023-01-01 04:05:06.789 PST",
174///
175/// [IANA timezones]: https://www.iana.org/time-zones
176pub fn string_to_datetime<T: TimeZone>(timezone: &T, s: &str) -> Result<DateTime<T>, ArrowError> {
177    let err =
178        |ctx: &str| ArrowError::ParseError(format!("Error parsing timestamp from '{s}': {ctx}"));
179
180    let bytes = s.as_bytes();
181    if bytes.len() < 10 {
182        return Err(err("timestamp must contain at least 10 characters"));
183    }
184
185    let parser = TimestampParser::new(bytes);
186    let date = parser.date().ok_or_else(|| err("error parsing date"))?;
187    if bytes.len() == 10 {
188        let datetime = date.and_time(NaiveTime::from_hms_opt(0, 0, 0).unwrap());
189        return timezone
190            .from_local_datetime(&datetime)
191            .single()
192            .ok_or_else(|| err("error computing timezone offset"));
193    }
194
195    if !parser.test(10, b'T') && !parser.test(10, b't') && !parser.test(10, b' ') {
196        return Err(err("invalid timestamp separator"));
197    }
198
199    let (time, mut tz_offset) = parser.time().ok_or_else(|| err("error parsing time"))?;
200    let datetime = date.and_time(time);
201
202    if tz_offset == 32 {
203        // Decimal overrun
204        while tz_offset < bytes.len() && bytes[tz_offset].is_ascii_digit() {
205            tz_offset += 1;
206        }
207    }
208
209    if bytes.len() <= tz_offset {
210        return timezone
211            .from_local_datetime(&datetime)
212            .single()
213            .ok_or_else(|| err("error computing timezone offset"));
214    }
215
216    if (bytes[tz_offset] == b'z' || bytes[tz_offset] == b'Z') && tz_offset == bytes.len() - 1 {
217        return Ok(timezone.from_utc_datetime(&datetime));
218    }
219
220    // Parse remainder of string as timezone
221    let parsed_tz: Tz = s[tz_offset..].trim_start().parse()?;
222    let parsed = parsed_tz
223        .from_local_datetime(&datetime)
224        .single()
225        .ok_or_else(|| err("error computing timezone offset"))?;
226
227    Ok(parsed.with_timezone(timezone))
228}
229
230/// Accepts a string in RFC3339 / ISO8601 standard format and some
231/// variants and converts it to a nanosecond precision timestamp.
232///
233/// See [`string_to_datetime`] for the full set of supported formats
234///
235/// Implements the `to_timestamp` function to convert a string to a
236/// timestamp, following the model of spark SQL’s to_`timestamp`.
237///
238/// Internally, this function uses the `chrono` library for the
239/// datetime parsing
240///
241/// We hope to extend this function in the future with a second
242/// parameter to specifying the format string.
243///
244/// ## Timestamp Precision
245///
246/// Function uses the maximum precision timestamps supported by
247/// Arrow (nanoseconds stored as a 64-bit integer) timestamps. This
248/// means the range of dates that timestamps can represent is ~1677 AD
249/// to 2262 AM
250///
251/// ## Timezone / Offset Handling
252///
253/// Numerical values of timestamps are stored compared to offset UTC.
254///
255/// This function interprets string without an explicit time zone as timestamps
256/// relative to UTC, see [`string_to_datetime`] for alternative semantics
257///
258/// In particular:
259///
260/// ```
261/// # use arrow_cast::parse::string_to_timestamp_nanos;
262/// // Note all three of these timestamps are parsed as the same value
263/// let a = string_to_timestamp_nanos("1997-01-31 09:26:56.123Z").unwrap();
264/// let b = string_to_timestamp_nanos("1997-01-31T09:26:56.123").unwrap();
265/// let c = string_to_timestamp_nanos("1997-01-31T14:26:56.123+05:00").unwrap();
266///
267/// assert_eq!(a, b);
268/// assert_eq!(b, c);
269/// ```
270///
271#[inline]
272pub fn string_to_timestamp_nanos(s: &str) -> Result<i64, ArrowError> {
273    to_timestamp_nanos(string_to_datetime(&Utc, s)?.naive_utc())
274}
275
276/// Fallible conversion of [`NaiveDateTime`] to `i64` nanoseconds
277#[inline]
278fn to_timestamp_nanos(dt: NaiveDateTime) -> Result<i64, ArrowError> {
279    dt.and_utc()
280        .timestamp_nanos_opt()
281        .ok_or_else(|| ArrowError::ParseError(ERR_NANOSECONDS_NOT_SUPPORTED.to_string()))
282}
283
284/// Accepts a string in ISO8601 standard format and some
285/// variants and converts it to nanoseconds since midnight.
286///
287/// Examples of accepted inputs:
288///
289/// * `09:26:56.123 AM`
290/// * `23:59:59`
291/// * `6:00 pm`
292///
293/// Internally, this function uses the `chrono` library for the time parsing
294///
295/// ## Timezone / Offset Handling
296///
297/// This function does not support parsing strings with a timezone
298/// or offset specified, as it considers only time since midnight.
299pub fn string_to_time_nanoseconds(s: &str) -> Result<i64, ArrowError> {
300    let nt = string_to_time(s)
301        .ok_or_else(|| ArrowError::ParseError(format!("Failed to parse \'{s}\' as time")))?;
302    Ok(nt.num_seconds_from_midnight() as i64 * 1_000_000_000 + nt.nanosecond() as i64)
303}
304
305fn string_to_time(s: &str) -> Option<NaiveTime> {
306    let bytes = s.as_bytes();
307    if bytes.len() < 4 {
308        return None;
309    }
310
311    let (am, bytes) = match bytes.get(bytes.len() - 3..) {
312        Some(b" AM" | b" am" | b" Am" | b" aM") => (Some(true), &bytes[..bytes.len() - 3]),
313        Some(b" PM" | b" pm" | b" pM" | b" Pm") => (Some(false), &bytes[..bytes.len() - 3]),
314        _ => (None, bytes),
315    };
316
317    if bytes.len() < 4 {
318        return None;
319    }
320
321    let mut digits = [b'0'; 6];
322
323    // Extract hour
324    let bytes = match (bytes[1], bytes[2]) {
325        (b':', _) => {
326            digits[1] = bytes[0];
327            &bytes[2..]
328        }
329        (_, b':') => {
330            digits[0] = bytes[0];
331            digits[1] = bytes[1];
332            &bytes[3..]
333        }
334        _ => return None,
335    };
336
337    if bytes.len() < 2 {
338        return None; // Minutes required
339    }
340
341    // Extract minutes
342    digits[2] = bytes[0];
343    digits[3] = bytes[1];
344
345    let nanoseconds = match bytes.get(2) {
346        Some(b':') => {
347            if bytes.len() < 5 {
348                return None;
349            }
350
351            // Extract seconds
352            digits[4] = bytes[3];
353            digits[5] = bytes[4];
354
355            // Extract sub-seconds if any
356            match bytes.get(5) {
357                Some(b'.') => {
358                    let decimal = &bytes[6..];
359                    if decimal.iter().any(|x| !x.is_ascii_digit()) {
360                        return None;
361                    }
362                    match decimal.len() {
363                        0 => return None,
364                        1 => parse_nanos::<1, b'0'>(decimal),
365                        2 => parse_nanos::<2, b'0'>(decimal),
366                        3 => parse_nanos::<3, b'0'>(decimal),
367                        4 => parse_nanos::<4, b'0'>(decimal),
368                        5 => parse_nanos::<5, b'0'>(decimal),
369                        6 => parse_nanos::<6, b'0'>(decimal),
370                        7 => parse_nanos::<7, b'0'>(decimal),
371                        8 => parse_nanos::<8, b'0'>(decimal),
372                        _ => parse_nanos::<9, b'0'>(decimal),
373                    }
374                }
375                Some(_) => return None,
376                None => 0,
377            }
378        }
379        Some(_) => return None,
380        None => 0,
381    };
382
383    digits.iter_mut().for_each(|x| *x = x.wrapping_sub(b'0'));
384    if digits.iter().any(|x| *x > 9) {
385        return None;
386    }
387
388    let hour = match (digits[0] * 10 + digits[1], am) {
389        (12, Some(true)) => 0,               // 12:00 AM -> 00:00
390        (h @ 1..=11, Some(true)) => h,       // 1:00 AM -> 01:00
391        (12, Some(false)) => 12,             // 12:00 PM -> 12:00
392        (h @ 1..=11, Some(false)) => h + 12, // 1:00 PM -> 13:00
393        (_, Some(_)) => return None,
394        (h, None) => h,
395    };
396
397    // Handle leap second
398    let (second, nanoseconds) = match digits[4] * 10 + digits[5] {
399        60 => (59, nanoseconds + 1_000_000_000),
400        s => (s, nanoseconds),
401    };
402
403    NaiveTime::from_hms_nano_opt(
404        hour as _,
405        (digits[2] * 10 + digits[3]) as _,
406        second as _,
407        nanoseconds,
408    )
409}
410
411/// Specialized parsing implementations to convert strings to Arrow types.
412///
413/// This is used by csv and json reader and can be used directly as well.
414///
415/// # Example
416///
417/// To parse a string to a [`Date32Type`]:
418///
419/// ```
420/// use arrow_cast::parse::Parser;
421/// use arrow_array::types::Date32Type;
422/// let date = Date32Type::parse("2021-01-01").unwrap();
423/// assert_eq!(date, 18628);
424/// ```
425///
426/// To parse a string to a [`TimestampNanosecondType`]:
427///
428/// ```
429/// use arrow_cast::parse::Parser;
430/// use arrow_array::types::TimestampNanosecondType;
431/// let ts = TimestampNanosecondType::parse("2021-01-01T00:00:00.123456789Z").unwrap();
432/// assert_eq!(ts, 1609459200123456789);
433/// ```
434pub trait Parser: ArrowPrimitiveType {
435    /// Parse a string to the native type
436    fn parse(string: &str) -> Option<Self::Native>;
437
438    /// Parse a string to the native type with a format string
439    ///
440    /// When not implemented, the format string is unused, and this method is equivalent to [parse](#tymethod.parse)
441    fn parse_formatted(string: &str, _format: &str) -> Option<Self::Native> {
442        Self::parse(string)
443    }
444}
445
446impl Parser for Float16Type {
447    fn parse(string: &str) -> Option<f16> {
448        if let Ok(raw_float) = lexical_core::parse(string.as_bytes()) {
449            return Some(f16::from_f32(raw_float));
450        }
451        let string = trim_pre_and_post_whitespace(string);
452        lexical_core::parse(string.as_bytes())
453            .ok()
454            .map(f16::from_f32)
455    }
456}
457
458impl Parser for Float32Type {
459    fn parse(string: &str) -> Option<f32> {
460        if let Ok(raw_float) = lexical_core::parse(string.as_bytes()) {
461            return Some(raw_float);
462        }
463        let string = trim_pre_and_post_whitespace(string);
464        lexical_core::parse(string.as_bytes()).ok()
465    }
466}
467
468impl Parser for Float64Type {
469    fn parse(string: &str) -> Option<f64> {
470        if let Ok(raw_float) = lexical_core::parse(string.as_bytes()) {
471            return Some(raw_float);
472        }
473        let string = trim_pre_and_post_whitespace(string);
474        lexical_core::parse(string.as_bytes()).ok()
475    }
476}
477
478/// this is a no-op if the string starts and ends with a digit, otherwise it will trim whitespace from the start and end of the string.
479#[inline]
480fn trim_pre_and_post_whitespace(string: &str) -> &str {
481    let bytes = string.as_bytes();
482    let prefix = bytes.first().is_some_and(|b| !b.is_ascii_digit());
483    let suffix = bytes.last().is_some_and(|b| !b.is_ascii_digit());
484    match (prefix, suffix) {
485        (false, false) => string,
486        (true, false) => string.trim_ascii_start(),
487        (false, true) => string.trim_ascii_end(),
488        (true, true) => string.trim_ascii(),
489    }
490}
491
492macro_rules! parser_primitive {
493    ($t:ty) => {
494        impl Parser for $t {
495            fn parse(string: &str) -> Option<Self::Native> {
496                let mut raw_bytes = string.as_bytes();
497                if !raw_bytes.last().is_some_and(|x| x.is_ascii_digit()) {
498                    raw_bytes = raw_bytes.trim_ascii_end();
499                    if !raw_bytes.last().is_some_and(|x| x.is_ascii_digit()) {
500                        return None;
501                    }
502                }
503                match atoi::FromRadix10SignedChecked::from_radix_10_signed_checked(raw_bytes) {
504                    (Some(n), x) if x == raw_bytes.len() => Some(n),
505                    _ => {
506                        let trimmed = raw_bytes.trim_ascii_start();
507                        match atoi::FromRadix10SignedChecked::from_radix_10_signed_checked(trimmed)
508                        {
509                            (Some(n), x) if x == trimmed.len() => Some(n),
510                            _ => None,
511                        }
512                    }
513                }
514            }
515        }
516    };
517}
518parser_primitive!(UInt64Type);
519parser_primitive!(UInt32Type);
520parser_primitive!(UInt16Type);
521parser_primitive!(UInt8Type);
522parser_primitive!(Int64Type);
523parser_primitive!(Int32Type);
524parser_primitive!(Int16Type);
525parser_primitive!(Int8Type);
526parser_primitive!(DurationNanosecondType);
527parser_primitive!(DurationMicrosecondType);
528parser_primitive!(DurationMillisecondType);
529parser_primitive!(DurationSecondType);
530
531impl Parser for TimestampNanosecondType {
532    fn parse(string: &str) -> Option<i64> {
533        string_to_timestamp_nanos(string).ok()
534    }
535}
536
537impl Parser for TimestampMicrosecondType {
538    fn parse(string: &str) -> Option<i64> {
539        let nanos = string_to_timestamp_nanos(string).ok();
540        nanos.map(|x| x / 1000)
541    }
542}
543
544impl Parser for TimestampMillisecondType {
545    fn parse(string: &str) -> Option<i64> {
546        let nanos = string_to_timestamp_nanos(string).ok();
547        nanos.map(|x| x / 1_000_000)
548    }
549}
550
551impl Parser for TimestampSecondType {
552    fn parse(string: &str) -> Option<i64> {
553        let nanos = string_to_timestamp_nanos(string).ok();
554        nanos.map(|x| x / 1_000_000_000)
555    }
556}
557
558impl Parser for Time64NanosecondType {
559    // Will truncate any fractions of a nanosecond
560    fn parse(string: &str) -> Option<Self::Native> {
561        string_to_time_nanoseconds(string)
562            .ok()
563            .or_else(|| string.parse::<Self::Native>().ok())
564    }
565
566    fn parse_formatted(string: &str, format: &str) -> Option<Self::Native> {
567        let nt = NaiveTime::parse_from_str(string, format).ok()?;
568        Some(nt.num_seconds_from_midnight() as i64 * 1_000_000_000 + nt.nanosecond() as i64)
569    }
570}
571
572impl Parser for Time64MicrosecondType {
573    // Will truncate any fractions of a microsecond
574    fn parse(string: &str) -> Option<Self::Native> {
575        string_to_time_nanoseconds(string)
576            .ok()
577            .map(|nanos| nanos / 1_000)
578            .or_else(|| string.parse::<Self::Native>().ok())
579    }
580
581    fn parse_formatted(string: &str, format: &str) -> Option<Self::Native> {
582        let nt = NaiveTime::parse_from_str(string, format).ok()?;
583        Some(nt.num_seconds_from_midnight() as i64 * 1_000_000 + nt.nanosecond() as i64 / 1_000)
584    }
585}
586
587impl Parser for Time32MillisecondType {
588    // Will truncate any fractions of a millisecond
589    fn parse(string: &str) -> Option<Self::Native> {
590        string_to_time_nanoseconds(string)
591            .ok()
592            .map(|nanos| (nanos / 1_000_000) as i32)
593            .or_else(|| string.parse::<Self::Native>().ok())
594    }
595
596    fn parse_formatted(string: &str, format: &str) -> Option<Self::Native> {
597        let nt = NaiveTime::parse_from_str(string, format).ok()?;
598        Some(nt.num_seconds_from_midnight() as i32 * 1_000 + nt.nanosecond() as i32 / 1_000_000)
599    }
600}
601
602impl Parser for Time32SecondType {
603    // Will truncate any fractions of a second
604    fn parse(string: &str) -> Option<Self::Native> {
605        string_to_time_nanoseconds(string)
606            .ok()
607            .map(|nanos| (nanos / 1_000_000_000) as i32)
608            .or_else(|| string.parse::<Self::Native>().ok())
609    }
610
611    fn parse_formatted(string: &str, format: &str) -> Option<Self::Native> {
612        let nt = NaiveTime::parse_from_str(string, format).ok()?;
613        Some(nt.num_seconds_from_midnight() as i32 + nt.nanosecond() as i32 / 1_000_000_000)
614    }
615}
616
617/// Number of days between 0001-01-01 and 1970-01-01
618const EPOCH_DAYS_FROM_CE: i32 = 719_163;
619
620/// Error message if nanosecond conversion request beyond supported interval
621const ERR_NANOSECONDS_NOT_SUPPORTED: &str = "The dates that can be represented as nanoseconds have to be between 1677-09-21T00:12:44.0 and 2262-04-11T23:47:16.854775804";
622
623/// Parse the ISO 8601 signed extended-year form (`±YYYY[Y...]-MM-DD`) into
624/// raw `(year, month, day)` components, without validating the calendar date.
625///
626/// The caller must have already verified that `string` begins with `+` or `-`;
627/// the year must have at least 4 digits. Returns `None` if the shape is
628/// malformed or any component fails to parse numerically.
629fn parse_extended_ymd(string: &str) -> Option<(i32, u32, u32)> {
630    debug_assert!(string.starts_with('+') || string.starts_with('-'));
631    // Skip the sign and look for the hyphen that terminates the year digits.
632    // Per ISO 8601 the unsigned year part must be at least 4 digits.
633    let rest = &string[1..];
634    let hyphen = rest.find('-')?;
635    if hyphen < 4 {
636        return None;
637    }
638    // The year substring is the sign and the digits (but not the separator),
639    // e.g. for "+10999-12-31", hyphen is 5 and s[..6] is "+10999".
640    let year: i32 = string[..hyphen + 1].parse().ok()?;
641    // The remainder should begin with a '-' which we strip off, leaving the month-day part.
642    let remainder = string[hyphen + 1..].strip_prefix('-')?;
643    let mut parts = remainder.splitn(2, '-');
644    let month: u32 = parts.next()?.parse().ok()?;
645    let day: u32 = parts.next()?.parse().ok()?;
646    Some((year, month, day))
647}
648
649fn parse_date(string: &str) -> Option<NaiveDate> {
650    // If the date has an extended (signed) year such as "+10999-12-31" or "-0012-05-06"
651    //
652    // According to [ISO 8601], years have:
653    //  Four digits or more for the year. Years in the range 0000 to 9999 will be pre-padded by
654    //  zero to ensure four digits. Years outside that range will have a prefixed positive or negative symbol.
655    //
656    // [ISO 8601]: https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/format/DateTimeFormatter.html#ISO_LOCAL_DATE
657    if string.starts_with('+') || string.starts_with('-') {
658        let (year, month, day) = parse_extended_ymd(string)?;
659        return NaiveDate::from_ymd_opt(year, month, day);
660    }
661
662    if string.len() > 10 {
663        // Try to parse as datetime and return just the date part
664        return string_to_datetime(&Utc, string)
665            .map(|dt| dt.date_naive())
666            .ok();
667    };
668    let mut digits = [0; 10];
669    let mut mask = 0;
670
671    // Treating all bytes the same way, helps LLVM vectorise this correctly
672    for (idx, (o, i)) in digits.iter_mut().zip(string.bytes()).enumerate() {
673        *o = i.wrapping_sub(b'0');
674        mask |= ((*o < 10) as u16) << idx
675    }
676
677    const HYPHEN: u8 = b'-'.wrapping_sub(b'0');
678
679    //  refer to https://www.rfc-editor.org/rfc/rfc3339#section-3
680    if digits[4] != HYPHEN {
681        let (year, month, day) = match (mask, string.len()) {
682            (0b11111111, 8) => (
683                digits[0] as u16 * 1000
684                    + digits[1] as u16 * 100
685                    + digits[2] as u16 * 10
686                    + digits[3] as u16,
687                digits[4] * 10 + digits[5],
688                digits[6] * 10 + digits[7],
689            ),
690            _ => return None,
691        };
692        return NaiveDate::from_ymd_opt(year as _, month as _, day as _);
693    }
694
695    let (month, day) = match mask {
696        0b1101101111 => {
697            if digits[7] != HYPHEN {
698                return None;
699            }
700            (digits[5] * 10 + digits[6], digits[8] * 10 + digits[9])
701        }
702        0b101101111 => {
703            if digits[7] != HYPHEN {
704                return None;
705            }
706            (digits[5] * 10 + digits[6], digits[8])
707        }
708        0b110101111 => {
709            if digits[6] != HYPHEN {
710                return None;
711            }
712            (digits[5], digits[7] * 10 + digits[8])
713        }
714        0b10101111 => {
715            if digits[6] != HYPHEN {
716                return None;
717            }
718            (digits[5], digits[7])
719        }
720        _ => return None,
721    };
722
723    let year =
724        digits[0] as u16 * 1000 + digits[1] as u16 * 100 + digits[2] as u16 * 10 + digits[3] as u16;
725
726    NaiveDate::from_ymd_opt(year as _, month as _, day as _)
727}
728
729/// Parse a date string into days since 1970-01-01, covering the full
730/// `Date32` range (years ≈ ±5,881,580) for the signed extended-year form.
731///
732/// The Gregorian calendar repeats exactly every 400 years (146,097 days), so
733/// we fold the year into `[0, 400)`, validate the folded date, and add
734/// `era * 146_097` to recover the absolute day count.
735///
736/// For all other inputs, behavior matches [`parse_date`].
737fn parse_date_to_days(string: &str) -> Option<i32> {
738    if string.starts_with('+') || string.starts_with('-') {
739        let (year, month, day) = parse_extended_ymd(string)?;
740        let y = year as i64;
741        let era = y.div_euclid(400);
742        let yoe = y.rem_euclid(400) as i32;
743        let nd = NaiveDate::from_ymd_opt(yoe, month, day)?;
744        let in_era = (nd.num_days_from_ce() - EPOCH_DAYS_FROM_CE) as i64;
745        return i32::try_from(era * 146_097 + in_era).ok();
746    }
747    parse_date(string).map(|nd| nd.num_days_from_ce() - EPOCH_DAYS_FROM_CE)
748}
749
750impl Parser for Date32Type {
751    fn parse(string: &str) -> Option<i32> {
752        parse_date_to_days(string)
753    }
754
755    fn parse_formatted(string: &str, format: &str) -> Option<i32> {
756        let date = NaiveDate::parse_from_str(string, format).ok()?;
757        Some(date.num_days_from_ce() - EPOCH_DAYS_FROM_CE)
758    }
759}
760
761impl Parser for Date64Type {
762    fn parse(string: &str) -> Option<i64> {
763        if string.len() <= 10 {
764            let datetime = NaiveDateTime::new(parse_date(string)?, NaiveTime::default());
765            Some(datetime.and_utc().timestamp_millis())
766        } else {
767            let date_time = string_to_datetime(&Utc, string).ok()?;
768            Some(date_time.timestamp_millis())
769        }
770    }
771
772    fn parse_formatted(string: &str, format: &str) -> Option<i64> {
773        use chrono::format::Fixed;
774        use chrono::format::StrftimeItems;
775        let fmt = StrftimeItems::new(format);
776        let has_zone = fmt.into_iter().any(|item| match item {
777            chrono::format::Item::Fixed(fixed_item) => matches!(
778                fixed_item,
779                Fixed::RFC2822
780                    | Fixed::RFC3339
781                    | Fixed::TimezoneName
782                    | Fixed::TimezoneOffsetColon
783                    | Fixed::TimezoneOffsetColonZ
784                    | Fixed::TimezoneOffset
785                    | Fixed::TimezoneOffsetZ
786            ),
787            _ => false,
788        });
789        if has_zone {
790            let date_time = chrono::DateTime::parse_from_str(string, format).ok()?;
791            Some(date_time.timestamp_millis())
792        } else {
793            let date_time = NaiveDateTime::parse_from_str(string, format).ok()?;
794            Some(date_time.and_utc().timestamp_millis())
795        }
796    }
797}
798
799fn parse_e_notation<T: DecimalType>(
800    s: &str,
801    mut digits: u16,
802    mut fractionals: i16,
803    mut result: T::Native,
804    index: usize,
805    precision: u16,
806    scale: i16,
807) -> Result<T::Native, ArrowError> {
808    let mut exp: i16 = 0;
809    let base = T::Native::usize_as(10);
810
811    // e has a plus sign
812    let mut pos_shift_direction: bool = true;
813
814    // skip to the exponent index directly or just after any processed fractionals
815    let mut bs = s.as_bytes().iter().skip(index + fractionals as usize);
816
817    // This function is only called from `parse_decimal`, in which we skip parsing any fractionals
818    // after we reach `scale` digits, not knowing ahead of time whether the decimal contains an
819    // e-notation or not.
820    // So once we do hit into an e-notation, and drop down into this function, we need to parse the
821    // remaining unprocessed fractionals too, since otherwise we might lose precision.
822    for b in bs.by_ref() {
823        match b {
824            b'0'..=b'9' => {
825                result = result.mul_wrapping(base);
826                result = result.add_wrapping(T::Native::usize_as((b - b'0') as usize));
827                fractionals += 1;
828                digits += 1;
829            }
830            b'e' | b'E' => {
831                break;
832            }
833            _ => {
834                return Err(ArrowError::ParseError(format!(
835                    "can't parse the string value {s} to decimal"
836                )));
837            }
838        };
839    }
840
841    // parse the exponent itself
842    let mut signed = false;
843    for b in bs {
844        match b {
845            b'-' if !signed => {
846                pos_shift_direction = false;
847                signed = true;
848            }
849            b'+' if !signed => {
850                pos_shift_direction = true;
851                signed = true;
852            }
853            b if b.is_ascii_digit() => {
854                exp *= 10;
855                exp += (b - b'0') as i16;
856            }
857            _ => {
858                return Err(ArrowError::ParseError(format!(
859                    "can't parse the string value {s} to decimal"
860                )));
861            }
862        }
863    }
864
865    if digits == 0 && fractionals == 0 && exp == 0 {
866        return Err(ArrowError::ParseError(format!(
867            "can't parse the string value {s} to decimal"
868        )));
869    }
870
871    if !pos_shift_direction {
872        // exponent has a large negative sign
873        // 1.12345e-30 => 0.0{29}12345, scale = 5
874        if exp - (digits as i16 + scale) > 0 {
875            return Ok(T::Native::usize_as(0));
876        }
877        exp *= -1;
878    }
879
880    // point offset
881    exp = fractionals - exp;
882    // We have zeros on the left, we need to count them
883    if !pos_shift_direction && exp > digits as i16 {
884        digits = exp as u16;
885    }
886    // Number of numbers to be removed or added
887    exp = scale - exp;
888
889    if (digits as i16 + exp) as u16 > precision {
890        return Err(ArrowError::ParseError(format!(
891            "parse decimal overflow ({s})"
892        )));
893    }
894
895    if exp < 0 {
896        result = result.div_wrapping(base.pow_wrapping(-exp as _));
897    } else {
898        result = result.mul_wrapping(base.pow_wrapping(exp as _));
899    }
900
901    Ok(result)
902}
903
904/// Parse the string format decimal value to i128/i256 format and checking the precision and scale.
905/// Expected behavior:
906/// - The result value can't be out of bounds.
907/// - When parsing a decimal with scale 0, all fractional digits will be discarded. The final
908///   fractional digits may be a subset or a superset of the digits after the decimal point when
909///   e-notation is used.
910pub fn parse_decimal<T: DecimalType>(
911    s: &str,
912    precision: u8,
913    scale: i8,
914) -> Result<T::Native, ArrowError> {
915    let mut result = T::Native::usize_as(0);
916    let mut fractionals: i8 = 0;
917    let mut digits: u8 = 0;
918    let base = T::Native::usize_as(10);
919
920    let bs = s.as_bytes();
921
922    if !bs
923        .last()
924        .is_some_and(|b| b.is_ascii_digit() || (b == &b'.' && s.len() > 1))
925    {
926        // If the last character is not a digit (or a decimal point prefixed with some digits), then
927        // it's not a valid decimal.
928        return Err(ArrowError::ParseError(format!(
929            "can't parse the string value {s} to decimal"
930        )));
931    }
932
933    let (signed, negative) = match bs.first() {
934        Some(b'-') => (true, true),
935        Some(b'+') => (true, false),
936        _ => (false, false),
937    };
938
939    // Iterate over the raw input bytes, skipping the sign if any
940    let mut bs = bs.iter().enumerate().skip(signed as usize);
941
942    let mut is_e_notation = false;
943
944    // Overflow checks are not required if 10^(precision - 1) <= T::MAX holds.
945    // Thus, if we validate the precision correctly, we can skip overflow checks.
946    while let Some((index, b)) = bs.next() {
947        match b {
948            b'0'..=b'9' => {
949                if digits == 0 && *b == b'0' {
950                    // Ignore leading zeros.
951                    continue;
952                }
953                digits += 1;
954                result = result.mul_wrapping(base);
955                result = result.add_wrapping(T::Native::usize_as((b - b'0') as usize));
956            }
957            b'.' => {
958                let point_index = index;
959
960                for (_, b) in bs.by_ref() {
961                    if !b.is_ascii_digit() {
962                        if *b == b'e' || *b == b'E' {
963                            result = parse_e_notation::<T>(
964                                s,
965                                digits as u16,
966                                fractionals as i16,
967                                result,
968                                point_index + 1,
969                                precision as u16,
970                                scale as i16,
971                            )?;
972
973                            is_e_notation = true;
974
975                            break;
976                        }
977                        return Err(ArrowError::ParseError(format!(
978                            "can't parse the string value {s} to decimal"
979                        )));
980                    }
981                    if fractionals == scale {
982                        // We have processed all the digits that we need. All that
983                        // is left is to validate that the rest of the string contains
984                        // valid digits.
985                        continue;
986                    }
987                    fractionals += 1;
988                    digits += 1;
989                    result = result.mul_wrapping(base);
990                    result = result.add_wrapping(T::Native::usize_as((b - b'0') as usize));
991                }
992
993                if is_e_notation {
994                    break;
995                }
996            }
997            b'e' | b'E' => {
998                result = parse_e_notation::<T>(
999                    s,
1000                    digits as u16,
1001                    fractionals as i16,
1002                    result,
1003                    index,
1004                    precision as u16,
1005                    scale as i16,
1006                )?;
1007
1008                is_e_notation = true;
1009
1010                break;
1011            }
1012            _ => {
1013                return Err(ArrowError::ParseError(format!(
1014                    "can't parse the string value {s} to decimal"
1015                )));
1016            }
1017        }
1018    }
1019
1020    if !is_e_notation {
1021        if fractionals < scale {
1022            let exp = scale - fractionals;
1023            if exp as u8 + digits > precision {
1024                return Err(ArrowError::ParseError(format!(
1025                    "parse decimal overflow ({s})"
1026                )));
1027            }
1028            let mul = base.pow_wrapping(exp as _);
1029            result = result.mul_wrapping(mul);
1030        } else if digits > precision {
1031            return Err(ArrowError::ParseError(format!(
1032                "parse decimal overflow ({s})"
1033            )));
1034        }
1035    }
1036
1037    Ok(if negative {
1038        result.neg_wrapping()
1039    } else {
1040        result
1041    })
1042}
1043
1044/// Parse human-readable interval string to Arrow [IntervalYearMonthType]
1045pub fn parse_interval_year_month(
1046    value: &str,
1047) -> Result<<IntervalYearMonthType as ArrowPrimitiveType>::Native, ArrowError> {
1048    let config = IntervalParseConfig::new(IntervalUnit::Year);
1049    let interval = Interval::parse(value, &config)?;
1050
1051    let months = interval.to_year_months().map_err(|_| {
1052        ArrowError::CastError(format!(
1053            "Cannot cast {value} to IntervalYearMonth. Only year and month fields are allowed."
1054        ))
1055    })?;
1056
1057    Ok(IntervalYearMonthType::make_value(0, months))
1058}
1059
1060/// Parse human-readable interval string to Arrow [IntervalDayTimeType]
1061pub fn parse_interval_day_time(
1062    value: &str,
1063) -> Result<<IntervalDayTimeType as ArrowPrimitiveType>::Native, ArrowError> {
1064    let config = IntervalParseConfig::new(IntervalUnit::Day);
1065    let interval = Interval::parse(value, &config)?;
1066
1067    let (days, millis) = interval.to_day_time().map_err(|_| ArrowError::CastError(format!(
1068        "Cannot cast {value} to IntervalDayTime because the nanos part isn't multiple of milliseconds"
1069    )))?;
1070
1071    Ok(IntervalDayTimeType::make_value(days, millis))
1072}
1073
1074/// Parse human-readable interval string to Arrow [IntervalMonthDayNanoType]
1075pub fn parse_interval_month_day_nano_config(
1076    value: &str,
1077    config: IntervalParseConfig,
1078) -> Result<<IntervalMonthDayNanoType as ArrowPrimitiveType>::Native, ArrowError> {
1079    let interval = Interval::parse(value, &config)?;
1080
1081    let (months, days, nanos) = interval.to_month_day_nanos();
1082
1083    Ok(IntervalMonthDayNanoType::make_value(months, days, nanos))
1084}
1085
1086/// Parse human-readable interval string to Arrow [IntervalMonthDayNanoType]
1087pub fn parse_interval_month_day_nano(
1088    value: &str,
1089) -> Result<<IntervalMonthDayNanoType as ArrowPrimitiveType>::Native, ArrowError> {
1090    parse_interval_month_day_nano_config(value, IntervalParseConfig::new(IntervalUnit::Month))
1091}
1092
1093const NANOS_PER_MILLIS: i64 = 1_000_000;
1094const NANOS_PER_SECOND: i64 = 1_000 * NANOS_PER_MILLIS;
1095const NANOS_PER_MINUTE: i64 = 60 * NANOS_PER_SECOND;
1096const NANOS_PER_HOUR: i64 = 60 * NANOS_PER_MINUTE;
1097#[cfg(test)]
1098const NANOS_PER_DAY: i64 = 24 * NANOS_PER_HOUR;
1099
1100/// Config to parse interval strings
1101///
1102/// Currently stores the `default_unit` to use if the string doesn't have one specified
1103#[derive(Debug, Clone)]
1104pub struct IntervalParseConfig {
1105    /// The default unit to use if none is specified
1106    /// e.g. `INTERVAL 1` represents `INTERVAL 1 SECOND` when default_unit = [IntervalUnit::Second]
1107    default_unit: IntervalUnit,
1108}
1109
1110impl IntervalParseConfig {
1111    /// Create a new [IntervalParseConfig] with the given default unit
1112    pub fn new(default_unit: IntervalUnit) -> Self {
1113        Self { default_unit }
1114    }
1115}
1116
1117#[rustfmt::skip]
1118#[derive(Debug, Clone, Copy)]
1119#[repr(u16)]
1120/// Represents the units of an interval, with each variant
1121/// corresponding to a bit in the interval's bitfield representation
1122pub enum IntervalUnit {
1123    /// A Century
1124    Century     = 0b_0000_0000_0001,
1125    /// A Decade
1126    Decade      = 0b_0000_0000_0010,
1127    /// A Year
1128    Year        = 0b_0000_0000_0100,
1129    /// A Month
1130    Month       = 0b_0000_0000_1000,
1131    /// A Week
1132    Week        = 0b_0000_0001_0000,
1133    /// A Day
1134    Day         = 0b_0000_0010_0000,
1135    /// An Hour
1136    Hour        = 0b_0000_0100_0000,
1137    /// A Minute
1138    Minute      = 0b_0000_1000_0000,
1139    /// A Second
1140    Second      = 0b_0001_0000_0000,
1141    /// A Millisecond
1142    Millisecond = 0b_0010_0000_0000,
1143    /// A Microsecond
1144    Microsecond = 0b_0100_0000_0000,
1145    /// A Nanosecond
1146    Nanosecond  = 0b_1000_0000_0000,
1147}
1148
1149/// Logic for parsing interval unit strings
1150///
1151/// See <https://github.com/postgres/postgres/blob/2caa85f4aae689e6f6721d7363b4c66a2a6417d6/src/backend/utils/adt/datetime.c#L189>
1152/// for a list of unit names supported by PostgreSQL which we try to match here.
1153impl FromStr for IntervalUnit {
1154    type Err = ArrowError;
1155
1156    fn from_str(s: &str) -> Result<Self, ArrowError> {
1157        match s.to_lowercase().as_str() {
1158            "c" | "cent" | "cents" | "century" | "centuries" => Ok(Self::Century),
1159            "dec" | "decs" | "decade" | "decades" => Ok(Self::Decade),
1160            "y" | "yr" | "yrs" | "year" | "years" => Ok(Self::Year),
1161            "mon" | "mons" | "month" | "months" => Ok(Self::Month),
1162            "w" | "week" | "weeks" => Ok(Self::Week),
1163            "d" | "day" | "days" => Ok(Self::Day),
1164            "h" | "hr" | "hrs" | "hour" | "hours" => Ok(Self::Hour),
1165            "m" | "min" | "mins" | "minute" | "minutes" => Ok(Self::Minute),
1166            "s" | "sec" | "secs" | "second" | "seconds" => Ok(Self::Second),
1167            "ms" | "msec" | "msecs" | "msecond" | "mseconds" | "millisecond" | "milliseconds" => {
1168                Ok(Self::Millisecond)
1169            }
1170            "us" | "usec" | "usecs" | "usecond" | "useconds" | "microsecond" | "microseconds" => {
1171                Ok(Self::Microsecond)
1172            }
1173            "nanosecond" | "nanoseconds" => Ok(Self::Nanosecond),
1174            _ => Err(ArrowError::InvalidArgumentError(format!(
1175                "Unknown interval type: {s}"
1176            ))),
1177        }
1178    }
1179}
1180
1181impl IntervalUnit {
1182    fn from_str_or_config(
1183        s: Option<&str>,
1184        config: &IntervalParseConfig,
1185    ) -> Result<Self, ArrowError> {
1186        match s {
1187            Some(s) => s.parse(),
1188            None => Ok(config.default_unit),
1189        }
1190    }
1191}
1192
1193/// A tuple representing (months, days, nanoseconds) in an interval
1194pub type MonthDayNano = (i32, i32, i64);
1195
1196/// Chosen based on the number of decimal digits in 1 week in nanoseconds
1197const INTERVAL_PRECISION: u32 = 15;
1198
1199#[derive(Clone, Copy, Debug, PartialEq)]
1200struct IntervalAmount {
1201    /// The integer component of the interval amount
1202    integer: i64,
1203    /// The fractional component multiplied by 10^INTERVAL_PRECISION
1204    frac: i64,
1205}
1206
1207#[cfg(test)]
1208impl IntervalAmount {
1209    fn new(integer: i64, frac: i64) -> Self {
1210        Self { integer, frac }
1211    }
1212}
1213
1214impl FromStr for IntervalAmount {
1215    type Err = ArrowError;
1216
1217    fn from_str(s: &str) -> Result<Self, Self::Err> {
1218        match s.split_once('.') {
1219            Some((integer, frac))
1220                if frac.len() <= INTERVAL_PRECISION as usize
1221                    && !frac.is_empty()
1222                    && !frac.starts_with('-') =>
1223            {
1224                // integer will be "" for values like ".5"
1225                // and "-" for values like "-.5"
1226                let explicit_neg = integer.starts_with('-');
1227                let integer = if integer.is_empty() || integer == "-" {
1228                    Ok(0)
1229                } else {
1230                    integer.parse::<i64>().map_err(|_| {
1231                        ArrowError::ParseError(format!("Failed to parse {s} as interval amount"))
1232                    })
1233                }?;
1234
1235                let frac_unscaled = frac.parse::<i64>().map_err(|_| {
1236                    ArrowError::ParseError(format!("Failed to parse {s} as interval amount"))
1237                })?;
1238
1239                // scale fractional part by interval precision
1240                let frac = frac_unscaled * 10_i64.pow(INTERVAL_PRECISION - frac.len() as u32);
1241
1242                // propagate the sign of the integer part to the fractional part
1243                let frac = if integer < 0 || explicit_neg {
1244                    -frac
1245                } else {
1246                    frac
1247                };
1248
1249                let result = Self { integer, frac };
1250
1251                Ok(result)
1252            }
1253            Some((_, frac)) if frac.starts_with('-') => Err(ArrowError::ParseError(format!(
1254                "Failed to parse {s} as interval amount"
1255            ))),
1256            Some((_, frac)) if frac.len() > INTERVAL_PRECISION as usize => {
1257                Err(ArrowError::ParseError(format!(
1258                    "{s} exceeds the precision available for interval amount"
1259                )))
1260            }
1261            Some(_) | None => {
1262                let integer = s.parse::<i64>().map_err(|_| {
1263                    ArrowError::ParseError(format!("Failed to parse {s} as interval amount"))
1264                })?;
1265
1266                let result = Self { integer, frac: 0 };
1267                Ok(result)
1268            }
1269        }
1270    }
1271}
1272
1273#[derive(Debug, Default, PartialEq)]
1274struct Interval {
1275    months: i32,
1276    days: i32,
1277    nanos: i64,
1278}
1279
1280impl Interval {
1281    fn new(months: i32, days: i32, nanos: i64) -> Self {
1282        Self {
1283            months,
1284            days,
1285            nanos,
1286        }
1287    }
1288
1289    fn to_year_months(&self) -> Result<i32, ArrowError> {
1290        match (self.months, self.days, self.nanos) {
1291            (months, days, nanos) if days == 0 && nanos == 0 => Ok(months),
1292            _ => Err(ArrowError::InvalidArgumentError(format!(
1293                "Unable to represent interval with days and nanos as year-months: {self:?}"
1294            ))),
1295        }
1296    }
1297
1298    fn to_day_time(&self) -> Result<(i32, i32), ArrowError> {
1299        let days = self.months.mul_checked(30)?.add_checked(self.days)?;
1300
1301        match self.nanos {
1302            nanos if nanos % NANOS_PER_MILLIS == 0 => {
1303                let millis = (self.nanos / 1_000_000).try_into().map_err(|_| {
1304                    ArrowError::InvalidArgumentError(format!(
1305                        "Unable to represent {} nanos as milliseconds in a signed 32-bit integer",
1306                        self.nanos
1307                    ))
1308                })?;
1309
1310                Ok((days, millis))
1311            }
1312            nanos => Err(ArrowError::InvalidArgumentError(format!(
1313                "Unable to represent {nanos} as milliseconds"
1314            ))),
1315        }
1316    }
1317
1318    fn to_month_day_nanos(&self) -> (i32, i32, i64) {
1319        (self.months, self.days, self.nanos)
1320    }
1321
1322    /// Parse string value in traditional Postgres format such as
1323    /// `1 year 2 months 3 days 4 hours 5 minutes 6 seconds`
1324    fn parse(value: &str, config: &IntervalParseConfig) -> Result<Self, ArrowError> {
1325        let components = parse_interval_components(value, config)?;
1326
1327        components
1328            .into_iter()
1329            .try_fold(Self::default(), |result, (amount, unit)| {
1330                result.add(amount, unit)
1331            })
1332    }
1333
1334    /// Interval addition following Postgres behavior. Fractional units will be spilled into smaller units.
1335    /// When the interval unit is larger than months, the result is rounded to total months and not spilled to days/nanos.
1336    /// Fractional parts of weeks and days are represented using days and nanoseconds.
1337    /// e.g. INTERVAL '0.5 MONTH' = 15 days, INTERVAL '1.5 MONTH' = 1 month 15 days
1338    /// e.g. INTERVAL '0.5 DAY' = 12 hours, INTERVAL '1.5 DAY' = 1 day 12 hours
1339    /// [Postgres reference](https://www.postgresql.org/docs/15/datatype-datetime.html#DATATYPE-INTERVAL-INPUT:~:text=Field%20values%20can,fractional%20on%20output.)
1340    fn add(&self, amount: IntervalAmount, unit: IntervalUnit) -> Result<Self, ArrowError> {
1341        let result = match unit {
1342            IntervalUnit::Century => {
1343                let months_int = amount.integer.mul_checked(100)?.mul_checked(12)?;
1344                let month_frac = amount.frac * 12 / 10_i64.pow(INTERVAL_PRECISION - 2);
1345                let months = months_int
1346                    .add_checked(month_frac)?
1347                    .try_into()
1348                    .map_err(|_| {
1349                        ArrowError::ParseError(format!(
1350                            "Unable to represent {} centuries as months in a signed 32-bit integer",
1351                            amount.integer
1352                        ))
1353                    })?;
1354
1355                Self::new(self.months.add_checked(months)?, self.days, self.nanos)
1356            }
1357            IntervalUnit::Decade => {
1358                let months_int = amount.integer.mul_checked(10)?.mul_checked(12)?;
1359
1360                let month_frac = amount.frac * 12 / 10_i64.pow(INTERVAL_PRECISION - 1);
1361                let months = months_int
1362                    .add_checked(month_frac)?
1363                    .try_into()
1364                    .map_err(|_| {
1365                        ArrowError::ParseError(format!(
1366                            "Unable to represent {} decades as months in a signed 32-bit integer",
1367                            amount.integer
1368                        ))
1369                    })?;
1370
1371                Self::new(self.months.add_checked(months)?, self.days, self.nanos)
1372            }
1373            IntervalUnit::Year => {
1374                let months_int = amount.integer.mul_checked(12)?;
1375                let month_frac = amount.frac * 12 / 10_i64.pow(INTERVAL_PRECISION);
1376                let months = months_int
1377                    .add_checked(month_frac)?
1378                    .try_into()
1379                    .map_err(|_| {
1380                        ArrowError::ParseError(format!(
1381                            "Unable to represent {} years as months in a signed 32-bit integer",
1382                            amount.integer
1383                        ))
1384                    })?;
1385
1386                Self::new(self.months.add_checked(months)?, self.days, self.nanos)
1387            }
1388            IntervalUnit::Month => {
1389                let months = amount.integer.try_into().map_err(|_| {
1390                    ArrowError::ParseError(format!(
1391                        "Unable to represent {} months in a signed 32-bit integer",
1392                        amount.integer
1393                    ))
1394                })?;
1395
1396                let days = amount.frac * 3 / 10_i64.pow(INTERVAL_PRECISION - 1);
1397                let days = days.try_into().map_err(|_| {
1398                    ArrowError::ParseError(format!(
1399                        "Unable to represent {} months as days in a signed 32-bit integer",
1400                        amount.frac / 10_i64.pow(INTERVAL_PRECISION)
1401                    ))
1402                })?;
1403
1404                Self::new(
1405                    self.months.add_checked(months)?,
1406                    self.days.add_checked(days)?,
1407                    self.nanos,
1408                )
1409            }
1410            IntervalUnit::Week => {
1411                let days = amount.integer.mul_checked(7)?.try_into().map_err(|_| {
1412                    ArrowError::ParseError(format!(
1413                        "Unable to represent {} weeks as days in a signed 32-bit integer",
1414                        amount.integer
1415                    ))
1416                })?;
1417
1418                let nanos = amount.frac * 7 * 24 * 6 * 6 / 10_i64.pow(INTERVAL_PRECISION - 11);
1419
1420                Self::new(
1421                    self.months,
1422                    self.days.add_checked(days)?,
1423                    self.nanos.add_checked(nanos)?,
1424                )
1425            }
1426            IntervalUnit::Day => {
1427                let days = amount.integer.try_into().map_err(|_| {
1428                    ArrowError::InvalidArgumentError(format!(
1429                        "Unable to represent {} days in a signed 32-bit integer",
1430                        amount.integer
1431                    ))
1432                })?;
1433
1434                let nanos = amount.frac * 24 * 6 * 6 / 10_i64.pow(INTERVAL_PRECISION - 11);
1435
1436                Self::new(
1437                    self.months,
1438                    self.days.add_checked(days)?,
1439                    self.nanos.add_checked(nanos)?,
1440                )
1441            }
1442            IntervalUnit::Hour => {
1443                let nanos_int = amount.integer.mul_checked(NANOS_PER_HOUR)?;
1444                let nanos_frac = amount.frac * 6 * 6 / 10_i64.pow(INTERVAL_PRECISION - 11);
1445                let nanos = nanos_int.add_checked(nanos_frac)?;
1446
1447                Interval::new(self.months, self.days, self.nanos.add_checked(nanos)?)
1448            }
1449            IntervalUnit::Minute => {
1450                let nanos_int = amount.integer.mul_checked(NANOS_PER_MINUTE)?;
1451                let nanos_frac = amount.frac * 6 / 10_i64.pow(INTERVAL_PRECISION - 10);
1452
1453                let nanos = nanos_int.add_checked(nanos_frac)?;
1454
1455                Interval::new(self.months, self.days, self.nanos.add_checked(nanos)?)
1456            }
1457            IntervalUnit::Second => {
1458                let nanos_int = amount.integer.mul_checked(NANOS_PER_SECOND)?;
1459                let nanos_frac = amount.frac / 10_i64.pow(INTERVAL_PRECISION - 9);
1460                let nanos = nanos_int.add_checked(nanos_frac)?;
1461
1462                Interval::new(self.months, self.days, self.nanos.add_checked(nanos)?)
1463            }
1464            IntervalUnit::Millisecond => {
1465                let nanos_int = amount.integer.mul_checked(NANOS_PER_MILLIS)?;
1466                let nanos_frac = amount.frac / 10_i64.pow(INTERVAL_PRECISION - 6);
1467                let nanos = nanos_int.add_checked(nanos_frac)?;
1468
1469                Interval::new(self.months, self.days, self.nanos.add_checked(nanos)?)
1470            }
1471            IntervalUnit::Microsecond => {
1472                let nanos_int = amount.integer.mul_checked(1_000)?;
1473                let nanos_frac = amount.frac / 10_i64.pow(INTERVAL_PRECISION - 3);
1474                let nanos = nanos_int.add_checked(nanos_frac)?;
1475
1476                Interval::new(self.months, self.days, self.nanos.add_checked(nanos)?)
1477            }
1478            IntervalUnit::Nanosecond => {
1479                let nanos_int = amount.integer;
1480                let nanos_frac = amount.frac / 10_i64.pow(INTERVAL_PRECISION);
1481                let nanos = nanos_int.add_checked(nanos_frac)?;
1482
1483                Interval::new(self.months, self.days, self.nanos.add_checked(nanos)?)
1484            }
1485        };
1486
1487        Ok(result)
1488    }
1489}
1490
1491/// parse the string into a vector of interval components i.e. (amount, unit) tuples
1492fn parse_interval_components(
1493    value: &str,
1494    config: &IntervalParseConfig,
1495) -> Result<Vec<(IntervalAmount, IntervalUnit)>, ArrowError> {
1496    let raw_pairs = split_interval_components(value);
1497
1498    // parse amounts and units
1499    let Ok(pairs): Result<Vec<(IntervalAmount, IntervalUnit)>, ArrowError> = raw_pairs
1500        .iter()
1501        .map(|(a, u)| Ok((a.parse()?, IntervalUnit::from_str_or_config(*u, config)?)))
1502        .collect()
1503    else {
1504        return Err(ArrowError::ParseError(format!(
1505            "Invalid input syntax for type interval: {value:?}"
1506        )));
1507    };
1508
1509    // collect parsed results
1510    let (amounts, units): (Vec<_>, Vec<_>) = pairs.into_iter().unzip();
1511
1512    // duplicate units?
1513    let mut observed_interval_types = 0;
1514    for (unit, (_, raw_unit)) in units.iter().zip(raw_pairs) {
1515        if observed_interval_types & (*unit as u16) != 0 {
1516            return Err(ArrowError::ParseError(format!(
1517                "Invalid input syntax for type interval: {:?}. Repeated type '{}'",
1518                value,
1519                raw_unit.unwrap_or_default(),
1520            )));
1521        }
1522
1523        observed_interval_types |= *unit as u16;
1524    }
1525
1526    let result = amounts.iter().copied().zip(units.iter().copied());
1527
1528    Ok(result.collect::<Vec<_>>())
1529}
1530
1531/// Split an interval into a vec of amounts and units.
1532///
1533/// Pairs are separated by spaces, but within a pair the amount and unit may or may not be separated by a space.
1534///
1535/// This should match the behavior of PostgreSQL's interval parser.
1536fn split_interval_components(value: &str) -> Vec<(&str, Option<&str>)> {
1537    let mut result = vec![];
1538    let mut words = value.split(char::is_whitespace);
1539    while let Some(word) = words.next() {
1540        if let Some(split_word_at) = word.find(not_interval_amount) {
1541            let (amount, unit) = word.split_at(split_word_at);
1542            result.push((amount, Some(unit)));
1543        } else if let Some(unit) = words.next() {
1544            result.push((word, Some(unit)));
1545        } else {
1546            result.push((word, None));
1547            break;
1548        }
1549    }
1550    result
1551}
1552
1553/// test if a character is NOT part of an interval numeric amount
1554fn not_interval_amount(c: char) -> bool {
1555    !c.is_ascii_digit() && c != '.' && c != '-'
1556}
1557
1558#[cfg(test)]
1559mod tests {
1560    use super::*;
1561    use arrow_array::temporal_conversions::date32_to_datetime;
1562    use arrow_buffer::i256;
1563
1564    #[test]
1565    fn test_parse_nanos() {
1566        assert_eq!(parse_nanos::<3, 0>(&[1, 2, 3]), 123_000_000);
1567        assert_eq!(parse_nanos::<5, 0>(&[1, 2, 3, 4, 5]), 123_450_000);
1568        assert_eq!(parse_nanos::<6, b'0'>(b"123456"), 123_456_000);
1569    }
1570
1571    #[test]
1572    fn string_to_timestamp_timezone() {
1573        // Explicit timezone
1574        assert_eq!(
1575            1599572549190855000,
1576            parse_timestamp("2020-09-08T13:42:29.190855+00:00").unwrap()
1577        );
1578        assert_eq!(
1579            1599572549190855000,
1580            parse_timestamp("2020-09-08T13:42:29.190855Z").unwrap()
1581        );
1582        assert_eq!(
1583            1599572549000000000,
1584            parse_timestamp("2020-09-08T13:42:29Z").unwrap()
1585        ); // no fractional part
1586        assert_eq!(
1587            1599590549190855000,
1588            parse_timestamp("2020-09-08T13:42:29.190855-05:00").unwrap()
1589        );
1590    }
1591
1592    #[test]
1593    fn string_to_timestamp_timezone_space() {
1594        // Ensure space rather than T between time and date is accepted
1595        assert_eq!(
1596            1599572549190855000,
1597            parse_timestamp("2020-09-08 13:42:29.190855+00:00").unwrap()
1598        );
1599        assert_eq!(
1600            1599572549190855000,
1601            parse_timestamp("2020-09-08 13:42:29.190855Z").unwrap()
1602        );
1603        assert_eq!(
1604            1599572549000000000,
1605            parse_timestamp("2020-09-08 13:42:29Z").unwrap()
1606        ); // no fractional part
1607        assert_eq!(
1608            1599590549190855000,
1609            parse_timestamp("2020-09-08 13:42:29.190855-05:00").unwrap()
1610        );
1611    }
1612
1613    #[test]
1614    #[cfg_attr(miri, ignore)] // unsupported operation: can't call foreign function: mktime
1615    fn string_to_timestamp_no_timezone() {
1616        // This test is designed to succeed in regardless of the local
1617        // timezone the test machine is running. Thus it is still
1618        // somewhat susceptible to bugs in the use of chrono
1619        let naive_datetime = NaiveDateTime::new(
1620            NaiveDate::from_ymd_opt(2020, 9, 8).unwrap(),
1621            NaiveTime::from_hms_nano_opt(13, 42, 29, 190855000).unwrap(),
1622        );
1623
1624        // Ensure both T and ' ' variants work
1625        assert_eq!(
1626            naive_datetime.and_utc().timestamp_nanos_opt().unwrap(),
1627            parse_timestamp("2020-09-08T13:42:29.190855").unwrap()
1628        );
1629
1630        assert_eq!(
1631            naive_datetime.and_utc().timestamp_nanos_opt().unwrap(),
1632            parse_timestamp("2020-09-08 13:42:29.190855").unwrap()
1633        );
1634
1635        // Also ensure that parsing timestamps with no fractional
1636        // second part works as well
1637        let datetime_whole_secs = NaiveDateTime::new(
1638            NaiveDate::from_ymd_opt(2020, 9, 8).unwrap(),
1639            NaiveTime::from_hms_opt(13, 42, 29).unwrap(),
1640        )
1641        .and_utc();
1642
1643        // Ensure both T and ' ' variants work
1644        assert_eq!(
1645            datetime_whole_secs.timestamp_nanos_opt().unwrap(),
1646            parse_timestamp("2020-09-08T13:42:29").unwrap()
1647        );
1648
1649        assert_eq!(
1650            datetime_whole_secs.timestamp_nanos_opt().unwrap(),
1651            parse_timestamp("2020-09-08 13:42:29").unwrap()
1652        );
1653
1654        // ensure without time work
1655        // no time, should be the nano second at
1656        // 2020-09-08 0:0:0
1657        let datetime_no_time = NaiveDateTime::new(
1658            NaiveDate::from_ymd_opt(2020, 9, 8).unwrap(),
1659            NaiveTime::from_hms_opt(0, 0, 0).unwrap(),
1660        )
1661        .and_utc();
1662
1663        assert_eq!(
1664            datetime_no_time.timestamp_nanos_opt().unwrap(),
1665            parse_timestamp("2020-09-08").unwrap()
1666        )
1667    }
1668
1669    #[test]
1670    fn string_to_timestamp_chrono() {
1671        let cases = [
1672            "2020-09-08T13:42:29Z",
1673            "1969-01-01T00:00:00.1Z",
1674            "2020-09-08T12:00:12.12345678+00:00",
1675            "2020-09-08T12:00:12+00:00",
1676            "2020-09-08T12:00:12.1+00:00",
1677            "2020-09-08T12:00:12.12+00:00",
1678            "2020-09-08T12:00:12.123+00:00",
1679            "2020-09-08T12:00:12.1234+00:00",
1680            "2020-09-08T12:00:12.12345+00:00",
1681            "2020-09-08T12:00:12.123456+00:00",
1682            "2020-09-08T12:00:12.1234567+00:00",
1683            "2020-09-08T12:00:12.12345678+00:00",
1684            "2020-09-08T12:00:12.123456789+00:00",
1685            "2020-09-08T12:00:12.12345678912z",
1686            "2020-09-08T12:00:12.123456789123Z",
1687            "2020-09-08T12:00:12.123456789123+02:00",
1688            "2020-09-08T12:00:12.12345678912345Z",
1689            "2020-09-08T12:00:12.1234567891234567+02:00",
1690            "2020-09-08T12:00:60Z",
1691            "2020-09-08T12:00:60.123Z",
1692            "2020-09-08T12:00:60.123456+02:00",
1693            "2020-09-08T12:00:60.1234567891234567+02:00",
1694            "2020-09-08T12:00:60.999999999+02:00",
1695            "2020-09-08t12:00:12.12345678+00:00",
1696            "2020-09-08t12:00:12+00:00",
1697            "2020-09-08t12:00:12Z",
1698        ];
1699
1700        for case in cases {
1701            let chrono = DateTime::parse_from_rfc3339(case).unwrap();
1702            let chrono_utc = chrono.with_timezone(&Utc);
1703
1704            let custom = string_to_datetime(&Utc, case).unwrap();
1705            assert_eq!(chrono_utc, custom)
1706        }
1707    }
1708
1709    #[test]
1710    fn string_to_timestamp_naive() {
1711        let cases = [
1712            "2018-11-13T17:11:10.011375885995",
1713            "2030-12-04T17:11:10.123",
1714            "2030-12-04T17:11:10.1234",
1715            "2030-12-04T17:11:10.123456",
1716        ];
1717        for case in cases {
1718            let chrono = NaiveDateTime::parse_from_str(case, "%Y-%m-%dT%H:%M:%S%.f").unwrap();
1719            let custom = string_to_datetime(&Utc, case).unwrap();
1720            assert_eq!(chrono, custom.naive_utc())
1721        }
1722    }
1723
1724    #[test]
1725    fn string_to_timestamp_invalid() {
1726        // Test parsing invalid formats
1727        let cases = [
1728            ("", "timestamp must contain at least 10 characters"),
1729            ("SS", "timestamp must contain at least 10 characters"),
1730            ("Wed, 18 Feb 2015 23:16:09 GMT", "error parsing date"),
1731            ("1997-01-31H09:26:56.123Z", "invalid timestamp separator"),
1732            ("1997-01-31  09:26:56.123Z", "error parsing time"),
1733            ("1997:01:31T09:26:56.123Z", "error parsing date"),
1734            ("1997:1:31T09:26:56.123Z", "error parsing date"),
1735            ("1997-01-32T09:26:56.123Z", "error parsing date"),
1736            ("1997-13-32T09:26:56.123Z", "error parsing date"),
1737            ("1997-02-29T09:26:56.123Z", "error parsing date"),
1738            ("2015-02-30T17:35:20-08:00", "error parsing date"),
1739            ("1997-01-10T9:26:56.123Z", "error parsing time"),
1740            ("2015-01-20T25:35:20-08:00", "error parsing time"),
1741            ("1997-01-10T09:61:56.123Z", "error parsing time"),
1742            ("1997-01-10T09:61:90.123Z", "error parsing time"),
1743            ("1997-01-10T12:00:6.123Z", "error parsing time"),
1744            ("1997-01-31T092656.123Z", "error parsing time"),
1745            ("1997-01-10T12:00:06.", "error parsing time"),
1746            ("1997-01-10T12:00:06. ", "error parsing time"),
1747        ];
1748
1749        for (s, ctx) in cases {
1750            let expected = format!("Parser error: Error parsing timestamp from '{s}': {ctx}");
1751            let actual = string_to_datetime(&Utc, s).unwrap_err().to_string();
1752            assert_eq!(actual, expected)
1753        }
1754    }
1755
1756    // Parse a timestamp to timestamp int with a useful human readable error message
1757    fn parse_timestamp(s: &str) -> Result<i64, ArrowError> {
1758        let result = string_to_timestamp_nanos(s);
1759        if let Err(e) = &result {
1760            eprintln!("Error parsing timestamp '{s}': {e:?}");
1761        }
1762        result
1763    }
1764
1765    #[test]
1766    fn string_without_timezone_to_timestamp() {
1767        // string without timezone should always output the same regardless the local or session timezone
1768
1769        let naive_datetime = NaiveDateTime::new(
1770            NaiveDate::from_ymd_opt(2020, 9, 8).unwrap(),
1771            NaiveTime::from_hms_nano_opt(13, 42, 29, 190855000).unwrap(),
1772        );
1773
1774        // Ensure both T and ' ' variants work
1775        assert_eq!(
1776            naive_datetime.and_utc().timestamp_nanos_opt().unwrap(),
1777            parse_timestamp("2020-09-08T13:42:29.190855").unwrap()
1778        );
1779
1780        assert_eq!(
1781            naive_datetime.and_utc().timestamp_nanos_opt().unwrap(),
1782            parse_timestamp("2020-09-08 13:42:29.190855").unwrap()
1783        );
1784
1785        let naive_datetime = NaiveDateTime::new(
1786            NaiveDate::from_ymd_opt(2020, 9, 8).unwrap(),
1787            NaiveTime::from_hms_nano_opt(13, 42, 29, 0).unwrap(),
1788        );
1789
1790        // Ensure both T and ' ' variants work
1791        assert_eq!(
1792            naive_datetime.and_utc().timestamp_nanos_opt().unwrap(),
1793            parse_timestamp("2020-09-08T13:42:29").unwrap()
1794        );
1795
1796        assert_eq!(
1797            naive_datetime.and_utc().timestamp_nanos_opt().unwrap(),
1798            parse_timestamp("2020-09-08 13:42:29").unwrap()
1799        );
1800
1801        let tz: Tz = "+02:00".parse().unwrap();
1802        let date = string_to_datetime(&tz, "2020-09-08 13:42:29").unwrap();
1803        let utc = date.naive_utc().to_string();
1804        assert_eq!(utc, "2020-09-08 11:42:29");
1805        let local = date.naive_local().to_string();
1806        assert_eq!(local, "2020-09-08 13:42:29");
1807
1808        let date = string_to_datetime(&tz, "2020-09-08 13:42:29Z").unwrap();
1809        let utc = date.naive_utc().to_string();
1810        assert_eq!(utc, "2020-09-08 13:42:29");
1811        let local = date.naive_local().to_string();
1812        assert_eq!(local, "2020-09-08 15:42:29");
1813
1814        let dt =
1815            NaiveDateTime::parse_from_str("2020-09-08T13:42:29Z", "%Y-%m-%dT%H:%M:%SZ").unwrap();
1816        let local: Tz = "+08:00".parse().unwrap();
1817
1818        // Parsed as offset from UTC
1819        let date = string_to_datetime(&local, "2020-09-08T13:42:29Z").unwrap();
1820        assert_eq!(dt, date.naive_utc());
1821        assert_ne!(dt, date.naive_local());
1822
1823        // Parsed as offset from local
1824        let date = string_to_datetime(&local, "2020-09-08 13:42:29").unwrap();
1825        assert_eq!(dt, date.naive_local());
1826        assert_ne!(dt, date.naive_utc());
1827    }
1828
1829    #[test]
1830    fn parse_date32() {
1831        let cases = [
1832            "2020-09-08",
1833            "2020-9-8",
1834            "2020-09-8",
1835            "2020-9-08",
1836            "2020-12-1",
1837            "1690-2-5",
1838            "2020-09-08 01:02:03",
1839        ];
1840        for case in cases {
1841            let v = date32_to_datetime(Date32Type::parse(case).unwrap()).unwrap();
1842            let expected = NaiveDate::parse_from_str(case, "%Y-%m-%d")
1843                .or(NaiveDate::parse_from_str(case, "%Y-%m-%d %H:%M:%S"))
1844                .unwrap();
1845            assert_eq!(v.date(), expected);
1846        }
1847
1848        let err_cases = [
1849            "",
1850            "80-01-01",
1851            "342",
1852            "Foo",
1853            "2020-09-08-03",
1854            "2020--04-03",
1855            "2020--",
1856            "2020-09-08 01",
1857            "2020-09-08 01:02",
1858            "2020-09-08 01-02-03",
1859            "2020-9-8 01:02:03",
1860            "2020-09-08 1:2:3",
1861        ];
1862        for case in err_cases {
1863            assert_eq!(Date32Type::parse(case), None);
1864        }
1865    }
1866
1867    #[test]
1868    fn parse_date32_extended_year() {
1869        // `Date32` covers any i32 days-from-epoch, verify we can parse it
1870        let cases: &[(&str, i32)] = &[
1871            ("+1970-01-01", 0),
1872            ("+2024-01-01", 19_723),
1873            ("-0001-01-01", -719_893),
1874            ("+29349-01-26", 10_000_000),
1875            ("+2739877-01-03", 1_000_000_000),
1876            // Extremes of the Date32 representable range.
1877            ("+5881580-07-11", i32::MAX),
1878            ("-5877641-06-23", i32::MIN),
1879        ];
1880        for (input, expected) in cases {
1881            assert_eq!(Date32Type::parse(input), Some(*expected), "input: {input}");
1882        }
1883
1884        // One past Date32::MAX / MIN overflows i32 days-from-epoch.
1885        assert_eq!(Date32Type::parse("+5881580-07-12"), None);
1886        assert_eq!(Date32Type::parse("-5877641-06-22"), None);
1887        // Invalid calendar dates still rejected regardless of year magnitude.
1888        assert_eq!(Date32Type::parse("+2739877-02-30"), None);
1889        assert_eq!(Date32Type::parse("+2739877-13-01"), None);
1890        assert_eq!(Date32Type::parse("-2739877-02-30"), None);
1891    }
1892
1893    #[test]
1894    fn parse_time64_nanos() {
1895        assert_eq!(
1896            Time64NanosecondType::parse("02:10:01.1234567899999999"),
1897            Some(7_801_123_456_789)
1898        );
1899        assert_eq!(
1900            Time64NanosecondType::parse("02:10:01.1234567"),
1901            Some(7_801_123_456_700)
1902        );
1903        assert_eq!(
1904            Time64NanosecondType::parse("2:10:01.1234567"),
1905            Some(7_801_123_456_700)
1906        );
1907        assert_eq!(
1908            Time64NanosecondType::parse("12:10:01.123456789 AM"),
1909            Some(601_123_456_789)
1910        );
1911        assert_eq!(
1912            Time64NanosecondType::parse("12:10:01.123456789 am"),
1913            Some(601_123_456_789)
1914        );
1915        assert_eq!(
1916            Time64NanosecondType::parse("2:10:01.12345678 PM"),
1917            Some(51_001_123_456_780)
1918        );
1919        assert_eq!(
1920            Time64NanosecondType::parse("2:10:01.12345678 pm"),
1921            Some(51_001_123_456_780)
1922        );
1923        assert_eq!(
1924            Time64NanosecondType::parse("02:10:01"),
1925            Some(7_801_000_000_000)
1926        );
1927        assert_eq!(
1928            Time64NanosecondType::parse("2:10:01"),
1929            Some(7_801_000_000_000)
1930        );
1931        assert_eq!(
1932            Time64NanosecondType::parse("12:10:01 AM"),
1933            Some(601_000_000_000)
1934        );
1935        assert_eq!(
1936            Time64NanosecondType::parse("12:10:01 am"),
1937            Some(601_000_000_000)
1938        );
1939        assert_eq!(
1940            Time64NanosecondType::parse("2:10:01 PM"),
1941            Some(51_001_000_000_000)
1942        );
1943        assert_eq!(
1944            Time64NanosecondType::parse("2:10:01 pm"),
1945            Some(51_001_000_000_000)
1946        );
1947        assert_eq!(
1948            Time64NanosecondType::parse("02:10"),
1949            Some(7_800_000_000_000)
1950        );
1951        assert_eq!(Time64NanosecondType::parse("2:10"), Some(7_800_000_000_000));
1952        assert_eq!(
1953            Time64NanosecondType::parse("12:10 AM"),
1954            Some(600_000_000_000)
1955        );
1956        assert_eq!(
1957            Time64NanosecondType::parse("12:10 am"),
1958            Some(600_000_000_000)
1959        );
1960        assert_eq!(
1961            Time64NanosecondType::parse("2:10 PM"),
1962            Some(51_000_000_000_000)
1963        );
1964        assert_eq!(
1965            Time64NanosecondType::parse("2:10 pm"),
1966            Some(51_000_000_000_000)
1967        );
1968
1969        // parse directly as nanoseconds
1970        assert_eq!(Time64NanosecondType::parse("1"), Some(1));
1971
1972        // leap second
1973        assert_eq!(
1974            Time64NanosecondType::parse("23:59:60"),
1975            Some(86_400_000_000_000)
1976        );
1977
1978        // custom format
1979        assert_eq!(
1980            Time64NanosecondType::parse_formatted("02 - 10 - 01 - .1234567", "%H - %M - %S - %.f"),
1981            Some(7_801_123_456_700)
1982        );
1983    }
1984
1985    #[test]
1986    fn parse_time64_micros() {
1987        // expected formats
1988        assert_eq!(
1989            Time64MicrosecondType::parse("02:10:01.1234"),
1990            Some(7_801_123_400)
1991        );
1992        assert_eq!(
1993            Time64MicrosecondType::parse("2:10:01.1234"),
1994            Some(7_801_123_400)
1995        );
1996        assert_eq!(
1997            Time64MicrosecondType::parse("12:10:01.123456 AM"),
1998            Some(601_123_456)
1999        );
2000        assert_eq!(
2001            Time64MicrosecondType::parse("12:10:01.123456 am"),
2002            Some(601_123_456)
2003        );
2004        assert_eq!(
2005            Time64MicrosecondType::parse("2:10:01.12345 PM"),
2006            Some(51_001_123_450)
2007        );
2008        assert_eq!(
2009            Time64MicrosecondType::parse("2:10:01.12345 pm"),
2010            Some(51_001_123_450)
2011        );
2012        assert_eq!(
2013            Time64MicrosecondType::parse("02:10:01"),
2014            Some(7_801_000_000)
2015        );
2016        assert_eq!(Time64MicrosecondType::parse("2:10:01"), Some(7_801_000_000));
2017        assert_eq!(
2018            Time64MicrosecondType::parse("12:10:01 AM"),
2019            Some(601_000_000)
2020        );
2021        assert_eq!(
2022            Time64MicrosecondType::parse("12:10:01 am"),
2023            Some(601_000_000)
2024        );
2025        assert_eq!(
2026            Time64MicrosecondType::parse("2:10:01 PM"),
2027            Some(51_001_000_000)
2028        );
2029        assert_eq!(
2030            Time64MicrosecondType::parse("2:10:01 pm"),
2031            Some(51_001_000_000)
2032        );
2033        assert_eq!(Time64MicrosecondType::parse("02:10"), Some(7_800_000_000));
2034        assert_eq!(Time64MicrosecondType::parse("2:10"), Some(7_800_000_000));
2035        assert_eq!(Time64MicrosecondType::parse("12:10 AM"), Some(600_000_000));
2036        assert_eq!(Time64MicrosecondType::parse("12:10 am"), Some(600_000_000));
2037        assert_eq!(
2038            Time64MicrosecondType::parse("2:10 PM"),
2039            Some(51_000_000_000)
2040        );
2041        assert_eq!(
2042            Time64MicrosecondType::parse("2:10 pm"),
2043            Some(51_000_000_000)
2044        );
2045
2046        // parse directly as microseconds
2047        assert_eq!(Time64MicrosecondType::parse("1"), Some(1));
2048
2049        // leap second
2050        assert_eq!(
2051            Time64MicrosecondType::parse("23:59:60"),
2052            Some(86_400_000_000)
2053        );
2054
2055        // custom format
2056        assert_eq!(
2057            Time64MicrosecondType::parse_formatted("02 - 10 - 01 - .1234", "%H - %M - %S - %.f"),
2058            Some(7_801_123_400)
2059        );
2060    }
2061
2062    #[test]
2063    fn parse_time32_millis() {
2064        // expected formats
2065        assert_eq!(Time32MillisecondType::parse("02:10:01.1"), Some(7_801_100));
2066        assert_eq!(Time32MillisecondType::parse("2:10:01.1"), Some(7_801_100));
2067        assert_eq!(
2068            Time32MillisecondType::parse("12:10:01.123 AM"),
2069            Some(601_123)
2070        );
2071        assert_eq!(
2072            Time32MillisecondType::parse("12:10:01.123 am"),
2073            Some(601_123)
2074        );
2075        assert_eq!(
2076            Time32MillisecondType::parse("2:10:01.12 PM"),
2077            Some(51_001_120)
2078        );
2079        assert_eq!(
2080            Time32MillisecondType::parse("2:10:01.12 pm"),
2081            Some(51_001_120)
2082        );
2083        assert_eq!(Time32MillisecondType::parse("02:10:01"), Some(7_801_000));
2084        assert_eq!(Time32MillisecondType::parse("2:10:01"), Some(7_801_000));
2085        assert_eq!(Time32MillisecondType::parse("12:10:01 AM"), Some(601_000));
2086        assert_eq!(Time32MillisecondType::parse("12:10:01 am"), Some(601_000));
2087        assert_eq!(Time32MillisecondType::parse("2:10:01 PM"), Some(51_001_000));
2088        assert_eq!(Time32MillisecondType::parse("2:10:01 pm"), Some(51_001_000));
2089        assert_eq!(Time32MillisecondType::parse("02:10"), Some(7_800_000));
2090        assert_eq!(Time32MillisecondType::parse("2:10"), Some(7_800_000));
2091        assert_eq!(Time32MillisecondType::parse("12:10 AM"), Some(600_000));
2092        assert_eq!(Time32MillisecondType::parse("12:10 am"), Some(600_000));
2093        assert_eq!(Time32MillisecondType::parse("2:10 PM"), Some(51_000_000));
2094        assert_eq!(Time32MillisecondType::parse("2:10 pm"), Some(51_000_000));
2095
2096        // parse directly as milliseconds
2097        assert_eq!(Time32MillisecondType::parse("1"), Some(1));
2098
2099        // leap second
2100        assert_eq!(Time32MillisecondType::parse("23:59:60"), Some(86_400_000));
2101
2102        // custom format
2103        assert_eq!(
2104            Time32MillisecondType::parse_formatted("02 - 10 - 01 - .1", "%H - %M - %S - %.f"),
2105            Some(7_801_100)
2106        );
2107    }
2108
2109    #[test]
2110    fn parse_time32_secs() {
2111        // expected formats
2112        assert_eq!(Time32SecondType::parse("02:10:01.1"), Some(7_801));
2113        assert_eq!(Time32SecondType::parse("02:10:01"), Some(7_801));
2114        assert_eq!(Time32SecondType::parse("2:10:01"), Some(7_801));
2115        assert_eq!(Time32SecondType::parse("12:10:01 AM"), Some(601));
2116        assert_eq!(Time32SecondType::parse("12:10:01 am"), Some(601));
2117        assert_eq!(Time32SecondType::parse("2:10:01 PM"), Some(51_001));
2118        assert_eq!(Time32SecondType::parse("2:10:01 pm"), Some(51_001));
2119        assert_eq!(Time32SecondType::parse("02:10"), Some(7_800));
2120        assert_eq!(Time32SecondType::parse("2:10"), Some(7_800));
2121        assert_eq!(Time32SecondType::parse("12:10 AM"), Some(600));
2122        assert_eq!(Time32SecondType::parse("12:10 am"), Some(600));
2123        assert_eq!(Time32SecondType::parse("2:10 PM"), Some(51_000));
2124        assert_eq!(Time32SecondType::parse("2:10 pm"), Some(51_000));
2125
2126        // parse directly as seconds
2127        assert_eq!(Time32SecondType::parse("1"), Some(1));
2128
2129        // leap second
2130        assert_eq!(Time32SecondType::parse("23:59:60"), Some(86400));
2131
2132        // custom format
2133        assert_eq!(
2134            Time32SecondType::parse_formatted("02 - 10 - 01", "%H - %M - %S"),
2135            Some(7_801)
2136        );
2137    }
2138
2139    #[test]
2140    fn test_string_to_time_invalid() {
2141        let cases = [
2142            "25:00",
2143            "9:00:",
2144            "009:00",
2145            "09:0:00",
2146            "25:00:00",
2147            "13:00 AM",
2148            "13:00 PM",
2149            "12:00. AM",
2150            "09:0:00",
2151            "09:01:0",
2152            "09:01:1",
2153            "9:1:0",
2154            "09:01:0",
2155            "1:00.123",
2156            "1:00:00.123f",
2157            " 9:00:00",
2158            ":09:00",
2159            "T9:00:00",
2160            "AM",
2161        ];
2162        for case in cases {
2163            assert!(string_to_time(case).is_none(), "{case}");
2164        }
2165    }
2166
2167    #[test]
2168    fn test_string_to_time_chrono() {
2169        let cases = [
2170            ("1:00", "%H:%M"),
2171            ("12:00", "%H:%M"),
2172            ("13:00", "%H:%M"),
2173            ("24:00", "%H:%M"),
2174            ("1:00:00", "%H:%M:%S"),
2175            ("12:00:30", "%H:%M:%S"),
2176            ("13:00:59", "%H:%M:%S"),
2177            ("24:00:60", "%H:%M:%S"),
2178            ("09:00:00", "%H:%M:%S%.f"),
2179            ("0:00:30.123456", "%H:%M:%S%.f"),
2180            ("0:00 AM", "%I:%M %P"),
2181            ("1:00 AM", "%I:%M %P"),
2182            ("12:00 AM", "%I:%M %P"),
2183            ("13:00 AM", "%I:%M %P"),
2184            ("0:00 PM", "%I:%M %P"),
2185            ("1:00 PM", "%I:%M %P"),
2186            ("12:00 PM", "%I:%M %P"),
2187            ("13:00 PM", "%I:%M %P"),
2188            ("1:00 pM", "%I:%M %P"),
2189            ("1:00 Pm", "%I:%M %P"),
2190            ("1:00 aM", "%I:%M %P"),
2191            ("1:00 Am", "%I:%M %P"),
2192            ("1:00:30.123456 PM", "%I:%M:%S%.f %P"),
2193            ("1:00:30.123456789 PM", "%I:%M:%S%.f %P"),
2194            ("1:00:30.123456789123 PM", "%I:%M:%S%.f %P"),
2195            ("1:00:30.1234 PM", "%I:%M:%S%.f %P"),
2196            ("1:00:30.123456 PM", "%I:%M:%S%.f %P"),
2197            ("1:00:30.123456789123456789 PM", "%I:%M:%S%.f %P"),
2198            ("1:00:30.12F456 PM", "%I:%M:%S%.f %P"),
2199        ];
2200        for (s, format) in cases {
2201            let chrono = NaiveTime::parse_from_str(s, format).ok();
2202            let custom = string_to_time(s);
2203            assert_eq!(chrono, custom, "{s}");
2204        }
2205    }
2206
2207    #[test]
2208    fn test_parse_interval() {
2209        let config = IntervalParseConfig::new(IntervalUnit::Month);
2210
2211        assert_eq!(
2212            Interval::new(1i32, 0i32, 0i64),
2213            Interval::parse("1 month", &config).unwrap(),
2214        );
2215
2216        assert_eq!(
2217            Interval::new(2i32, 0i32, 0i64),
2218            Interval::parse("2 month", &config).unwrap(),
2219        );
2220
2221        assert_eq!(
2222            Interval::new(-1i32, -18i32, -(NANOS_PER_DAY / 5)),
2223            Interval::parse("-1.5 months -3.2 days", &config).unwrap(),
2224        );
2225
2226        assert_eq!(
2227            Interval::new(0i32, 15i32, 0),
2228            Interval::parse("0.5 months", &config).unwrap(),
2229        );
2230
2231        assert_eq!(
2232            Interval::new(0i32, 15i32, 0),
2233            Interval::parse(".5 months", &config).unwrap(),
2234        );
2235
2236        assert_eq!(
2237            Interval::new(0i32, -15i32, 0),
2238            Interval::parse("-0.5 months", &config).unwrap(),
2239        );
2240
2241        assert_eq!(
2242            Interval::new(0i32, -15i32, 0),
2243            Interval::parse("-.5 months", &config).unwrap(),
2244        );
2245
2246        assert_eq!(
2247            Interval::new(2i32, 10i32, 9 * NANOS_PER_HOUR),
2248            Interval::parse("2.1 months 7.25 days 3 hours", &config).unwrap(),
2249        );
2250
2251        assert_eq!(
2252            Interval::parse("1 centurys 1 month", &config)
2253                .unwrap_err()
2254                .to_string(),
2255            r#"Parser error: Invalid input syntax for type interval: "1 centurys 1 month""#
2256        );
2257
2258        assert_eq!(
2259            Interval::new(37i32, 0i32, 0i64),
2260            Interval::parse("3 year 1 month", &config).unwrap(),
2261        );
2262
2263        assert_eq!(
2264            Interval::new(35i32, 0i32, 0i64),
2265            Interval::parse("3 year -1 month", &config).unwrap(),
2266        );
2267
2268        assert_eq!(
2269            Interval::new(-37i32, 0i32, 0i64),
2270            Interval::parse("-3 year -1 month", &config).unwrap(),
2271        );
2272
2273        assert_eq!(
2274            Interval::new(-35i32, 0i32, 0i64),
2275            Interval::parse("-3 year 1 month", &config).unwrap(),
2276        );
2277
2278        assert_eq!(
2279            Interval::new(0i32, 5i32, 0i64),
2280            Interval::parse("5 days", &config).unwrap(),
2281        );
2282
2283        assert_eq!(
2284            Interval::new(0i32, 7i32, 3 * NANOS_PER_HOUR),
2285            Interval::parse("7 days 3 hours", &config).unwrap(),
2286        );
2287
2288        assert_eq!(
2289            Interval::new(0i32, 7i32, 5 * NANOS_PER_MINUTE),
2290            Interval::parse("7 days 5 minutes", &config).unwrap(),
2291        );
2292
2293        assert_eq!(
2294            Interval::new(0i32, 7i32, -5 * NANOS_PER_MINUTE),
2295            Interval::parse("7 days -5 minutes", &config).unwrap(),
2296        );
2297
2298        assert_eq!(
2299            Interval::new(0i32, -7i32, 5 * NANOS_PER_HOUR),
2300            Interval::parse("-7 days 5 hours", &config).unwrap(),
2301        );
2302
2303        assert_eq!(
2304            Interval::new(
2305                0i32,
2306                -7i32,
2307                -5 * NANOS_PER_HOUR - 5 * NANOS_PER_MINUTE - 5 * NANOS_PER_SECOND
2308            ),
2309            Interval::parse("-7 days -5 hours -5 minutes -5 seconds", &config).unwrap(),
2310        );
2311
2312        assert_eq!(
2313            Interval::new(12i32, 0i32, 25 * NANOS_PER_MILLIS),
2314            Interval::parse("1 year 25 millisecond", &config).unwrap(),
2315        );
2316
2317        assert_eq!(
2318            Interval::new(
2319                12i32,
2320                1i32,
2321                (NANOS_PER_SECOND as f64 * 0.000000001_f64) as i64
2322            ),
2323            Interval::parse("1 year 1 day 0.000000001 seconds", &config).unwrap(),
2324        );
2325
2326        assert_eq!(
2327            Interval::new(12i32, 1i32, NANOS_PER_MILLIS / 10),
2328            Interval::parse("1 year 1 day 0.1 milliseconds", &config).unwrap(),
2329        );
2330
2331        assert_eq!(
2332            Interval::new(12i32, 1i32, 1000i64),
2333            Interval::parse("1 year 1 day 1 microsecond", &config).unwrap(),
2334        );
2335
2336        assert_eq!(
2337            Interval::new(12i32, 1i32, 1i64),
2338            Interval::parse("1 year 1 day 1 nanoseconds", &config).unwrap(),
2339        );
2340
2341        assert_eq!(
2342            Interval::new(1i32, 0i32, -NANOS_PER_SECOND),
2343            Interval::parse("1 month -1 second", &config).unwrap(),
2344        );
2345
2346        assert_eq!(
2347            Interval::new(
2348                -13i32,
2349                -8i32,
2350                -NANOS_PER_HOUR
2351                    - NANOS_PER_MINUTE
2352                    - NANOS_PER_SECOND
2353                    - (1.11_f64 * NANOS_PER_MILLIS as f64) as i64
2354            ),
2355            Interval::parse(
2356                "-1 year -1 month -1 week -1 day -1 hour -1 minute -1 second -1.11 millisecond",
2357                &config
2358            )
2359            .unwrap(),
2360        );
2361
2362        // no units
2363        assert_eq!(
2364            Interval::new(1, 0, 0),
2365            Interval::parse("1", &config).unwrap()
2366        );
2367        assert_eq!(
2368            Interval::new(42, 0, 0),
2369            Interval::parse("42", &config).unwrap()
2370        );
2371        assert_eq!(
2372            Interval::new(0, 0, 42_000_000_000),
2373            Interval::parse("42", &IntervalParseConfig::new(IntervalUnit::Second)).unwrap()
2374        );
2375
2376        // shorter units
2377        assert_eq!(
2378            Interval::new(1, 0, 0),
2379            Interval::parse("1 mon", &config).unwrap()
2380        );
2381        assert_eq!(
2382            Interval::new(1, 0, 0),
2383            Interval::parse("1 mons", &config).unwrap()
2384        );
2385        assert_eq!(
2386            Interval::new(0, 0, 1_000_000),
2387            Interval::parse("1 ms", &config).unwrap()
2388        );
2389        assert_eq!(
2390            Interval::new(0, 0, 1_000),
2391            Interval::parse("1 us", &config).unwrap()
2392        );
2393
2394        // no space
2395        assert_eq!(
2396            Interval::new(0, 0, 1_000),
2397            Interval::parse("1us", &config).unwrap()
2398        );
2399        assert_eq!(
2400            Interval::new(0, 0, NANOS_PER_SECOND),
2401            Interval::parse("1s", &config).unwrap()
2402        );
2403        assert_eq!(
2404            Interval::new(1, 2, 10_864_000_000_000),
2405            Interval::parse("1mon 2days 3hr 1min 4sec", &config).unwrap()
2406        );
2407
2408        assert_eq!(
2409            Interval::new(
2410                -13i32,
2411                -8i32,
2412                -NANOS_PER_HOUR
2413                    - NANOS_PER_MINUTE
2414                    - NANOS_PER_SECOND
2415                    - (1.11_f64 * NANOS_PER_MILLIS as f64) as i64
2416            ),
2417            Interval::parse(
2418                "-1year -1month -1week -1day -1 hour -1 minute -1 second -1.11millisecond",
2419                &config
2420            )
2421            .unwrap(),
2422        );
2423
2424        assert_eq!(
2425            Interval::parse("1h s", &config).unwrap_err().to_string(),
2426            r#"Parser error: Invalid input syntax for type interval: "1h s""#
2427        );
2428
2429        assert_eq!(
2430            Interval::parse("1XX", &config).unwrap_err().to_string(),
2431            r#"Parser error: Invalid input syntax for type interval: "1XX""#
2432        );
2433    }
2434
2435    #[test]
2436    fn test_duplicate_interval_type() {
2437        let config = IntervalParseConfig::new(IntervalUnit::Month);
2438
2439        let err = Interval::parse("1 month 1 second 1 second", &config)
2440            .expect_err("parsing interval should have failed");
2441        assert_eq!(
2442            r#"ParseError("Invalid input syntax for type interval: \"1 month 1 second 1 second\". Repeated type 'second'")"#,
2443            format!("{err:?}")
2444        );
2445
2446        // test with singular and plural forms
2447        let err = Interval::parse("1 century 2 centuries", &config)
2448            .expect_err("parsing interval should have failed");
2449        assert_eq!(
2450            r#"ParseError("Invalid input syntax for type interval: \"1 century 2 centuries\". Repeated type 'centuries'")"#,
2451            format!("{err:?}")
2452        );
2453    }
2454
2455    #[test]
2456    fn test_interval_amount_parsing() {
2457        // integer
2458        let result = IntervalAmount::from_str("123").unwrap();
2459        let expected = IntervalAmount::new(123, 0);
2460
2461        assert_eq!(result, expected);
2462
2463        // positive w/ fractional
2464        let result = IntervalAmount::from_str("0.3").unwrap();
2465        let expected = IntervalAmount::new(0, 3 * 10_i64.pow(INTERVAL_PRECISION - 1));
2466
2467        assert_eq!(result, expected);
2468
2469        // negative w/ fractional
2470        let result = IntervalAmount::from_str("-3.5").unwrap();
2471        let expected = IntervalAmount::new(-3, -5 * 10_i64.pow(INTERVAL_PRECISION - 1));
2472
2473        assert_eq!(result, expected);
2474
2475        // invalid: missing fractional
2476        let result = IntervalAmount::from_str("3.");
2477        assert!(result.is_err());
2478
2479        // invalid: sign in fractional
2480        let result = IntervalAmount::from_str("3.-5");
2481        assert!(result.is_err());
2482    }
2483
2484    #[test]
2485    fn test_interval_precision() {
2486        let config = IntervalParseConfig::new(IntervalUnit::Month);
2487
2488        let result = Interval::parse("100000.1 days", &config).unwrap();
2489        let expected = Interval::new(0_i32, 100_000_i32, NANOS_PER_DAY / 10);
2490
2491        assert_eq!(result, expected);
2492    }
2493
2494    #[test]
2495    fn test_interval_addition() {
2496        // add 4.1 centuries
2497        let start = Interval::new(1, 2, 3);
2498        let expected = Interval::new(4921, 2, 3);
2499
2500        let result = start
2501            .add(
2502                IntervalAmount::new(4, 10_i64.pow(INTERVAL_PRECISION - 1)),
2503                IntervalUnit::Century,
2504            )
2505            .unwrap();
2506
2507        assert_eq!(result, expected);
2508
2509        // add 10.25 decades
2510        let start = Interval::new(1, 2, 3);
2511        let expected = Interval::new(1231, 2, 3);
2512
2513        let result = start
2514            .add(
2515                IntervalAmount::new(10, 25 * 10_i64.pow(INTERVAL_PRECISION - 2)),
2516                IntervalUnit::Decade,
2517            )
2518            .unwrap();
2519
2520        assert_eq!(result, expected);
2521
2522        // add 30.3 years (reminder: Postgres logic does not spill to days/nanos when interval is larger than a month)
2523        let start = Interval::new(1, 2, 3);
2524        let expected = Interval::new(364, 2, 3);
2525
2526        let result = start
2527            .add(
2528                IntervalAmount::new(30, 3 * 10_i64.pow(INTERVAL_PRECISION - 1)),
2529                IntervalUnit::Year,
2530            )
2531            .unwrap();
2532
2533        assert_eq!(result, expected);
2534
2535        // add 1.5 months
2536        let start = Interval::new(1, 2, 3);
2537        let expected = Interval::new(2, 17, 3);
2538
2539        let result = start
2540            .add(
2541                IntervalAmount::new(1, 5 * 10_i64.pow(INTERVAL_PRECISION - 1)),
2542                IntervalUnit::Month,
2543            )
2544            .unwrap();
2545
2546        assert_eq!(result, expected);
2547
2548        // add -2 weeks
2549        let start = Interval::new(1, 25, 3);
2550        let expected = Interval::new(1, 11, 3);
2551
2552        let result = start
2553            .add(IntervalAmount::new(-2, 0), IntervalUnit::Week)
2554            .unwrap();
2555
2556        assert_eq!(result, expected);
2557
2558        // add 2.2 days
2559        let start = Interval::new(12, 15, 3);
2560        let expected = Interval::new(12, 17, 3 + 17_280 * NANOS_PER_SECOND);
2561
2562        let result = start
2563            .add(
2564                IntervalAmount::new(2, 2 * 10_i64.pow(INTERVAL_PRECISION - 1)),
2565                IntervalUnit::Day,
2566            )
2567            .unwrap();
2568
2569        assert_eq!(result, expected);
2570
2571        // add 12.5 hours
2572        let start = Interval::new(1, 2, 3);
2573        let expected = Interval::new(1, 2, 3 + 45_000 * NANOS_PER_SECOND);
2574
2575        let result = start
2576            .add(
2577                IntervalAmount::new(12, 5 * 10_i64.pow(INTERVAL_PRECISION - 1)),
2578                IntervalUnit::Hour,
2579            )
2580            .unwrap();
2581
2582        assert_eq!(result, expected);
2583
2584        // add -1.5 minutes
2585        let start = Interval::new(0, 0, -3);
2586        let expected = Interval::new(0, 0, -90_000_000_000 - 3);
2587
2588        let result = start
2589            .add(
2590                IntervalAmount::new(-1, -5 * 10_i64.pow(INTERVAL_PRECISION - 1)),
2591                IntervalUnit::Minute,
2592            )
2593            .unwrap();
2594
2595        assert_eq!(result, expected);
2596    }
2597
2598    #[test]
2599    fn string_to_timestamp_old() {
2600        parse_timestamp("1677-06-14T07:29:01.256")
2601            .map_err(|e| assert!(e.to_string().ends_with(ERR_NANOSECONDS_NOT_SUPPORTED)))
2602            .unwrap_err();
2603    }
2604
2605    #[test]
2606    fn test_parse_decimal_with_parameter() {
2607        let tests = [
2608            ("0", 0i128),
2609            ("123.123", 123123i128),
2610            ("123.1234", 123123i128),
2611            ("123.1", 123100i128),
2612            ("123", 123000i128),
2613            ("-123.123", -123123i128),
2614            ("-123.1234", -123123i128),
2615            ("-123.1", -123100i128),
2616            ("-123", -123000i128),
2617            ("0.0000123", 0i128),
2618            ("12.", 12000i128),
2619            ("-12.", -12000i128),
2620            ("00.1", 100i128),
2621            ("-00.1", -100i128),
2622            ("12345678912345678.1234", 12345678912345678123i128),
2623            ("-12345678912345678.1234", -12345678912345678123i128),
2624            ("99999999999999999.999", 99999999999999999999i128),
2625            ("-99999999999999999.999", -99999999999999999999i128),
2626            (".123", 123i128),
2627            ("-.123", -123i128),
2628            ("123.", 123000i128),
2629            ("-123.", -123000i128),
2630        ];
2631        for (s, i) in tests {
2632            let result_128 = parse_decimal::<Decimal128Type>(s, 20, 3);
2633            assert_eq!(i, result_128.unwrap());
2634            let result_256 = parse_decimal::<Decimal256Type>(s, 20, 3);
2635            assert_eq!(i256::from_i128(i), result_256.unwrap());
2636        }
2637
2638        let e_notation_tests = [
2639            ("1.23e3", "1230.0", 2),
2640            ("5.6714e+2", "567.14", 4),
2641            ("5.6714e-2", "0.056714", 4),
2642            ("5.6714e-2", "0.056714", 3),
2643            ("5.6741214125e2", "567.41214125", 4),
2644            ("8.91E4", "89100.0", 2),
2645            ("3.14E+5", "314000.0", 2),
2646            ("2.718e0", "2.718", 2),
2647            ("9.999999e-1", "0.9999999", 4),
2648            ("1.23e+3", "1230", 2),
2649            ("1.234559e+3", "1234.559", 2),
2650            ("1.00E-10", "0.0000000001", 11),
2651            ("1.23e-4", "0.000123", 2),
2652            ("9.876e7", "98760000.0", 2),
2653            ("5.432E+8", "543200000.0", 10),
2654            ("1.234567e9", "1234567000.0", 2),
2655            ("1.234567e2", "123.45670000", 2),
2656            ("4749.3e-5", "0.047493", 10),
2657            ("4749.3e+5", "474930000", 10),
2658            ("4749.3e-5", "0.047493", 1),
2659            ("4749.3e+5", "474930000", 1),
2660            ("0E-8", "0", 10),
2661            ("0E+6", "0", 10),
2662            ("1E-8", "0.00000001", 10),
2663            ("12E+6", "12000000", 10),
2664            ("12E-6", "0.000012", 10),
2665            ("0.1e-6", "0.0000001", 10),
2666            ("0.1e+6", "100000", 10),
2667            ("0.12e-6", "0.00000012", 10),
2668            ("0.12e+6", "120000", 10),
2669            ("000000000001e0", "000000000001", 3),
2670            ("000001.1034567002e0", "000001.1034567002", 3),
2671            ("1.234e16", "12340000000000000", 0),
2672            ("123.4e16", "1234000000000000000", 0),
2673        ];
2674        for (e, d, scale) in e_notation_tests {
2675            let result_128_e = parse_decimal::<Decimal128Type>(e, 20, scale);
2676            let result_128_d = parse_decimal::<Decimal128Type>(d, 20, scale);
2677            assert_eq!(result_128_e.unwrap(), result_128_d.unwrap());
2678            let result_256_e = parse_decimal::<Decimal256Type>(e, 20, scale);
2679            let result_256_d = parse_decimal::<Decimal256Type>(d, 20, scale);
2680            assert_eq!(result_256_e.unwrap(), result_256_d.unwrap());
2681        }
2682        let can_not_parse_tests = [
2683            "123,123",
2684            ".",
2685            "123.123.123",
2686            "",
2687            "+",
2688            "-",
2689            "e",
2690            "1.3e+e3",
2691            "5.6714ee-2",
2692            "4.11ee-+4",
2693            "4.11e++4",
2694            "1.1e.12",
2695            "1.23e+3.",
2696            "1.23e+3.1",
2697            "1e",
2698            "1e+",
2699            "1e-",
2700        ];
2701        for s in can_not_parse_tests {
2702            let result_128 = parse_decimal::<Decimal128Type>(s, 20, 3);
2703            assert_eq!(
2704                format!("Parser error: can't parse the string value {s} to decimal"),
2705                result_128.unwrap_err().to_string()
2706            );
2707            let result_256 = parse_decimal::<Decimal256Type>(s, 20, 3);
2708            assert_eq!(
2709                format!("Parser error: can't parse the string value {s} to decimal"),
2710                result_256.unwrap_err().to_string()
2711            );
2712        }
2713        let overflow_parse_tests = [
2714            ("12345678", 3),
2715            ("1.2345678e7", 3),
2716            ("12345678.9", 3),
2717            ("1.23456789e+7", 3),
2718            ("99999999.99", 3),
2719            ("9.999999999e7", 3),
2720            ("12345678908765.123456", 3),
2721            ("123456789087651234.56e-4", 3),
2722            ("1234560000000", 0),
2723            ("12345678900.0", 0),
2724            ("1.23456e12", 0),
2725        ];
2726        for (s, scale) in overflow_parse_tests {
2727            let result_128 = parse_decimal::<Decimal128Type>(s, 10, scale);
2728            let expected_128 = "Parser error: parse decimal overflow";
2729            let actual_128 = result_128.unwrap_err().to_string();
2730
2731            assert!(
2732                actual_128.contains(expected_128),
2733                "actual: '{actual_128}', expected: '{expected_128}'"
2734            );
2735
2736            let result_256 = parse_decimal::<Decimal256Type>(s, 10, scale);
2737            let expected_256 = "Parser error: parse decimal overflow";
2738            let actual_256 = result_256.unwrap_err().to_string();
2739
2740            assert!(
2741                actual_256.contains(expected_256),
2742                "actual: '{actual_256}', expected: '{expected_256}'"
2743            );
2744        }
2745
2746        let edge_tests_128 = [
2747            (
2748                "99999999999999999999999999999999999999",
2749                99999999999999999999999999999999999999i128,
2750                0,
2751            ),
2752            (
2753                "999999999999999999999999999999999999.99",
2754                99999999999999999999999999999999999999i128,
2755                2,
2756            ),
2757            (
2758                "9999999999999999999999999.9999999999999",
2759                99999999999999999999999999999999999999i128,
2760                13,
2761            ),
2762            (
2763                "9999999999999999999999999",
2764                99999999999999999999999990000000000000i128,
2765                13,
2766            ),
2767            (
2768                "0.99999999999999999999999999999999999999",
2769                99999999999999999999999999999999999999i128,
2770                38,
2771            ),
2772            (
2773                "0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001016744",
2774                0i128,
2775                15,
2776            ),
2777            ("1.016744e-320", 0i128, 15),
2778            ("-1e3", -1000000000i128, 6),
2779            ("+1e3", 1000000000i128, 6),
2780            ("-1e31", -10000000000000000000000000000000000000i128, 6),
2781        ];
2782        for (s, i, scale) in edge_tests_128 {
2783            let result_128 = parse_decimal::<Decimal128Type>(s, 38, scale);
2784            assert_eq!(i, result_128.unwrap());
2785        }
2786        let edge_tests_256 = [
2787            (
2788                "9999999999999999999999999999999999999999999999999999999999999999999999999999",
2789                i256::from_string(
2790                    "9999999999999999999999999999999999999999999999999999999999999999999999999999",
2791                )
2792                .unwrap(),
2793                0,
2794            ),
2795            (
2796                "999999999999999999999999999999999999999999999999999999999999999999999999.9999",
2797                i256::from_string(
2798                    "9999999999999999999999999999999999999999999999999999999999999999999999999999",
2799                )
2800                .unwrap(),
2801                4,
2802            ),
2803            (
2804                "99999999999999999999999999999999999999999999999999.99999999999999999999999999",
2805                i256::from_string(
2806                    "9999999999999999999999999999999999999999999999999999999999999999999999999999",
2807                )
2808                .unwrap(),
2809                26,
2810            ),
2811            (
2812                "9.999999999999999999999999999999999999999999999999999999999999999999999999999e49",
2813                i256::from_string(
2814                    "9999999999999999999999999999999999999999999999999999999999999999999999999999",
2815                )
2816                .unwrap(),
2817                26,
2818            ),
2819            (
2820                "99999999999999999999999999999999999999999999999999",
2821                i256::from_string(
2822                    "9999999999999999999999999999999999999999999999999900000000000000000000000000",
2823                )
2824                .unwrap(),
2825                26,
2826            ),
2827            (
2828                "9.9999999999999999999999999999999999999999999999999e+49",
2829                i256::from_string(
2830                    "9999999999999999999999999999999999999999999999999900000000000000000000000000",
2831                )
2832                .unwrap(),
2833                26,
2834            ),
2835        ];
2836        for (s, i, scale) in edge_tests_256 {
2837            let result = parse_decimal::<Decimal256Type>(s, 76, scale);
2838            assert_eq!(i, result.unwrap());
2839        }
2840
2841        let zero_scale_tests = [
2842            (".123", 0, 3),
2843            ("0.123", 0, 3),
2844            ("1.0", 1, 3),
2845            ("1.2", 1, 3),
2846            ("1.00", 1, 3),
2847            ("1.23", 1, 3),
2848            ("1.000", 1, 3),
2849            ("1.123", 1, 3),
2850            ("123.0", 123, 3),
2851            ("123.4", 123, 3),
2852            ("123.00", 123, 3),
2853            ("123.45", 123, 3),
2854            ("123.000000000000000000004", 123, 3),
2855            ("0.123e2", 12, 3),
2856            ("0.123e4", 1230, 10),
2857            ("1.23e4", 12300, 10),
2858            ("12.3e4", 123000, 10),
2859            ("123e4", 1230000, 10),
2860            (
2861                "20000000000000000000000000000000000002.0",
2862                20000000000000000000000000000000000002,
2863                38,
2864            ),
2865        ];
2866        for (s, i, precision) in zero_scale_tests {
2867            let result_128 = parse_decimal::<Decimal128Type>(s, precision, 0).unwrap();
2868            assert_eq!(i, result_128);
2869        }
2870
2871        let can_not_parse_zero_scale = [".", "blag", "", "+", "-", "e"];
2872        for s in can_not_parse_zero_scale {
2873            let result_128 = parse_decimal::<Decimal128Type>(s, 5, 0);
2874            assert_eq!(
2875                format!("Parser error: can't parse the string value {s} to decimal"),
2876                result_128.unwrap_err().to_string(),
2877            );
2878        }
2879    }
2880
2881    #[test]
2882    fn test_parse_empty() {
2883        assert_eq!(Int32Type::parse(""), None);
2884        assert_eq!(Int64Type::parse(""), None);
2885        assert_eq!(UInt32Type::parse(""), None);
2886        assert_eq!(UInt64Type::parse(""), None);
2887        assert_eq!(Float32Type::parse(""), None);
2888        assert_eq!(Float64Type::parse(""), None);
2889        assert_eq!(Int32Type::parse("+"), None);
2890        assert_eq!(Int64Type::parse("+"), None);
2891        assert_eq!(UInt32Type::parse("+"), None);
2892        assert_eq!(UInt64Type::parse("+"), None);
2893        assert_eq!(Float32Type::parse("+"), None);
2894        assert_eq!(Float64Type::parse("+"), None);
2895        assert_eq!(TimestampNanosecondType::parse(""), None);
2896        assert_eq!(Date32Type::parse(""), None);
2897    }
2898
2899    #[test]
2900    fn test_parse_interval_month_day_nano_config() {
2901        let interval = parse_interval_month_day_nano_config(
2902            "1",
2903            IntervalParseConfig::new(IntervalUnit::Second),
2904        )
2905        .unwrap();
2906        assert_eq!(interval.months, 0);
2907        assert_eq!(interval.days, 0);
2908        assert_eq!(interval.nanoseconds, NANOS_PER_SECOND);
2909    }
2910    #[test]
2911    fn test_parse_prefix_white_space() {
2912        assert_eq!(Float64Type::parse(" 1.5"), Some(1.5));
2913        assert_eq!(Float64Type::parse("\t\n 20.54"), Some(20.54));
2914        assert_eq!(Float64Type::parse("\n2.5"), Some(2.5));
2915        assert_eq!(Float64Type::parse("\n-942.5423"), Some(-942.5423));
2916        assert_eq!(Float64Type::parse("\n\t\n\t\n40.5123"), Some(40.5123));
2917        assert_eq!(Float64Type::parse(" 1.5"), Some(1.5));
2918        assert_eq!(Float64Type::parse("\n\t\n\t\n-40.5123"), Some(-40.5123));
2919        assert_eq!(Float64Type::parse(" -1.5"), Some(-1.5));
2920        assert_eq!(Int32Type::parse(" 3"), Some(3));
2921        assert_eq!(Int32Type::parse("          30"), Some(30));
2922        assert_eq!(Int32Type::parse("\n \n 100"), Some(100));
2923        assert_eq!(Int32Type::parse(" \n25"), Some(25));
2924        assert_eq!(Int32Type::parse("\t800"), Some(800));
2925        assert_eq!(Int32Type::parse("\t  \n \t 851"), Some(851));
2926        assert_eq!(Int32Type::parse("\t\n\t\n\n\n\t1"), Some(1));
2927        assert_eq!(Int32Type::parse(" \n-25"), Some(-25));
2928        assert_eq!(Int32Type::parse("\t-800"), Some(-800));
2929
2930        // suffix whitespace
2931        assert_eq!(Float64Type::parse("1.5 "), Some(1.5));
2932        assert_eq!(Float64Type::parse("40.5123\n"), Some(40.5123));
2933        assert_eq!(Float64Type::parse("40.5123\n\t\n\t\n"), Some(40.5123));
2934        assert_eq!(Float64Type::parse("-942.5423\t"), Some(-942.5423));
2935        assert_eq!(Int32Type::parse("3 "), Some(3));
2936        assert_eq!(Int32Type::parse("30          "), Some(30));
2937        assert_eq!(Int32Type::parse("-25 \n"), Some(-25));
2938        assert_eq!(Int32Type::parse("800\t"), Some(800));
2939        // whitespace on both sides
2940        assert_eq!(Float64Type::parse(" 1.5 "), Some(1.5));
2941        assert_eq!(Float64Type::parse("\t\n 20.54 \t"), Some(20.54));
2942        assert_eq!(Float64Type::parse("\n-942.5423\n"), Some(-942.5423));
2943        assert_eq!(Int32Type::parse(" 3 "), Some(3));
2944        assert_eq!(Int32Type::parse("\n \n 100 \n"), Some(100));
2945        assert_eq!(Int32Type::parse("\t-800\t\n"), Some(-800));
2946
2947        // trailing non-whitespace chars should not parse
2948        assert_eq!(Float64Type::parse("1.5abc"), None);
2949        assert_eq!(Float64Type::parse("40.5123x"), None);
2950        assert_eq!(Int32Type::parse("30x"), None);
2951        assert_eq!(Int32Type::parse("100px"), None);
2952        assert_eq!(Int32Type::parse("-25!"), None);
2953        assert_eq!(Int32Type::parse("3j"), None);
2954        assert_eq!(Int32Type::parse("3"), Some(3));
2955    }
2956}