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