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::MIN);
189        return timezone
190            .from_local_datetime(&datetime)
191            .single()
192            .ok_or_else(|| err("error computing timezone offset"));
193    }
194
195    if !parser.test(10, b'T') && !parser.test(10, b't') && !parser.test(10, b' ') {
196        return Err(err("invalid timestamp separator"));
197    }
198
199    let (time, mut tz_offset) = parser.time().ok_or_else(|| err("error parsing time"))?;
200    let datetime = date.and_time(time);
201
202    if tz_offset == 32 {
203        // Decimal overrun
204        while tz_offset < bytes.len() && bytes[tz_offset].is_ascii_digit() {
205            tz_offset += 1;
206        }
207    }
208
209    if bytes.len() <= tz_offset {
210        return timezone
211            .from_local_datetime(&datetime)
212            .single()
213            .ok_or_else(|| err("error computing timezone offset"));
214    }
215
216    if (bytes[tz_offset] == b'z' || bytes[tz_offset] == b'Z') && tz_offset == bytes.len() - 1 {
217        return Ok(timezone.from_utc_datetime(&datetime));
218    }
219
220    // Parse remainder of string as timezone
221    let parsed_tz: Tz = s[tz_offset..].trim_start().parse()?;
222    let parsed = parsed_tz
223        .from_local_datetime(&datetime)
224        .single()
225        .ok_or_else(|| err("error computing timezone offset"))?;
226
227    Ok(parsed.with_timezone(timezone))
228}
229
230/// Accepts a string in RFC3339 / ISO8601 standard format and some
231/// variants and converts it to a nanosecond precision timestamp.
232///
233/// See [`string_to_datetime`] for the full set of supported formats
234///
235/// Implements the `to_timestamp` function to convert a string to a
236/// timestamp, following the model of spark SQL’s to_`timestamp`.
237///
238/// Internally, this function uses the `chrono` library for the
239/// datetime parsing
240///
241/// We hope to extend this function in the future with a second
242/// parameter to specifying the format string.
243///
244/// ## Timestamp Precision
245///
246/// Function uses the maximum precision timestamps supported by
247/// Arrow (nanoseconds stored as a 64-bit integer) timestamps. This
248/// means the range of dates that timestamps can represent is ~1677 AD
249/// to 2262 AM
250///
251/// ## Timezone / Offset Handling
252///
253/// Numerical values of timestamps are stored compared to offset UTC.
254///
255/// This function interprets string without an explicit time zone as timestamps
256/// relative to UTC, see [`string_to_datetime`] for alternative semantics
257///
258/// In particular:
259///
260/// ```
261/// # use arrow_cast::parse::string_to_timestamp_nanos;
262/// // Note all three of these timestamps are parsed as the same value
263/// let a = string_to_timestamp_nanos("1997-01-31 09:26:56.123Z").unwrap();
264/// let b = string_to_timestamp_nanos("1997-01-31T09:26:56.123").unwrap();
265/// let c = string_to_timestamp_nanos("1997-01-31T14:26:56.123+05:00").unwrap();
266///
267/// assert_eq!(a, b);
268/// assert_eq!(b, c);
269/// ```
270///
271#[inline]
272pub fn string_to_timestamp_nanos(s: &str) -> Result<i64, ArrowError> {
273    to_timestamp_nanos(string_to_datetime(&Utc, s)?.naive_utc())
274}
275
276/// Fallible conversion of [`NaiveDateTime`] to `i64` nanoseconds
277#[inline]
278fn to_timestamp_nanos(dt: NaiveDateTime) -> Result<i64, ArrowError> {
279    dt.and_utc()
280        .timestamp_nanos_opt()
281        .ok_or_else(|| ArrowError::ParseError(ERR_NANOSECONDS_NOT_SUPPORTED.to_string()))
282}
283
284/// Accepts a string in ISO8601 standard format and some
285/// variants and converts it to nanoseconds since midnight.
286///
287/// Examples of accepted inputs:
288///
289/// * `09:26:56.123 AM`
290/// * `23:59:59`
291/// * `6:00 pm`
292///
293/// Internally, this function uses the `chrono` library for the time parsing
294///
295/// ## Timezone / Offset Handling
296///
297/// This function does not support parsing strings with a timezone
298/// or offset specified, as it considers only time since midnight.
299pub fn string_to_time_nanoseconds(s: &str) -> Result<i64, ArrowError> {
300    let nt = string_to_time(s)
301        .ok_or_else(|| ArrowError::ParseError(format!("Failed to parse \'{s}\' as time")))?;
302    Ok(nt.num_seconds_from_midnight() as i64 * 1_000_000_000 + nt.nanosecond() as i64)
303}
304
305fn string_to_time(s: &str) -> Option<NaiveTime> {
306    let bytes = s.as_bytes();
307    if bytes.len() < 4 {
308        return None;
309    }
310
311    let (am, bytes) = match bytes.get(bytes.len() - 3..) {
312        Some(b" AM" | b" am" | b" Am" | b" aM") => (Some(true), &bytes[..bytes.len() - 3]),
313        Some(b" PM" | b" pm" | b" pM" | b" Pm") => (Some(false), &bytes[..bytes.len() - 3]),
314        _ => (None, bytes),
315    };
316
317    if bytes.len() < 4 {
318        return None;
319    }
320
321    let mut digits = [b'0'; 6];
322
323    // Extract hour
324    let bytes = match (bytes[1], bytes[2]) {
325        (b':', _) => {
326            digits[1] = bytes[0];
327            &bytes[2..]
328        }
329        (_, b':') => {
330            digits[0] = bytes[0];
331            digits[1] = bytes[1];
332            &bytes[3..]
333        }
334        _ => return None,
335    };
336
337    if bytes.len() < 2 {
338        return None; // Minutes required
339    }
340
341    // Extract minutes
342    digits[2] = bytes[0];
343    digits[3] = bytes[1];
344
345    let nanoseconds = match bytes.get(2) {
346        Some(b':') => {
347            if bytes.len() < 5 {
348                return None;
349            }
350
351            // Extract seconds
352            digits[4] = bytes[3];
353            digits[5] = bytes[4];
354
355            // Extract sub-seconds if any
356            match bytes.get(5) {
357                Some(b'.') => {
358                    let decimal = &bytes[6..];
359                    if decimal.iter().any(|x| !x.is_ascii_digit()) {
360                        return None;
361                    }
362                    match decimal.len() {
363                        0 => return None,
364                        1 => parse_nanos::<1, b'0'>(decimal),
365                        2 => parse_nanos::<2, b'0'>(decimal),
366                        3 => parse_nanos::<3, b'0'>(decimal),
367                        4 => parse_nanos::<4, b'0'>(decimal),
368                        5 => parse_nanos::<5, b'0'>(decimal),
369                        6 => parse_nanos::<6, b'0'>(decimal),
370                        7 => parse_nanos::<7, b'0'>(decimal),
371                        8 => parse_nanos::<8, b'0'>(decimal),
372                        _ => parse_nanos::<9, b'0'>(decimal),
373                    }
374                }
375                Some(_) => return None,
376                None => 0,
377            }
378        }
379        Some(_) => return None,
380        None => 0,
381    };
382
383    digits.iter_mut().for_each(|x| *x = x.wrapping_sub(b'0'));
384    if digits.iter().any(|x| *x > 9) {
385        return None;
386    }
387
388    let hour = match (digits[0] * 10 + digits[1], am) {
389        (12, Some(true)) => 0,               // 12:00 AM -> 00:00
390        (h @ 1..=11, Some(true)) => h,       // 1:00 AM -> 01:00
391        (12, Some(false)) => 12,             // 12:00 PM -> 12:00
392        (h @ 1..=11, Some(false)) => h + 12, // 1:00 PM -> 13:00
393        (_, Some(_)) => return None,
394        (h, None) => h,
395    };
396
397    // Handle leap second
398    let (second, nanoseconds) = match digits[4] * 10 + digits[5] {
399        60 => (59, nanoseconds + 1_000_000_000),
400        s => (s, nanoseconds),
401    };
402
403    NaiveTime::from_hms_nano_opt(
404        hour as _,
405        (digits[2] * 10 + digits[3]) as _,
406        second as _,
407        nanoseconds,
408    )
409}
410
411/// Specialized parsing implementations to convert strings to Arrow types.
412///
413/// This is used by csv and json reader and can be used directly as well.
414///
415/// # Example
416///
417/// To parse a string to a [`Date32Type`]:
418///
419/// ```
420/// use arrow_cast::parse::Parser;
421/// use arrow_array::types::Date32Type;
422/// let date = Date32Type::parse("2021-01-01").unwrap();
423/// assert_eq!(date, 18628);
424/// ```
425///
426/// To parse a string to a [`TimestampNanosecondType`]:
427///
428/// ```
429/// use arrow_cast::parse::Parser;
430/// use arrow_array::types::TimestampNanosecondType;
431/// let ts = TimestampNanosecondType::parse("2021-01-01T00:00:00.123456789Z").unwrap();
432/// assert_eq!(ts, 1609459200123456789);
433/// ```
434pub trait Parser: ArrowPrimitiveType {
435    /// Parse a string to the native type
436    fn parse(string: &str) -> Option<Self::Native>;
437
438    /// Parse a string to the native type with a format string
439    ///
440    /// When not implemented, the format string is unused, and this method is equivalent to [parse](#tymethod.parse)
441    fn parse_formatted(string: &str, _format: &str) -> Option<Self::Native> {
442        Self::parse(string)
443    }
444}
445
446impl Parser for Float16Type {
447    fn parse(string: &str) -> Option<f16> {
448        if let Ok(raw_float) = lexical_core::parse(string.as_bytes()) {
449            return Some(f16::from_f32(raw_float));
450        }
451        let string = trim_pre_and_post_whitespace(string);
452        lexical_core::parse(string.as_bytes())
453            .ok()
454            .map(f16::from_f32)
455    }
456}
457
458impl Parser for Float32Type {
459    fn parse(string: &str) -> Option<f32> {
460        if let Ok(raw_float) = lexical_core::parse(string.as_bytes()) {
461            return Some(raw_float);
462        }
463        let string = trim_pre_and_post_whitespace(string);
464        lexical_core::parse(string.as_bytes()).ok()
465    }
466}
467
468impl Parser for Float64Type {
469    fn parse(string: &str) -> Option<f64> {
470        if let Ok(raw_float) = lexical_core::parse(string.as_bytes()) {
471            return Some(raw_float);
472        }
473        let string = trim_pre_and_post_whitespace(string);
474        lexical_core::parse(string.as_bytes()).ok()
475    }
476}
477
478/// this is a no-op if the string starts and ends with a digit, otherwise it will trim whitespace from the start and end of the string.
479#[inline]
480fn trim_pre_and_post_whitespace(string: &str) -> &str {
481    let bytes = string.as_bytes();
482    let prefix = bytes.first().is_some_and(|b| !b.is_ascii_digit());
483    let suffix = bytes.last().is_some_and(|b| !b.is_ascii_digit());
484    match (prefix, suffix) {
485        (false, false) => string,
486        (true, false) => string.trim_ascii_start(),
487        (false, true) => string.trim_ascii_end(),
488        (true, true) => string.trim_ascii(),
489    }
490}
491
492macro_rules! parser_primitive {
493    ($t:ty) => {
494        impl Parser for $t {
495            fn parse(string: &str) -> Option<Self::Native> {
496                let mut raw_bytes = string.as_bytes();
497                if !raw_bytes.last().is_some_and(|x| x.is_ascii_digit()) {
498                    raw_bytes = raw_bytes.trim_ascii_end();
499                    if !raw_bytes.last().is_some_and(|x| x.is_ascii_digit()) {
500                        return None;
501                    }
502                }
503                match atoi::FromRadix10SignedChecked::from_radix_10_signed_checked(raw_bytes) {
504                    (Some(n), x) if x == raw_bytes.len() => Some(n),
505                    _ => {
506                        let trimmed = raw_bytes.trim_ascii_start();
507                        match atoi::FromRadix10SignedChecked::from_radix_10_signed_checked(trimmed)
508                        {
509                            (Some(n), x) if x == trimmed.len() => Some(n),
510                            _ => None,
511                        }
512                    }
513                }
514            }
515        }
516    };
517}
518parser_primitive!(UInt64Type);
519parser_primitive!(UInt32Type);
520parser_primitive!(UInt16Type);
521parser_primitive!(UInt8Type);
522parser_primitive!(Int64Type);
523parser_primitive!(Int32Type);
524parser_primitive!(Int16Type);
525parser_primitive!(Int8Type);
526parser_primitive!(DurationNanosecondType);
527parser_primitive!(DurationMicrosecondType);
528parser_primitive!(DurationMillisecondType);
529parser_primitive!(DurationSecondType);
530
531impl Parser for TimestampNanosecondType {
532    fn parse(string: &str) -> Option<i64> {
533        string_to_timestamp_nanos(string).ok()
534    }
535}
536
537impl Parser for TimestampMicrosecondType {
538    fn parse(string: &str) -> Option<i64> {
539        let nanos = string_to_timestamp_nanos(string).ok();
540        nanos.map(|x| x / 1000)
541    }
542}
543
544impl Parser for TimestampMillisecondType {
545    fn parse(string: &str) -> Option<i64> {
546        let nanos = string_to_timestamp_nanos(string).ok();
547        nanos.map(|x| x / 1_000_000)
548    }
549}
550
551impl Parser for TimestampSecondType {
552    fn parse(string: &str) -> Option<i64> {
553        let nanos = string_to_timestamp_nanos(string).ok();
554        nanos.map(|x| x / 1_000_000_000)
555    }
556}
557
558impl Parser for Time64NanosecondType {
559    // Will truncate any fractions of a nanosecond
560    fn parse(string: &str) -> Option<Self::Native> {
561        string_to_time_nanoseconds(string)
562            .ok()
563            .or_else(|| string.parse::<Self::Native>().ok())
564    }
565
566    fn parse_formatted(string: &str, format: &str) -> Option<Self::Native> {
567        let nt = NaiveTime::parse_from_str(string, format).ok()?;
568        Some(nt.num_seconds_from_midnight() as i64 * 1_000_000_000 + nt.nanosecond() as i64)
569    }
570}
571
572impl Parser for Time64MicrosecondType {
573    // Will truncate any fractions of a microsecond
574    fn parse(string: &str) -> Option<Self::Native> {
575        string_to_time_nanoseconds(string)
576            .ok()
577            .map(|nanos| nanos / 1_000)
578            .or_else(|| string.parse::<Self::Native>().ok())
579    }
580
581    fn parse_formatted(string: &str, format: &str) -> Option<Self::Native> {
582        let nt = NaiveTime::parse_from_str(string, format).ok()?;
583        Some(nt.num_seconds_from_midnight() as i64 * 1_000_000 + nt.nanosecond() as i64 / 1_000)
584    }
585}
586
587impl Parser for Time32MillisecondType {
588    // Will truncate any fractions of a millisecond
589    fn parse(string: &str) -> Option<Self::Native> {
590        string_to_time_nanoseconds(string)
591            .ok()
592            .map(|nanos| (nanos / 1_000_000) as i32)
593            .or_else(|| string.parse::<Self::Native>().ok())
594    }
595
596    fn parse_formatted(string: &str, format: &str) -> Option<Self::Native> {
597        let nt = NaiveTime::parse_from_str(string, format).ok()?;
598        Some(nt.num_seconds_from_midnight() as i32 * 1_000 + nt.nanosecond() as i32 / 1_000_000)
599    }
600}
601
602impl Parser for Time32SecondType {
603    // Will truncate any fractions of a second
604    fn parse(string: &str) -> Option<Self::Native> {
605        string_to_time_nanoseconds(string)
606            .ok()
607            .map(|nanos| (nanos / 1_000_000_000) as i32)
608            .or_else(|| string.parse::<Self::Native>().ok())
609    }
610
611    fn parse_formatted(string: &str, format: &str) -> Option<Self::Native> {
612        let nt = NaiveTime::parse_from_str(string, format).ok()?;
613        Some(nt.num_seconds_from_midnight() as i32 + nt.nanosecond() as i32 / 1_000_000_000)
614    }
615}
616
617/// Number of days between 0001-01-01 and 1970-01-01
618const EPOCH_DAYS_FROM_CE: i32 = 719_163;
619
620/// Error message if nanosecond conversion request beyond supported interval
621const ERR_NANOSECONDS_NOT_SUPPORTED: &str = "The dates that can be represented as nanoseconds have to be between 1677-09-21T00:12:44.0 and 2262-04-11T23:47:16.854775804";
622
623/// Parse the ISO 8601 signed extended-year form (`±YYYY[Y...]-MM-DD`) into
624/// raw `(year, month, day)` components, without validating the calendar date.
625///
626/// The caller must have already verified that `string` begins with `+` or `-`;
627/// the year must have at least 4 digits. Returns `None` if the shape is
628/// malformed or any component fails to parse numerically.
629fn parse_extended_ymd(string: &str) -> Option<(i32, u32, u32)> {
630    debug_assert!(string.starts_with('+') || string.starts_with('-'));
631    // Skip the sign and look for the hyphen that terminates the year digits.
632    // Per ISO 8601 the unsigned year part must be at least 4 digits.
633    let rest = &string[1..];
634    let hyphen = rest.find('-')?;
635    if hyphen < 4 {
636        return None;
637    }
638    // The year substring is the sign and the digits (but not the separator),
639    // e.g. for "+10999-12-31", hyphen is 5 and s[..6] is "+10999".
640    let year: i32 = string[..hyphen + 1].parse().ok()?;
641    // The remainder should begin with a '-' which we strip off, leaving the month-day part.
642    let remainder = string[hyphen + 1..].strip_prefix('-')?;
643    let mut parts = remainder.splitn(2, '-');
644    let month: u32 = parts.next()?.parse().ok()?;
645    let day: u32 = parts.next()?.parse().ok()?;
646    Some((year, month, day))
647}
648
649fn parse_date(string: &str) -> Option<NaiveDate> {
650    // If the date has an extended (signed) year such as "+10999-12-31" or "-0012-05-06"
651    //
652    // According to [ISO 8601], years have:
653    //  Four digits or more for the year. Years in the range 0000 to 9999 will be pre-padded by
654    //  zero to ensure four digits. Years outside that range will have a prefixed positive or negative symbol.
655    //
656    // [ISO 8601]: https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/format/DateTimeFormatter.html#ISO_LOCAL_DATE
657    if string.starts_with('+') || string.starts_with('-') {
658        let (year, month, day) = parse_extended_ymd(string)?;
659        return NaiveDate::from_ymd_opt(year, month, day);
660    }
661
662    if string.len() > 10 {
663        // Try to parse as datetime and return just the date part
664        return string_to_datetime(&Utc, string)
665            .map(|dt| dt.date_naive())
666            .ok();
667    }
668    let mut digits = [0; 10];
669    let mut mask = 0;
670
671    // Treating all bytes the same way, helps LLVM vectorise this correctly
672    for (idx, (o, i)) in digits.iter_mut().zip(string.bytes()).enumerate() {
673        *o = i.wrapping_sub(b'0');
674        mask |= ((*o < 10) as u16) << idx
675    }
676
677    const HYPHEN: u8 = b'-'.wrapping_sub(b'0');
678
679    //  refer to https://www.rfc-editor.org/rfc/rfc3339#section-3
680    if digits[4] != HYPHEN {
681        let (year, month, day) = match (mask, string.len()) {
682            (0b11111111, 8) => (
683                digits[0] as u16 * 1000
684                    + digits[1] as u16 * 100
685                    + digits[2] as u16 * 10
686                    + digits[3] as u16,
687                digits[4] * 10 + digits[5],
688                digits[6] * 10 + digits[7],
689            ),
690            _ => return None,
691        };
692        return NaiveDate::from_ymd_opt(year as _, month as _, day as _);
693    }
694
695    let (month, day) = match mask {
696        0b1101101111 => {
697            if digits[7] != HYPHEN {
698                return None;
699            }
700            (digits[5] * 10 + digits[6], digits[8] * 10 + digits[9])
701        }
702        0b101101111 => {
703            if digits[7] != HYPHEN {
704                return None;
705            }
706            (digits[5] * 10 + digits[6], digits[8])
707        }
708        0b110101111 => {
709            if digits[6] != HYPHEN {
710                return None;
711            }
712            (digits[5], digits[7] * 10 + digits[8])
713        }
714        0b10101111 => {
715            if digits[6] != HYPHEN {
716                return None;
717            }
718            (digits[5], digits[7])
719        }
720        _ => return None,
721    };
722
723    let year =
724        digits[0] as u16 * 1000 + digits[1] as u16 * 100 + digits[2] as u16 * 10 + digits[3] as u16;
725
726    NaiveDate::from_ymd_opt(year as _, month as _, day as _)
727}
728
729/// Parse a date string into days since 1970-01-01, covering the full
730/// `Date32` range (years ≈ ±5,881,580) for the signed extended-year form.
731///
732/// The Gregorian calendar repeats exactly every 400 years (146,097 days), so
733/// we fold the year into `[0, 400)`, validate the folded date, and add
734/// `era * 146_097` to recover the absolute day count.
735///
736/// For all other inputs, behavior matches [`parse_date`].
737fn parse_date_to_days(string: &str) -> Option<i32> {
738    if string.starts_with('+') || string.starts_with('-') {
739        let (year, month, day) = parse_extended_ymd(string)?;
740        let y = year as i64;
741        let era = y.div_euclid(400);
742        let yoe = y.rem_euclid(400) as i32;
743        let naive_date = NaiveDate::from_ymd_opt(yoe, month, day)?;
744        let in_era = (naive_date.num_days_from_ce() - EPOCH_DAYS_FROM_CE) as i64;
745        return i32::try_from(era * 146_097 + in_era).ok();
746    }
747    parse_date(string).map(|naive_date| naive_date.num_days_from_ce() - EPOCH_DAYS_FROM_CE)
748}
749
750impl Parser for Date32Type {
751    fn parse(string: &str) -> Option<i32> {
752        parse_date_to_days(string)
753    }
754
755    fn parse_formatted(string: &str, format: &str) -> Option<i32> {
756        let date = NaiveDate::parse_from_str(string, format).ok()?;
757        Some(date.num_days_from_ce() - EPOCH_DAYS_FROM_CE)
758    }
759}
760
761impl Parser for Date64Type {
762    fn parse(string: &str) -> Option<i64> {
763        if string.len() <= 10 {
764            let datetime = NaiveDateTime::new(parse_date(string)?, NaiveTime::default());
765            Some(datetime.and_utc().timestamp_millis())
766        } else {
767            let date_time = string_to_datetime(&Utc, string).ok()?;
768            Some(date_time.timestamp_millis())
769        }
770    }
771
772    fn parse_formatted(string: &str, format: &str) -> Option<i64> {
773        use chrono::format::Fixed;
774        use chrono::format::StrftimeItems;
775        let fmt = StrftimeItems::new(format);
776        let has_zone = fmt.into_iter().any(|item| match item {
777            chrono::format::Item::Fixed(fixed_item) => matches!(
778                fixed_item,
779                Fixed::RFC2822
780                    | Fixed::RFC3339
781                    | Fixed::TimezoneName
782                    | Fixed::TimezoneOffsetColon
783                    | Fixed::TimezoneOffsetColonZ
784                    | Fixed::TimezoneOffset
785                    | Fixed::TimezoneOffsetZ
786            ),
787            _ => false,
788        });
789        if has_zone {
790            let date_time = chrono::DateTime::parse_from_str(string, format).ok()?;
791            Some(date_time.timestamp_millis())
792        } else {
793            let date_time = NaiveDateTime::parse_from_str(string, format).ok()?;
794            Some(date_time.and_utc().timestamp_millis())
795        }
796    }
797}
798
799/// Parses the string representation of a decimal number into the unscaled
800/// native value of a decimal type with the given `precision` and `scale`.
801///
802/// The accepted syntax is:
803///
804/// ```text
805/// [whitespace] [+|-] digits [. [digits]] [(e|E) [+|-] digits] [whitespace]
806/// ```
807///
808/// or the same with the integer digits omitted (e.g. `.5`), as long as at
809/// least one digit is present in the mantissa. ASCII whitespace is trimmed
810/// from both ends. The exponent is applied before scaling, so `1.5e2` and
811/// `150` parse identically.
812///
813/// Fractional digits beyond `scale` are not stored but round the result half
814/// away from zero (e.g. `1.005` at scale 2 is `101`, `-1.005` is `-101`).
815/// Negative scales are supported and round the integer part in the same way
816/// (e.g. `150` at scale -2 is `2`).
817///
818/// Returns an error if the input is not a valid decimal string, or if the
819/// result does not fit the given precision.
820///
821/// # Example
822///
823/// ```
824/// # use arrow_array::types::Decimal128Type;
825/// # use arrow_cast::parse::parse_decimal;
826/// assert_eq!(parse_decimal::<Decimal128Type>("123.45", 10, 2).unwrap(), 12345);
827/// assert_eq!(parse_decimal::<Decimal128Type>("1.005", 10, 2).unwrap(), 101);
828/// assert_eq!(parse_decimal::<Decimal128Type>("1.5e2", 10, 0).unwrap(), 150);
829/// assert!(parse_decimal::<Decimal128Type>("1234.5", 5, 2).is_err()); // does not fit
830/// ```
831pub fn parse_decimal<T: DecimalType>(
832    s: &str,
833    precision: u8,
834    scale: i8,
835) -> Result<T::Native, ArrowError> {
836    parse_decimal_checked::<T>(s, precision, scale).map_err(|e| match e {
837        DecimalParseError::Overflow => ArrowError::ParseError(format!(
838            "{s:?} does not fit in {}({precision}, {scale})",
839            T::PREFIX
840        )),
841        DecimalParseError::InvalidFormat => {
842            ArrowError::ParseError(format!("Invalid decimal format: {s:?}"))
843        }
844    })
845}
846
847/// The reason a decimal string could not be parsed.
848#[derive(Debug, Clone, Copy, PartialEq, Eq)]
849pub(crate) enum DecimalParseError {
850    /// The input is not a valid decimal string
851    InvalidFormat,
852    /// The value does not fit in the precision or the native type of the decimal
853    Overflow,
854}
855
856/// Like [`parse_decimal`], but reports failures as a [`DecimalParseError`]
857/// instead of formatting an error message, for callers that discard or
858/// re-wrap the error.
859pub(crate) fn parse_decimal_checked<T: DecimalType>(
860    s: &str,
861    precision: u8,
862    scale: i8,
863) -> Result<T::Native, DecimalParseError> {
864    let (value, digits) = parse_decimal_native::<T>(s, scale)?;
865    // A value of at most `precision` digits is within the precision without
866    // inspecting it. A precision beyond the type's maximum is invalid.
867    let fits = precision <= T::MAX_PRECISION
868        && (digits <= precision as usize || T::is_valid_decimal_precision(value, precision));
869    if fits {
870        Ok(value)
871    } else {
872        Err(DecimalParseError::Overflow)
873    }
874}
875
876/// Parses `s` as a decimal with the given `scale` into the native type of `T`,
877/// checking only that the result fits the native type (not the precision),
878/// and returns it with an upper bound on its number of decimal digits.
879///
880/// See [`parse_decimal`] for the accepted syntax and rounding behaviour.
881#[inline]
882fn parse_decimal_native<T: DecimalType>(
883    s: &str,
884    scale: i8,
885) -> Result<(T::Native, usize), DecimalParseError> {
886    let bytes = s.as_bytes().trim_ascii();
887    let (negative, mut mantissa) = split_sign(bytes);
888
889    let mut scale = scale as i64;
890    loop {
891        let exponent_at = match parse_decimal_mantissa::<T>(mantissa, negative, scale) {
892            Ok(result) => return Ok(result),
893            Err(MantissaError::InvalidFormat) => return Err(DecimalParseError::InvalidFormat),
894            Err(MantissaError::Exponent(index)) => index,
895            // The digits before an exponent marker need not fit on their own
896            // (e.g. "4825037936439135476E-14"), so the overflow only stands
897            // if no marker follows
898            Err(MantissaError::Overflow) => mantissa
899                .iter()
900                .position(|b| matches!(b, b'e' | b'E'))
901                .ok_or(DecimalParseError::Overflow)?,
902        };
903
904        // If we saw an exponent, update the effective scale and rescan.
905        // Exponents are rare, so the risk of repeated work is preferable to
906        // the cost of scanning ahead for an exponent marker for every input.
907        let exponent = parse_decimal_exponent(&mantissa[exponent_at + 1..])?;
908        scale = scale.saturating_add(exponent);
909
910        // Trim the exponent so the next iteration succeeds without rescanning
911        mantissa = &mantissa[..exponent_at];
912    }
913}
914
915/// Why scanning the digits of a decimal string stopped.
916enum MantissaError {
917    /// The input is not a valid decimal string
918    InvalidFormat,
919    /// The value does not fit in the native type
920    Overflow,
921    /// An exponent marker (`e` or `E`) was found at the given byte offset
922    Exponent(usize),
923}
924
925impl From<DecimalParseError> for MantissaError {
926    fn from(e: DecimalParseError) -> Self {
927        match e {
928            DecimalParseError::InvalidFormat => Self::InvalidFormat,
929            DecimalParseError::Overflow => Self::Overflow,
930        }
931    }
932}
933
934/// The maximum number of decimal digits accumulated in a `u64` before the
935/// chunk is folded into the native value: every 18-digit number fits in a
936/// `u64`, and splits into two halves that each fit in a `u32` (see
937/// [`decimal_chunk_to_native`]).
938const MAX_CHUNK_DIGITS: usize = 18;
939
940/// Scans `mantissa` (digits with at most one decimal point; the sign has
941/// already been removed) and folds the digits that are significant at
942/// `scale` into a native value, rounding half away from zero on the first
943/// digit that is not. Also returns an upper bound on the number of decimal
944/// digits of the value: the digits kept, the zeros appended to reach the
945/// scale, and the digit that rounding up can add.
946#[inline]
947fn parse_decimal_mantissa<T: DecimalType>(
948    mantissa: &[u8],
949    negative: bool,
950    scale: i64,
951) -> Result<(T::Native, usize), MantissaError> {
952    // The number of integer and fractional digits that contribute to the
953    // result. For a non-negative scale that is every integer digit and the
954    // first `scale` fractional digits. For a negative scale the last `-scale`
955    // integer digits (and every fractional digit) only matter for rounding.
956    let (int_keep, frac_keep, mut round) = if scale >= 0 {
957        (
958            usize::MAX,
959            usize::try_from(scale).unwrap_or(usize::MAX),
960            true,
961        )
962    } else {
963        let int_digits = mantissa.iter().take_while(|b| b.is_ascii_digit()).count();
964        match usize::try_from(int_digits as i64 + scale) {
965            Ok(keep) => (keep, 0, true),
966            // Even the first digit is more than one position below the
967            // least significant digit of the result: the value rounds to
968            // zero regardless of what the digits are
969            Err(_) => (0, 0, false),
970        }
971    };
972
973    let mut acc = DecimalAccumulator::<T> {
974        value: T::Native::ZERO,
975        chunk: 0,
976        chunk_len: 0,
977        negative,
978    };
979    let mut int_kept = 0_usize;
980    let mut frac_kept = 0_usize;
981    let mut first_discarded_digit = None;
982
983    // Digits before the decimal point
984    let mut index = 0;
985    while let Some(&b) = mantissa.get(index) {
986        if !b.is_ascii_digit() {
987            break;
988        }
989        if int_kept < int_keep {
990            int_kept += 1;
991            acc.push(b - b'0')?;
992        } else {
993            first_discarded_digit.get_or_insert(b - b'0');
994        }
995        index += 1;
996    }
997
998    // Digits after the decimal point
999    if mantissa.get(index) == Some(&b'.') {
1000        index += 1;
1001        while let Some(&b) = mantissa.get(index) {
1002            if !b.is_ascii_digit() {
1003                break;
1004            }
1005            if frac_kept < frac_keep {
1006                frac_kept += 1;
1007                acc.push(b - b'0')?;
1008            } else {
1009                first_discarded_digit.get_or_insert(b - b'0');
1010            }
1011            index += 1;
1012        }
1013    }
1014
1015    match mantissa.get(index) {
1016        None => {}
1017        Some(b'e' | b'E') => return Err(MantissaError::Exponent(index)),
1018        Some(_) => return Err(MantissaError::InvalidFormat),
1019    }
1020
1021    if int_kept == 0 && frac_kept == 0 && first_discarded_digit.is_none() {
1022        return Err(MantissaError::InvalidFormat);
1023    }
1024
1025    let mut value = acc.finish()?;
1026
1027    // Scale the value up to the target scale. Skipped for zero, where computing
1028    // 10^missing could overflow the native type even though the result (zero)
1029    // is always representable.
1030    let missing = scale - frac_kept as i64;
1031    if missing > 0 && !value.is_zero() {
1032        value = value
1033            .mul_checked(decimal_pow::<T>(missing)?)
1034            .map_err(|_| MantissaError::Overflow)?;
1035    }
1036
1037    round &= first_discarded_digit.is_some_and(|digit| digit >= 5);
1038    if round {
1039        value = if negative {
1040            value.sub_checked(T::Native::ONE)
1041        } else {
1042            value.add_checked(T::Native::ONE)
1043        }
1044        .map_err(|_| MantissaError::Overflow)?;
1045    }
1046
1047    let digits = usize::try_from(missing.max(0))
1048        .unwrap_or(usize::MAX)
1049        .saturating_add(int_kept + frac_kept + round as usize);
1050    Ok((value, digits))
1051}
1052
1053/// Parses the digits of an exponent (`[+|-] digits`), saturating at the bounds
1054/// of `i64`; any exponent that large scales every non-zero mantissa out of
1055/// range of every decimal type.
1056fn parse_decimal_exponent(exponent: &[u8]) -> Result<i64, DecimalParseError> {
1057    let (negative, digits) = split_sign(exponent);
1058    if digits.is_empty() {
1059        return Err(DecimalParseError::InvalidFormat);
1060    }
1061    let mut value = 0_i64;
1062    for &b in digits {
1063        if !b.is_ascii_digit() {
1064            return Err(DecimalParseError::InvalidFormat);
1065        }
1066        value = value.saturating_mul(10).saturating_add((b - b'0') as i64);
1067    }
1068    Ok(if negative { -value } else { value })
1069}
1070
1071/// Splits an optional leading sign from `bytes`, returning whether it is `-`
1072/// and the bytes that follow it.
1073#[inline]
1074fn split_sign(bytes: &[u8]) -> (bool, &[u8]) {
1075    match bytes.first() {
1076        Some(b'-') => (true, &bytes[1..]),
1077        Some(b'+') => (false, &bytes[1..]),
1078        _ => (false, bytes),
1079    }
1080}
1081
1082/// Accumulates decimal digits into `chunk`, folding it into `value` whenever
1083/// it reaches [`MAX_CHUNK_DIGITS`] digits
1084struct DecimalAccumulator<T: DecimalType> {
1085    value: T::Native,
1086    chunk: u64,
1087    chunk_len: usize,
1088    negative: bool,
1089}
1090
1091impl<T: DecimalType> DecimalAccumulator<T> {
1092    #[inline(always)]
1093    fn push(&mut self, digit: u8) -> Result<(), DecimalParseError> {
1094        // Cannot overflow: the chunk is folded into `value` before it exceeds
1095        // MAX_CHUNK_DIGITS digits, all of which fit in a u64
1096        self.chunk = self.chunk * 10 + digit as u64;
1097        self.chunk_len += 1;
1098        if self.chunk_len == MAX_CHUNK_DIGITS {
1099            self.value =
1100                fold_decimal_chunk::<T>(self.value, self.chunk, self.chunk_len, self.negative)?;
1101            self.chunk = 0;
1102            self.chunk_len = 0;
1103        }
1104        Ok(())
1105    }
1106
1107    /// Folds the digits still in `chunk` into the value
1108    #[inline]
1109    fn finish(self) -> Result<T::Native, DecimalParseError> {
1110        if self.chunk_len == 0 {
1111            return Ok(self.value);
1112        }
1113        fold_decimal_chunk::<T>(self.value, self.chunk, self.chunk_len, self.negative)
1114    }
1115}
1116
1117/// Folds a chunk of up to [`MAX_CHUNK_DIGITS`] digits into `value`, producing
1118/// `value * 10^chunk_len + chunk` (`chunk` is negated first when parsing a
1119/// negative number).
1120#[inline(always)]
1121fn fold_decimal_chunk<T: DecimalType>(
1122    value: T::Native,
1123    chunk: u64,
1124    chunk_len: usize,
1125    negative: bool,
1126) -> Result<T::Native, DecimalParseError> {
1127    let chunk = decimal_chunk_to_native::<T>(chunk, negative)?;
1128
1129    // When `value` is zero the multiply would be a no-op; skipping it avoids
1130    // computing 10^chunk_len, which can overflow a narrow native type even
1131    // though the result (the chunk itself) is representable.
1132    if value.is_zero() {
1133        return Ok(chunk);
1134    }
1135
1136    value
1137        .mul_checked(decimal_pow::<T>(chunk_len as i64)?)
1138        .map_err(|_| DecimalParseError::Overflow)?
1139        .add_checked(chunk)
1140        .map_err(|_| DecimalParseError::Overflow)
1141}
1142
1143/// Converts a chunk of at most [`MAX_CHUNK_DIGITS`] digits to the native type,
1144/// negated if `negative`.
1145#[inline]
1146fn decimal_chunk_to_native<T: DecimalType>(
1147    chunk: u64,
1148    negative: bool,
1149) -> Result<T::Native, DecimalParseError> {
1150    // Every native type can represent +/- 10^9, so a chunk below that converts
1151    // losslessly through usize on every target. So does any chunk when the
1152    // native type holds MAX_CHUNK_DIGITS digits and usize holds a u64.
1153    const HALF: u64 = 1_000_000_000;
1154    if chunk < HALF || (T::MAX_PRECISION as usize >= MAX_CHUNK_DIGITS && usize::BITS >= 64) {
1155        let chunk = T::Native::usize_as(chunk as usize);
1156        // `ZERO.sub_wrapping` rather than `neg_wrapping`: the latter compiles
1157        // to measurably slower code for i256 (~10% on casting strings to
1158        // Decimal256)
1159        return Ok(if negative {
1160            T::Native::ZERO.sub_wrapping(chunk)
1161        } else {
1162            chunk
1163        });
1164    }
1165    // Otherwise narrow the chunk in two halves that are each below 10^9
1166    let low = T::Native::usize_as((chunk % HALF) as usize);
1167    let high = T::Native::usize_as((chunk / HALF) as usize)
1168        .mul_checked(T::Native::usize_as(HALF as usize))
1169        .map_err(|_| DecimalParseError::Overflow)?;
1170    // Negate before combining so that a chunk with the magnitude of the
1171    // native type's minimum value (e.g. "2147483648" for Decimal32) remains
1172    // representable
1173    if negative {
1174        T::Native::ZERO
1175            .sub_checked(high)
1176            .map_err(|_| DecimalParseError::Overflow)?
1177            .sub_checked(low)
1178            .map_err(|_| DecimalParseError::Overflow)
1179    } else {
1180        high.add_checked(low)
1181            .map_err(|_| DecimalParseError::Overflow)
1182    }
1183}
1184
1185/// Returns `10^exp` as a `T::Native`, or an overflow error if the result does
1186/// not fit in the native type.
1187#[inline]
1188fn decimal_pow<T: DecimalType>(exp: i64) -> Result<T::Native, DecimalParseError> {
1189    // T::MAX_FOR_EACH_PRECISION[k] holds 10^k - 1, so adding one yields 10^k
1190    // without computing a power at runtime. Exponents beyond the table always
1191    // overflow: the native type cannot hold 10^(MAX_PRECISION + 1).
1192    usize::try_from(exp)
1193        .ok()
1194        .and_then(|exp| T::MAX_FOR_EACH_PRECISION.get(exp))
1195        .map(|max| max.add_wrapping(T::Native::ONE))
1196        .ok_or(DecimalParseError::Overflow)
1197}
1198
1199/// Parse human-readable interval string to Arrow [IntervalYearMonthType]
1200pub fn parse_interval_year_month(
1201    value: &str,
1202) -> Result<<IntervalYearMonthType as ArrowPrimitiveType>::Native, ArrowError> {
1203    let config = IntervalParseConfig::new(IntervalUnit::Year);
1204    let interval = Interval::parse(value, &config)?;
1205
1206    let months = interval.to_year_months().map_err(|_| {
1207        ArrowError::CastError(format!(
1208            "Cannot cast {value} to IntervalYearMonth. Only year and month fields are allowed."
1209        ))
1210    })?;
1211
1212    Ok(IntervalYearMonthType::make_value(0, months))
1213}
1214
1215/// Parse human-readable interval string to Arrow [IntervalDayTimeType]
1216pub fn parse_interval_day_time(
1217    value: &str,
1218) -> Result<<IntervalDayTimeType as ArrowPrimitiveType>::Native, ArrowError> {
1219    let config = IntervalParseConfig::new(IntervalUnit::Day);
1220    let interval = Interval::parse(value, &config)?;
1221
1222    let (days, millis) = interval.to_day_time().map_err(|_| ArrowError::CastError(format!(
1223        "Cannot cast {value} to IntervalDayTime because the nanos part isn't multiple of milliseconds"
1224    )))?;
1225
1226    Ok(IntervalDayTimeType::make_value(days, millis))
1227}
1228
1229/// Parse human-readable interval string to Arrow [IntervalMonthDayNanoType]
1230pub fn parse_interval_month_day_nano_config(
1231    value: &str,
1232    config: IntervalParseConfig,
1233) -> Result<<IntervalMonthDayNanoType as ArrowPrimitiveType>::Native, ArrowError> {
1234    let interval = Interval::parse(value, &config)?;
1235
1236    let (months, days, nanos) = interval.to_month_day_nanos();
1237
1238    Ok(IntervalMonthDayNanoType::make_value(months, days, nanos))
1239}
1240
1241/// Parse human-readable interval string to Arrow [IntervalMonthDayNanoType]
1242pub fn parse_interval_month_day_nano(
1243    value: &str,
1244) -> Result<<IntervalMonthDayNanoType as ArrowPrimitiveType>::Native, ArrowError> {
1245    parse_interval_month_day_nano_config(value, IntervalParseConfig::new(IntervalUnit::Month))
1246}
1247
1248const NANOS_PER_MILLIS: i64 = 1_000_000;
1249const NANOS_PER_SECOND: i64 = 1_000 * NANOS_PER_MILLIS;
1250const NANOS_PER_MINUTE: i64 = 60 * NANOS_PER_SECOND;
1251const NANOS_PER_HOUR: i64 = 60 * NANOS_PER_MINUTE;
1252#[cfg(test)]
1253const NANOS_PER_DAY: i64 = 24 * NANOS_PER_HOUR;
1254
1255/// Config to parse interval strings
1256///
1257/// Currently stores the `default_unit` to use if the string doesn't have one specified
1258#[derive(Debug, Clone)]
1259pub struct IntervalParseConfig {
1260    /// The default unit to use if none is specified
1261    /// e.g. `INTERVAL 1` represents `INTERVAL 1 SECOND` when default_unit = [IntervalUnit::Second]
1262    default_unit: IntervalUnit,
1263}
1264
1265impl IntervalParseConfig {
1266    /// Create a new [IntervalParseConfig] with the given default unit
1267    pub fn new(default_unit: IntervalUnit) -> Self {
1268        Self { default_unit }
1269    }
1270}
1271
1272#[rustfmt::skip]
1273#[derive(Debug, Clone, Copy)]
1274#[repr(u16)]
1275/// Represents the units of an interval, with each variant
1276/// corresponding to a bit in the interval's bitfield representation
1277pub enum IntervalUnit {
1278    /// A Century
1279    Century     = 0b_0000_0000_0001,
1280    /// A Decade
1281    Decade      = 0b_0000_0000_0010,
1282    /// A Year
1283    Year        = 0b_0000_0000_0100,
1284    /// A Month
1285    Month       = 0b_0000_0000_1000,
1286    /// A Week
1287    Week        = 0b_0000_0001_0000,
1288    /// A Day
1289    Day         = 0b_0000_0010_0000,
1290    /// An Hour
1291    Hour        = 0b_0000_0100_0000,
1292    /// A Minute
1293    Minute      = 0b_0000_1000_0000,
1294    /// A Second
1295    Second      = 0b_0001_0000_0000,
1296    /// A Millisecond
1297    Millisecond = 0b_0010_0000_0000,
1298    /// A Microsecond
1299    Microsecond = 0b_0100_0000_0000,
1300    /// A Nanosecond
1301    Nanosecond  = 0b_1000_0000_0000,
1302}
1303
1304/// Logic for parsing interval unit strings
1305///
1306/// See <https://github.com/postgres/postgres/blob/2caa85f4aae689e6f6721d7363b4c66a2a6417d6/src/backend/utils/adt/datetime.c#L189>
1307/// for a list of unit names supported by PostgreSQL which we try to match here.
1308impl FromStr for IntervalUnit {
1309    type Err = ArrowError;
1310
1311    fn from_str(s: &str) -> Result<Self, ArrowError> {
1312        match s.to_lowercase().as_str() {
1313            "c" | "cent" | "cents" | "century" | "centuries" => Ok(Self::Century),
1314            "dec" | "decs" | "decade" | "decades" => Ok(Self::Decade),
1315            "y" | "yr" | "yrs" | "year" | "years" => Ok(Self::Year),
1316            "mon" | "mons" | "month" | "months" => Ok(Self::Month),
1317            "w" | "week" | "weeks" => Ok(Self::Week),
1318            "d" | "day" | "days" => Ok(Self::Day),
1319            "h" | "hr" | "hrs" | "hour" | "hours" => Ok(Self::Hour),
1320            "m" | "min" | "mins" | "minute" | "minutes" => Ok(Self::Minute),
1321            "s" | "sec" | "secs" | "second" | "seconds" => Ok(Self::Second),
1322            "ms" | "msec" | "msecs" | "msecond" | "mseconds" | "millisecond" | "milliseconds" => {
1323                Ok(Self::Millisecond)
1324            }
1325            "us" | "usec" | "usecs" | "usecond" | "useconds" | "microsecond" | "microseconds" => {
1326                Ok(Self::Microsecond)
1327            }
1328            "nanosecond" | "nanoseconds" => Ok(Self::Nanosecond),
1329            _ => Err(ArrowError::InvalidArgumentError(format!(
1330                "Unknown interval type: {s}"
1331            ))),
1332        }
1333    }
1334}
1335
1336impl IntervalUnit {
1337    fn from_str_or_config(
1338        s: Option<&str>,
1339        config: &IntervalParseConfig,
1340    ) -> Result<Self, ArrowError> {
1341        match s {
1342            Some(s) => s.parse(),
1343            None => Ok(config.default_unit),
1344        }
1345    }
1346}
1347
1348/// A tuple representing (months, days, nanoseconds) in an interval
1349pub type MonthDayNano = (i32, i32, i64);
1350
1351/// Chosen based on the number of decimal digits in 1 week in nanoseconds
1352const INTERVAL_PRECISION: u32 = 15;
1353
1354#[derive(Clone, Copy, Debug, PartialEq)]
1355struct IntervalAmount {
1356    /// The integer component of the interval amount
1357    integer: i64,
1358    /// The fractional component multiplied by 10^INTERVAL_PRECISION
1359    frac: i64,
1360}
1361
1362#[cfg(test)]
1363impl IntervalAmount {
1364    fn new(integer: i64, frac: i64) -> Self {
1365        Self { integer, frac }
1366    }
1367}
1368
1369impl FromStr for IntervalAmount {
1370    type Err = ArrowError;
1371
1372    fn from_str(s: &str) -> Result<Self, Self::Err> {
1373        match s.split_once('.') {
1374            Some((integer, frac))
1375                if frac.len() <= INTERVAL_PRECISION as usize
1376                    && !frac.is_empty()
1377                    && !frac.starts_with('-') =>
1378            {
1379                // integer will be "" for values like ".5"
1380                // and "-" for values like "-.5"
1381                let explicit_neg = integer.starts_with('-');
1382                let integer = if integer.is_empty() || integer == "-" {
1383                    Ok(0)
1384                } else {
1385                    integer.parse::<i64>().map_err(|_| {
1386                        ArrowError::ParseError(format!("Failed to parse {s} as interval amount"))
1387                    })
1388                }?;
1389
1390                let frac_unscaled = frac.parse::<i64>().map_err(|_| {
1391                    ArrowError::ParseError(format!("Failed to parse {s} as interval amount"))
1392                })?;
1393
1394                // scale fractional part by interval precision
1395                let frac = frac_unscaled * 10_i64.pow(INTERVAL_PRECISION - frac.len() as u32);
1396
1397                // propagate the sign of the integer part to the fractional part
1398                let frac = if integer < 0 || explicit_neg {
1399                    -frac
1400                } else {
1401                    frac
1402                };
1403
1404                let result = Self { integer, frac };
1405
1406                Ok(result)
1407            }
1408            Some((_, frac)) if frac.starts_with('-') => Err(ArrowError::ParseError(format!(
1409                "Failed to parse {s} as interval amount"
1410            ))),
1411            Some((_, frac)) if frac.len() > INTERVAL_PRECISION as usize => {
1412                Err(ArrowError::ParseError(format!(
1413                    "{s} exceeds the precision available for interval amount"
1414                )))
1415            }
1416            Some(_) | None => {
1417                let integer = s.parse::<i64>().map_err(|_| {
1418                    ArrowError::ParseError(format!("Failed to parse {s} as interval amount"))
1419                })?;
1420
1421                let result = Self { integer, frac: 0 };
1422                Ok(result)
1423            }
1424        }
1425    }
1426}
1427
1428#[derive(Debug, Default, PartialEq)]
1429struct Interval {
1430    months: i32,
1431    days: i32,
1432    nanos: i64,
1433}
1434
1435impl Interval {
1436    fn new(months: i32, days: i32, nanos: i64) -> Self {
1437        Self {
1438            months,
1439            days,
1440            nanos,
1441        }
1442    }
1443
1444    fn to_year_months(&self) -> Result<i32, ArrowError> {
1445        match (self.months, self.days, self.nanos) {
1446            (months, days, nanos) if days == 0 && nanos == 0 => Ok(months),
1447            _ => Err(ArrowError::InvalidArgumentError(format!(
1448                "Unable to represent interval with days and nanos as year-months: {self:?}"
1449            ))),
1450        }
1451    }
1452
1453    fn to_day_time(&self) -> Result<(i32, i32), ArrowError> {
1454        let days = self.months.mul_checked(30)?.add_checked(self.days)?;
1455
1456        match self.nanos {
1457            nanos if nanos % NANOS_PER_MILLIS == 0 => {
1458                let millis = (self.nanos / 1_000_000).try_into().map_err(|_| {
1459                    ArrowError::InvalidArgumentError(format!(
1460                        "Unable to represent {} nanos as milliseconds in a signed 32-bit integer",
1461                        self.nanos
1462                    ))
1463                })?;
1464
1465                Ok((days, millis))
1466            }
1467            nanos => Err(ArrowError::InvalidArgumentError(format!(
1468                "Unable to represent {nanos} as milliseconds"
1469            ))),
1470        }
1471    }
1472
1473    fn to_month_day_nanos(&self) -> (i32, i32, i64) {
1474        (self.months, self.days, self.nanos)
1475    }
1476
1477    /// Parse string value in traditional Postgres format such as
1478    /// `1 year 2 months 3 days 4 hours 5 minutes 6 seconds`
1479    fn parse(value: &str, config: &IntervalParseConfig) -> Result<Self, ArrowError> {
1480        let components = parse_interval_components(value, config)?;
1481
1482        components
1483            .into_iter()
1484            .try_fold(Self::default(), |result, (amount, unit)| {
1485                result.add(amount, unit)
1486            })
1487    }
1488
1489    /// Interval addition following Postgres behavior. Fractional units will be spilled into smaller units.
1490    /// When the interval unit is larger than months, the result is rounded to total months and not spilled to days/nanos.
1491    /// Fractional parts of weeks and days are represented using days and nanoseconds.
1492    /// e.g. INTERVAL '0.5 MONTH' = 15 days, INTERVAL '1.5 MONTH' = 1 month 15 days
1493    /// e.g. INTERVAL '0.5 DAY' = 12 hours, INTERVAL '1.5 DAY' = 1 day 12 hours
1494    /// [Postgres reference](https://www.postgresql.org/docs/15/datatype-datetime.html#DATATYPE-INTERVAL-INPUT:~:text=Field%20values%20can,fractional%20on%20output.)
1495    fn add(&self, amount: IntervalAmount, unit: IntervalUnit) -> Result<Self, ArrowError> {
1496        let result = match unit {
1497            IntervalUnit::Century => {
1498                let months_int = amount.integer.mul_checked(100)?.mul_checked(12)?;
1499                let month_frac = amount.frac * 12 / 10_i64.pow(INTERVAL_PRECISION - 2);
1500                let months = months_int
1501                    .add_checked(month_frac)?
1502                    .try_into()
1503                    .map_err(|_| {
1504                        ArrowError::ParseError(format!(
1505                            "Unable to represent {} centuries as months in a signed 32-bit integer",
1506                            amount.integer
1507                        ))
1508                    })?;
1509
1510                Self::new(self.months.add_checked(months)?, self.days, self.nanos)
1511            }
1512            IntervalUnit::Decade => {
1513                let months_int = amount.integer.mul_checked(10)?.mul_checked(12)?;
1514
1515                let month_frac = amount.frac * 12 / 10_i64.pow(INTERVAL_PRECISION - 1);
1516                let months = months_int
1517                    .add_checked(month_frac)?
1518                    .try_into()
1519                    .map_err(|_| {
1520                        ArrowError::ParseError(format!(
1521                            "Unable to represent {} decades as months in a signed 32-bit integer",
1522                            amount.integer
1523                        ))
1524                    })?;
1525
1526                Self::new(self.months.add_checked(months)?, self.days, self.nanos)
1527            }
1528            IntervalUnit::Year => {
1529                let months_int = amount.integer.mul_checked(12)?;
1530                let month_frac = amount.frac * 12 / 10_i64.pow(INTERVAL_PRECISION);
1531                let months = months_int
1532                    .add_checked(month_frac)?
1533                    .try_into()
1534                    .map_err(|_| {
1535                        ArrowError::ParseError(format!(
1536                            "Unable to represent {} years as months in a signed 32-bit integer",
1537                            amount.integer
1538                        ))
1539                    })?;
1540
1541                Self::new(self.months.add_checked(months)?, self.days, self.nanos)
1542            }
1543            IntervalUnit::Month => {
1544                let months = amount.integer.try_into().map_err(|_| {
1545                    ArrowError::ParseError(format!(
1546                        "Unable to represent {} months in a signed 32-bit integer",
1547                        amount.integer
1548                    ))
1549                })?;
1550
1551                let days = amount.frac * 3 / 10_i64.pow(INTERVAL_PRECISION - 1);
1552                let days = days.try_into().map_err(|_| {
1553                    ArrowError::ParseError(format!(
1554                        "Unable to represent {} months as days in a signed 32-bit integer",
1555                        amount.frac / 10_i64.pow(INTERVAL_PRECISION)
1556                    ))
1557                })?;
1558
1559                Self::new(
1560                    self.months.add_checked(months)?,
1561                    self.days.add_checked(days)?,
1562                    self.nanos,
1563                )
1564            }
1565            IntervalUnit::Week => {
1566                let days = amount.integer.mul_checked(7)?.try_into().map_err(|_| {
1567                    ArrowError::ParseError(format!(
1568                        "Unable to represent {} weeks as days in a signed 32-bit integer",
1569                        amount.integer
1570                    ))
1571                })?;
1572
1573                let nanos = amount.frac * 7 * 24 * 6 * 6 / 10_i64.pow(INTERVAL_PRECISION - 11);
1574
1575                Self::new(
1576                    self.months,
1577                    self.days.add_checked(days)?,
1578                    self.nanos.add_checked(nanos)?,
1579                )
1580            }
1581            IntervalUnit::Day => {
1582                let days = amount.integer.try_into().map_err(|_| {
1583                    ArrowError::InvalidArgumentError(format!(
1584                        "Unable to represent {} days in a signed 32-bit integer",
1585                        amount.integer
1586                    ))
1587                })?;
1588
1589                let nanos = amount.frac * 24 * 6 * 6 / 10_i64.pow(INTERVAL_PRECISION - 11);
1590
1591                Self::new(
1592                    self.months,
1593                    self.days.add_checked(days)?,
1594                    self.nanos.add_checked(nanos)?,
1595                )
1596            }
1597            IntervalUnit::Hour => {
1598                let nanos_int = amount.integer.mul_checked(NANOS_PER_HOUR)?;
1599                let nanos_frac = amount.frac * 6 * 6 / 10_i64.pow(INTERVAL_PRECISION - 11);
1600                let nanos = nanos_int.add_checked(nanos_frac)?;
1601
1602                Interval::new(self.months, self.days, self.nanos.add_checked(nanos)?)
1603            }
1604            IntervalUnit::Minute => {
1605                let nanos_int = amount.integer.mul_checked(NANOS_PER_MINUTE)?;
1606                let nanos_frac = amount.frac * 6 / 10_i64.pow(INTERVAL_PRECISION - 10);
1607
1608                let nanos = nanos_int.add_checked(nanos_frac)?;
1609
1610                Interval::new(self.months, self.days, self.nanos.add_checked(nanos)?)
1611            }
1612            IntervalUnit::Second => {
1613                let nanos_int = amount.integer.mul_checked(NANOS_PER_SECOND)?;
1614                let nanos_frac = amount.frac / 10_i64.pow(INTERVAL_PRECISION - 9);
1615                let nanos = nanos_int.add_checked(nanos_frac)?;
1616
1617                Interval::new(self.months, self.days, self.nanos.add_checked(nanos)?)
1618            }
1619            IntervalUnit::Millisecond => {
1620                let nanos_int = amount.integer.mul_checked(NANOS_PER_MILLIS)?;
1621                let nanos_frac = amount.frac / 10_i64.pow(INTERVAL_PRECISION - 6);
1622                let nanos = nanos_int.add_checked(nanos_frac)?;
1623
1624                Interval::new(self.months, self.days, self.nanos.add_checked(nanos)?)
1625            }
1626            IntervalUnit::Microsecond => {
1627                let nanos_int = amount.integer.mul_checked(1_000)?;
1628                let nanos_frac = amount.frac / 10_i64.pow(INTERVAL_PRECISION - 3);
1629                let nanos = nanos_int.add_checked(nanos_frac)?;
1630
1631                Interval::new(self.months, self.days, self.nanos.add_checked(nanos)?)
1632            }
1633            IntervalUnit::Nanosecond => {
1634                let nanos_int = amount.integer;
1635                let nanos_frac = amount.frac / 10_i64.pow(INTERVAL_PRECISION);
1636                let nanos = nanos_int.add_checked(nanos_frac)?;
1637
1638                Interval::new(self.months, self.days, self.nanos.add_checked(nanos)?)
1639            }
1640        };
1641
1642        Ok(result)
1643    }
1644}
1645
1646/// parse the string into a vector of interval components i.e. (amount, unit) tuples
1647fn parse_interval_components(
1648    value: &str,
1649    config: &IntervalParseConfig,
1650) -> Result<Vec<(IntervalAmount, IntervalUnit)>, ArrowError> {
1651    let raw_pairs = split_interval_components(value);
1652
1653    // parse amounts and units
1654    let Ok(pairs): Result<Vec<(IntervalAmount, IntervalUnit)>, ArrowError> = raw_pairs
1655        .iter()
1656        .map(|(a, u)| Ok((a.parse()?, IntervalUnit::from_str_or_config(*u, config)?)))
1657        .collect()
1658    else {
1659        return Err(ArrowError::ParseError(format!(
1660            "Invalid input syntax for type interval: {value:?}"
1661        )));
1662    };
1663
1664    // collect parsed results
1665    let (amounts, units): (Vec<_>, Vec<_>) = pairs.into_iter().unzip();
1666
1667    // duplicate units?
1668    let mut observed_interval_types = 0;
1669    for (unit, (_, raw_unit)) in units.iter().zip(raw_pairs) {
1670        if observed_interval_types & (*unit as u16) != 0 {
1671            return Err(ArrowError::ParseError(format!(
1672                "Invalid input syntax for type interval: {:?}. Repeated type '{}'",
1673                value,
1674                raw_unit.unwrap_or_default(),
1675            )));
1676        }
1677
1678        observed_interval_types |= *unit as u16;
1679    }
1680
1681    let result = amounts.iter().copied().zip(units.iter().copied());
1682
1683    Ok(result.collect::<Vec<_>>())
1684}
1685
1686/// Split an interval into a vec of amounts and units.
1687///
1688/// Pairs are separated by spaces, but within a pair the amount and unit may or may not be separated by a space.
1689///
1690/// This should match the behavior of PostgreSQL's interval parser.
1691fn split_interval_components(value: &str) -> Vec<(&str, Option<&str>)> {
1692    let mut result = vec![];
1693    let mut words = value.split(char::is_whitespace);
1694    while let Some(word) = words.next() {
1695        if let Some(split_word_at) = word.find(not_interval_amount) {
1696            let (amount, unit) = word.split_at(split_word_at);
1697            result.push((amount, Some(unit)));
1698        } else if let Some(unit) = words.next() {
1699            result.push((word, Some(unit)));
1700        } else {
1701            result.push((word, None));
1702            break;
1703        }
1704    }
1705    result
1706}
1707
1708/// test if a character is NOT part of an interval numeric amount
1709fn not_interval_amount(c: char) -> bool {
1710    !c.is_ascii_digit() && c != '.' && c != '-'
1711}
1712
1713#[cfg(test)]
1714mod tests {
1715    use super::*;
1716    use arrow_array::temporal_conversions::date32_to_datetime;
1717    use arrow_buffer::i256;
1718
1719    /// Parses `s` without a precision check, for probing the native range
1720    fn parse_native<T: DecimalType>(s: &str, scale: i8) -> Result<T::Native, DecimalParseError> {
1721        parse_decimal_native::<T>(s, scale).map(|(value, _)| value)
1722    }
1723
1724    #[test]
1725    fn test_parse_nanos() {
1726        assert_eq!(parse_nanos::<3, 0>(&[1, 2, 3]), 123_000_000);
1727        assert_eq!(parse_nanos::<5, 0>(&[1, 2, 3, 4, 5]), 123_450_000);
1728        assert_eq!(parse_nanos::<6, b'0'>(b"123456"), 123_456_000);
1729    }
1730
1731    #[test]
1732    fn string_to_timestamp_timezone() {
1733        // Explicit timezone
1734        assert_eq!(
1735            1599572549190855000,
1736            parse_timestamp("2020-09-08T13:42:29.190855+00:00").unwrap()
1737        );
1738        assert_eq!(
1739            1599572549190855000,
1740            parse_timestamp("2020-09-08T13:42:29.190855Z").unwrap()
1741        );
1742        assert_eq!(
1743            1599572549000000000,
1744            parse_timestamp("2020-09-08T13:42:29Z").unwrap()
1745        ); // no fractional part
1746        assert_eq!(
1747            1599590549190855000,
1748            parse_timestamp("2020-09-08T13:42:29.190855-05:00").unwrap()
1749        );
1750    }
1751
1752    #[test]
1753    fn string_to_timestamp_timezone_space() {
1754        // Ensure space rather than T between time and date is accepted
1755        assert_eq!(
1756            1599572549190855000,
1757            parse_timestamp("2020-09-08 13:42:29.190855+00:00").unwrap()
1758        );
1759        assert_eq!(
1760            1599572549190855000,
1761            parse_timestamp("2020-09-08 13:42:29.190855Z").unwrap()
1762        );
1763        assert_eq!(
1764            1599572549000000000,
1765            parse_timestamp("2020-09-08 13:42:29Z").unwrap()
1766        ); // no fractional part
1767        assert_eq!(
1768            1599590549190855000,
1769            parse_timestamp("2020-09-08 13:42:29.190855-05:00").unwrap()
1770        );
1771    }
1772
1773    #[test]
1774    fn string_to_timestamp_no_timezone() {
1775        // This test is designed to succeed in regardless of the local
1776        // timezone the test machine is running. Thus it is still
1777        // somewhat susceptible to bugs in the use of chrono
1778        let naive_datetime = NaiveDateTime::new(
1779            NaiveDate::from_ymd_opt(2020, 9, 8).unwrap(),
1780            NaiveTime::from_hms_nano_opt(13, 42, 29, 190855000).unwrap(),
1781        );
1782
1783        // Ensure both T and ' ' variants work
1784        assert_eq!(
1785            naive_datetime.and_utc().timestamp_nanos_opt().unwrap(),
1786            parse_timestamp("2020-09-08T13:42:29.190855").unwrap()
1787        );
1788
1789        assert_eq!(
1790            naive_datetime.and_utc().timestamp_nanos_opt().unwrap(),
1791            parse_timestamp("2020-09-08 13:42:29.190855").unwrap()
1792        );
1793
1794        // Also ensure that parsing timestamps with no fractional
1795        // second part works as well
1796        let datetime_whole_secs = NaiveDateTime::new(
1797            NaiveDate::from_ymd_opt(2020, 9, 8).unwrap(),
1798            NaiveTime::from_hms_opt(13, 42, 29).unwrap(),
1799        )
1800        .and_utc();
1801
1802        // Ensure both T and ' ' variants work
1803        assert_eq!(
1804            datetime_whole_secs.timestamp_nanos_opt().unwrap(),
1805            parse_timestamp("2020-09-08T13:42:29").unwrap()
1806        );
1807
1808        assert_eq!(
1809            datetime_whole_secs.timestamp_nanos_opt().unwrap(),
1810            parse_timestamp("2020-09-08 13:42:29").unwrap()
1811        );
1812
1813        // ensure without time work
1814        // no time, should be the nano second at
1815        // 2020-09-08 0:0:0
1816        let datetime_no_time = NaiveDateTime::new(
1817            NaiveDate::from_ymd_opt(2020, 9, 8).unwrap(),
1818            NaiveTime::from_hms_opt(0, 0, 0).unwrap(),
1819        )
1820        .and_utc();
1821
1822        assert_eq!(
1823            datetime_no_time.timestamp_nanos_opt().unwrap(),
1824            parse_timestamp("2020-09-08").unwrap()
1825        )
1826    }
1827
1828    #[test]
1829    fn string_to_timestamp_chrono() {
1830        let cases = [
1831            "2020-09-08T13:42:29Z",
1832            "1969-01-01T00:00:00.1Z",
1833            "2020-09-08T12:00:12.12345678+00:00",
1834            "2020-09-08T12:00:12+00:00",
1835            "2020-09-08T12:00:12.1+00:00",
1836            "2020-09-08T12:00:12.12+00:00",
1837            "2020-09-08T12:00:12.123+00:00",
1838            "2020-09-08T12:00:12.1234+00:00",
1839            "2020-09-08T12:00:12.12345+00:00",
1840            "2020-09-08T12:00:12.123456+00:00",
1841            "2020-09-08T12:00:12.1234567+00:00",
1842            "2020-09-08T12:00:12.12345678+00:00",
1843            "2020-09-08T12:00:12.123456789+00:00",
1844            "2020-09-08T12:00:12.12345678912z",
1845            "2020-09-08T12:00:12.123456789123Z",
1846            "2020-09-08T12:00:12.123456789123+02:00",
1847            "2020-09-08T12:00:12.12345678912345Z",
1848            "2020-09-08T12:00:12.1234567891234567+02:00",
1849            "2020-09-08T12:00:60Z",
1850            "2020-09-08T12:00:60.123Z",
1851            "2020-09-08T12:00:60.123456+02:00",
1852            "2020-09-08T12:00:60.1234567891234567+02:00",
1853            "2020-09-08T12:00:60.999999999+02:00",
1854            "2020-09-08t12:00:12.12345678+00:00",
1855            "2020-09-08t12:00:12+00:00",
1856            "2020-09-08t12:00:12Z",
1857        ];
1858
1859        for case in cases {
1860            let chrono = DateTime::parse_from_rfc3339(case).unwrap();
1861            let chrono_utc = chrono.with_timezone(&Utc);
1862
1863            let custom = string_to_datetime(&Utc, case).unwrap();
1864            assert_eq!(chrono_utc, custom)
1865        }
1866    }
1867
1868    #[test]
1869    fn string_to_timestamp_naive() {
1870        let cases = [
1871            "2018-11-13T17:11:10.011375885995",
1872            "2030-12-04T17:11:10.123",
1873            "2030-12-04T17:11:10.1234",
1874            "2030-12-04T17:11:10.123456",
1875        ];
1876        for case in cases {
1877            let chrono = NaiveDateTime::parse_from_str(case, "%Y-%m-%dT%H:%M:%S%.f").unwrap();
1878            let custom = string_to_datetime(&Utc, case).unwrap();
1879            assert_eq!(chrono, custom.naive_utc())
1880        }
1881    }
1882
1883    #[test]
1884    fn string_to_timestamp_invalid() {
1885        // Test parsing invalid formats
1886        let cases = [
1887            ("", "timestamp must contain at least 10 characters"),
1888            ("SS", "timestamp must contain at least 10 characters"),
1889            ("Wed, 18 Feb 2015 23:16:09 GMT", "error parsing date"),
1890            ("1997-01-31H09:26:56.123Z", "invalid timestamp separator"),
1891            ("1997-01-31  09:26:56.123Z", "error parsing time"),
1892            ("1997:01:31T09:26:56.123Z", "error parsing date"),
1893            ("1997:1:31T09:26:56.123Z", "error parsing date"),
1894            ("1997-01-32T09:26:56.123Z", "error parsing date"),
1895            ("1997-13-32T09:26:56.123Z", "error parsing date"),
1896            ("1997-02-29T09:26:56.123Z", "error parsing date"),
1897            ("2015-02-30T17:35:20-08:00", "error parsing date"),
1898            ("1997-01-10T9:26:56.123Z", "error parsing time"),
1899            ("2015-01-20T25:35:20-08:00", "error parsing time"),
1900            ("1997-01-10T09:61:56.123Z", "error parsing time"),
1901            ("1997-01-10T09:61:90.123Z", "error parsing time"),
1902            ("1997-01-10T12:00:6.123Z", "error parsing time"),
1903            ("1997-01-31T092656.123Z", "error parsing time"),
1904            ("1997-01-10T12:00:06.", "error parsing time"),
1905            ("1997-01-10T12:00:06. ", "error parsing time"),
1906        ];
1907
1908        for (s, ctx) in cases {
1909            let expected = format!("Parser error: Error parsing timestamp from '{s}': {ctx}");
1910            let actual = string_to_datetime(&Utc, s).unwrap_err().to_string();
1911            assert_eq!(actual, expected)
1912        }
1913    }
1914
1915    // Parse a timestamp to timestamp int with a useful human readable error message
1916    fn parse_timestamp(s: &str) -> Result<i64, ArrowError> {
1917        let result = string_to_timestamp_nanos(s);
1918        if let Err(e) = &result {
1919            eprintln!("Error parsing timestamp '{s}': {e:?}");
1920        }
1921        result
1922    }
1923
1924    #[test]
1925    fn string_without_timezone_to_timestamp() {
1926        // string without timezone should always output the same regardless the local or session timezone
1927
1928        let naive_datetime = NaiveDateTime::new(
1929            NaiveDate::from_ymd_opt(2020, 9, 8).unwrap(),
1930            NaiveTime::from_hms_nano_opt(13, 42, 29, 190855000).unwrap(),
1931        );
1932
1933        // Ensure both T and ' ' variants work
1934        assert_eq!(
1935            naive_datetime.and_utc().timestamp_nanos_opt().unwrap(),
1936            parse_timestamp("2020-09-08T13:42:29.190855").unwrap()
1937        );
1938
1939        assert_eq!(
1940            naive_datetime.and_utc().timestamp_nanos_opt().unwrap(),
1941            parse_timestamp("2020-09-08 13:42:29.190855").unwrap()
1942        );
1943
1944        let naive_datetime = NaiveDateTime::new(
1945            NaiveDate::from_ymd_opt(2020, 9, 8).unwrap(),
1946            NaiveTime::from_hms_nano_opt(13, 42, 29, 0).unwrap(),
1947        );
1948
1949        // Ensure both T and ' ' variants work
1950        assert_eq!(
1951            naive_datetime.and_utc().timestamp_nanos_opt().unwrap(),
1952            parse_timestamp("2020-09-08T13:42:29").unwrap()
1953        );
1954
1955        assert_eq!(
1956            naive_datetime.and_utc().timestamp_nanos_opt().unwrap(),
1957            parse_timestamp("2020-09-08 13:42:29").unwrap()
1958        );
1959
1960        let tz: Tz = "+02:00".parse().unwrap();
1961        let date = string_to_datetime(&tz, "2020-09-08 13:42:29").unwrap();
1962        let utc = date.naive_utc().to_string();
1963        assert_eq!(utc, "2020-09-08 11:42:29");
1964        let local = date.naive_local().to_string();
1965        assert_eq!(local, "2020-09-08 13:42:29");
1966
1967        let date = string_to_datetime(&tz, "2020-09-08 13:42:29Z").unwrap();
1968        let utc = date.naive_utc().to_string();
1969        assert_eq!(utc, "2020-09-08 13:42:29");
1970        let local = date.naive_local().to_string();
1971        assert_eq!(local, "2020-09-08 15:42:29");
1972
1973        let dt =
1974            NaiveDateTime::parse_from_str("2020-09-08T13:42:29Z", "%Y-%m-%dT%H:%M:%SZ").unwrap();
1975        let local: Tz = "+08:00".parse().unwrap();
1976
1977        // Parsed as offset from UTC
1978        let date = string_to_datetime(&local, "2020-09-08T13:42:29Z").unwrap();
1979        assert_eq!(dt, date.naive_utc());
1980        assert_ne!(dt, date.naive_local());
1981
1982        // Parsed as offset from local
1983        let date = string_to_datetime(&local, "2020-09-08 13:42:29").unwrap();
1984        assert_eq!(dt, date.naive_local());
1985        assert_ne!(dt, date.naive_utc());
1986    }
1987
1988    #[test]
1989    fn parse_date32() {
1990        let cases = [
1991            "2020-09-08",
1992            "2020-9-8",
1993            "2020-09-8",
1994            "2020-9-08",
1995            "2020-12-1",
1996            "1690-2-5",
1997            "2020-09-08 01:02:03",
1998        ];
1999        for case in cases {
2000            let v = date32_to_datetime(Date32Type::parse(case).unwrap()).unwrap();
2001            let expected = NaiveDate::parse_from_str(case, "%Y-%m-%d")
2002                .or_else(|_| NaiveDate::parse_from_str(case, "%Y-%m-%d %H:%M:%S"))
2003                .unwrap();
2004            assert_eq!(v.date(), expected);
2005        }
2006
2007        let err_cases = [
2008            "",
2009            "80-01-01",
2010            "342",
2011            "Foo",
2012            "2020-09-08-03",
2013            "2020--04-03",
2014            "2020--",
2015            "2020-09-08 01",
2016            "2020-09-08 01:02",
2017            "2020-09-08 01-02-03",
2018            "2020-9-8 01:02:03",
2019            "2020-09-08 1:2:3",
2020        ];
2021        for case in err_cases {
2022            assert_eq!(Date32Type::parse(case), None);
2023        }
2024    }
2025
2026    #[test]
2027    fn parse_date32_extended_year() {
2028        // `Date32` covers any i32 days-from-epoch, verify we can parse it
2029        let cases: &[(&str, i32)] = &[
2030            ("+1970-01-01", 0),
2031            ("+2024-01-01", 19_723),
2032            ("-0001-01-01", -719_893),
2033            ("+29349-01-26", 10_000_000),
2034            ("+2739877-01-03", 1_000_000_000),
2035            // Extremes of the Date32 representable range.
2036            ("+5881580-07-11", i32::MAX),
2037            ("-5877641-06-23", i32::MIN),
2038        ];
2039        for (input, expected) in cases {
2040            assert_eq!(Date32Type::parse(input), Some(*expected), "input: {input}");
2041        }
2042
2043        // One past Date32::MAX / MIN overflows i32 days-from-epoch.
2044        assert_eq!(Date32Type::parse("+5881580-07-12"), None);
2045        assert_eq!(Date32Type::parse("-5877641-06-22"), None);
2046        // Invalid calendar dates still rejected regardless of year magnitude.
2047        assert_eq!(Date32Type::parse("+2739877-02-30"), None);
2048        assert_eq!(Date32Type::parse("+2739877-13-01"), None);
2049        assert_eq!(Date32Type::parse("-2739877-02-30"), None);
2050    }
2051
2052    #[test]
2053    fn parse_time64_nanos() {
2054        assert_eq!(
2055            Time64NanosecondType::parse("02:10:01.1234567899999999"),
2056            Some(7_801_123_456_789)
2057        );
2058        assert_eq!(
2059            Time64NanosecondType::parse("02:10:01.1234567"),
2060            Some(7_801_123_456_700)
2061        );
2062        assert_eq!(
2063            Time64NanosecondType::parse("2:10:01.1234567"),
2064            Some(7_801_123_456_700)
2065        );
2066        assert_eq!(
2067            Time64NanosecondType::parse("12:10:01.123456789 AM"),
2068            Some(601_123_456_789)
2069        );
2070        assert_eq!(
2071            Time64NanosecondType::parse("12:10:01.123456789 am"),
2072            Some(601_123_456_789)
2073        );
2074        assert_eq!(
2075            Time64NanosecondType::parse("2:10:01.12345678 PM"),
2076            Some(51_001_123_456_780)
2077        );
2078        assert_eq!(
2079            Time64NanosecondType::parse("2:10:01.12345678 pm"),
2080            Some(51_001_123_456_780)
2081        );
2082        assert_eq!(
2083            Time64NanosecondType::parse("02:10:01"),
2084            Some(7_801_000_000_000)
2085        );
2086        assert_eq!(
2087            Time64NanosecondType::parse("2:10:01"),
2088            Some(7_801_000_000_000)
2089        );
2090        assert_eq!(
2091            Time64NanosecondType::parse("12:10:01 AM"),
2092            Some(601_000_000_000)
2093        );
2094        assert_eq!(
2095            Time64NanosecondType::parse("12:10:01 am"),
2096            Some(601_000_000_000)
2097        );
2098        assert_eq!(
2099            Time64NanosecondType::parse("2:10:01 PM"),
2100            Some(51_001_000_000_000)
2101        );
2102        assert_eq!(
2103            Time64NanosecondType::parse("2:10:01 pm"),
2104            Some(51_001_000_000_000)
2105        );
2106        assert_eq!(
2107            Time64NanosecondType::parse("02:10"),
2108            Some(7_800_000_000_000)
2109        );
2110        assert_eq!(Time64NanosecondType::parse("2:10"), Some(7_800_000_000_000));
2111        assert_eq!(
2112            Time64NanosecondType::parse("12:10 AM"),
2113            Some(600_000_000_000)
2114        );
2115        assert_eq!(
2116            Time64NanosecondType::parse("12:10 am"),
2117            Some(600_000_000_000)
2118        );
2119        assert_eq!(
2120            Time64NanosecondType::parse("2:10 PM"),
2121            Some(51_000_000_000_000)
2122        );
2123        assert_eq!(
2124            Time64NanosecondType::parse("2:10 pm"),
2125            Some(51_000_000_000_000)
2126        );
2127
2128        // parse directly as nanoseconds
2129        assert_eq!(Time64NanosecondType::parse("1"), Some(1));
2130
2131        // leap second
2132        assert_eq!(
2133            Time64NanosecondType::parse("23:59:60"),
2134            Some(86_400_000_000_000)
2135        );
2136
2137        // custom format
2138        assert_eq!(
2139            Time64NanosecondType::parse_formatted("02 - 10 - 01 - .1234567", "%H - %M - %S - %.f"),
2140            Some(7_801_123_456_700)
2141        );
2142    }
2143
2144    #[test]
2145    fn parse_time64_micros() {
2146        // expected formats
2147        assert_eq!(
2148            Time64MicrosecondType::parse("02:10:01.1234"),
2149            Some(7_801_123_400)
2150        );
2151        assert_eq!(
2152            Time64MicrosecondType::parse("2:10:01.1234"),
2153            Some(7_801_123_400)
2154        );
2155        assert_eq!(
2156            Time64MicrosecondType::parse("12:10:01.123456 AM"),
2157            Some(601_123_456)
2158        );
2159        assert_eq!(
2160            Time64MicrosecondType::parse("12:10:01.123456 am"),
2161            Some(601_123_456)
2162        );
2163        assert_eq!(
2164            Time64MicrosecondType::parse("2:10:01.12345 PM"),
2165            Some(51_001_123_450)
2166        );
2167        assert_eq!(
2168            Time64MicrosecondType::parse("2:10:01.12345 pm"),
2169            Some(51_001_123_450)
2170        );
2171        assert_eq!(
2172            Time64MicrosecondType::parse("02:10:01"),
2173            Some(7_801_000_000)
2174        );
2175        assert_eq!(Time64MicrosecondType::parse("2:10:01"), Some(7_801_000_000));
2176        assert_eq!(
2177            Time64MicrosecondType::parse("12:10:01 AM"),
2178            Some(601_000_000)
2179        );
2180        assert_eq!(
2181            Time64MicrosecondType::parse("12:10:01 am"),
2182            Some(601_000_000)
2183        );
2184        assert_eq!(
2185            Time64MicrosecondType::parse("2:10:01 PM"),
2186            Some(51_001_000_000)
2187        );
2188        assert_eq!(
2189            Time64MicrosecondType::parse("2:10:01 pm"),
2190            Some(51_001_000_000)
2191        );
2192        assert_eq!(Time64MicrosecondType::parse("02:10"), Some(7_800_000_000));
2193        assert_eq!(Time64MicrosecondType::parse("2:10"), Some(7_800_000_000));
2194        assert_eq!(Time64MicrosecondType::parse("12:10 AM"), Some(600_000_000));
2195        assert_eq!(Time64MicrosecondType::parse("12:10 am"), Some(600_000_000));
2196        assert_eq!(
2197            Time64MicrosecondType::parse("2:10 PM"),
2198            Some(51_000_000_000)
2199        );
2200        assert_eq!(
2201            Time64MicrosecondType::parse("2:10 pm"),
2202            Some(51_000_000_000)
2203        );
2204
2205        // parse directly as microseconds
2206        assert_eq!(Time64MicrosecondType::parse("1"), Some(1));
2207
2208        // leap second
2209        assert_eq!(
2210            Time64MicrosecondType::parse("23:59:60"),
2211            Some(86_400_000_000)
2212        );
2213
2214        // custom format
2215        assert_eq!(
2216            Time64MicrosecondType::parse_formatted("02 - 10 - 01 - .1234", "%H - %M - %S - %.f"),
2217            Some(7_801_123_400)
2218        );
2219    }
2220
2221    #[test]
2222    fn parse_time32_millis() {
2223        // expected formats
2224        assert_eq!(Time32MillisecondType::parse("02:10:01.1"), Some(7_801_100));
2225        assert_eq!(Time32MillisecondType::parse("2:10:01.1"), Some(7_801_100));
2226        assert_eq!(
2227            Time32MillisecondType::parse("12:10:01.123 AM"),
2228            Some(601_123)
2229        );
2230        assert_eq!(
2231            Time32MillisecondType::parse("12:10:01.123 am"),
2232            Some(601_123)
2233        );
2234        assert_eq!(
2235            Time32MillisecondType::parse("2:10:01.12 PM"),
2236            Some(51_001_120)
2237        );
2238        assert_eq!(
2239            Time32MillisecondType::parse("2:10:01.12 pm"),
2240            Some(51_001_120)
2241        );
2242        assert_eq!(Time32MillisecondType::parse("02:10:01"), Some(7_801_000));
2243        assert_eq!(Time32MillisecondType::parse("2:10:01"), Some(7_801_000));
2244        assert_eq!(Time32MillisecondType::parse("12:10:01 AM"), Some(601_000));
2245        assert_eq!(Time32MillisecondType::parse("12:10:01 am"), Some(601_000));
2246        assert_eq!(Time32MillisecondType::parse("2:10:01 PM"), Some(51_001_000));
2247        assert_eq!(Time32MillisecondType::parse("2:10:01 pm"), Some(51_001_000));
2248        assert_eq!(Time32MillisecondType::parse("02:10"), Some(7_800_000));
2249        assert_eq!(Time32MillisecondType::parse("2:10"), Some(7_800_000));
2250        assert_eq!(Time32MillisecondType::parse("12:10 AM"), Some(600_000));
2251        assert_eq!(Time32MillisecondType::parse("12:10 am"), Some(600_000));
2252        assert_eq!(Time32MillisecondType::parse("2:10 PM"), Some(51_000_000));
2253        assert_eq!(Time32MillisecondType::parse("2:10 pm"), Some(51_000_000));
2254
2255        // parse directly as milliseconds
2256        assert_eq!(Time32MillisecondType::parse("1"), Some(1));
2257
2258        // leap second
2259        assert_eq!(Time32MillisecondType::parse("23:59:60"), Some(86_400_000));
2260
2261        // custom format
2262        assert_eq!(
2263            Time32MillisecondType::parse_formatted("02 - 10 - 01 - .1", "%H - %M - %S - %.f"),
2264            Some(7_801_100)
2265        );
2266    }
2267
2268    #[test]
2269    fn parse_time32_secs() {
2270        // expected formats
2271        assert_eq!(Time32SecondType::parse("02:10:01.1"), Some(7_801));
2272        assert_eq!(Time32SecondType::parse("02:10:01"), Some(7_801));
2273        assert_eq!(Time32SecondType::parse("2:10:01"), Some(7_801));
2274        assert_eq!(Time32SecondType::parse("12:10:01 AM"), Some(601));
2275        assert_eq!(Time32SecondType::parse("12:10:01 am"), Some(601));
2276        assert_eq!(Time32SecondType::parse("2:10:01 PM"), Some(51_001));
2277        assert_eq!(Time32SecondType::parse("2:10:01 pm"), Some(51_001));
2278        assert_eq!(Time32SecondType::parse("02:10"), Some(7_800));
2279        assert_eq!(Time32SecondType::parse("2:10"), Some(7_800));
2280        assert_eq!(Time32SecondType::parse("12:10 AM"), Some(600));
2281        assert_eq!(Time32SecondType::parse("12:10 am"), Some(600));
2282        assert_eq!(Time32SecondType::parse("2:10 PM"), Some(51_000));
2283        assert_eq!(Time32SecondType::parse("2:10 pm"), Some(51_000));
2284
2285        // parse directly as seconds
2286        assert_eq!(Time32SecondType::parse("1"), Some(1));
2287
2288        // leap second
2289        assert_eq!(Time32SecondType::parse("23:59:60"), Some(86400));
2290
2291        // custom format
2292        assert_eq!(
2293            Time32SecondType::parse_formatted("02 - 10 - 01", "%H - %M - %S"),
2294            Some(7_801)
2295        );
2296    }
2297
2298    #[test]
2299    fn test_string_to_time_invalid() {
2300        let cases = [
2301            "25:00",
2302            "9:00:",
2303            "009:00",
2304            "09:0:00",
2305            "25:00:00",
2306            "13:00 AM",
2307            "13:00 PM",
2308            "12:00. AM",
2309            "09:0:00",
2310            "09:01:0",
2311            "09:01:1",
2312            "9:1:0",
2313            "09:01:0",
2314            "1:00.123",
2315            "1:00:00.123f",
2316            " 9:00:00",
2317            ":09:00",
2318            "T9:00:00",
2319            "AM",
2320        ];
2321        for case in cases {
2322            assert!(string_to_time(case).is_none(), "{case}");
2323        }
2324    }
2325
2326    #[test]
2327    fn test_string_to_time_chrono() {
2328        let cases = [
2329            ("1:00", "%H:%M"),
2330            ("12:00", "%H:%M"),
2331            ("13:00", "%H:%M"),
2332            ("24:00", "%H:%M"),
2333            ("1:00:00", "%H:%M:%S"),
2334            ("12:00:30", "%H:%M:%S"),
2335            ("13:00:59", "%H:%M:%S"),
2336            ("24:00:60", "%H:%M:%S"),
2337            ("09:00:00", "%H:%M:%S%.f"),
2338            ("0:00:30.123456", "%H:%M:%S%.f"),
2339            ("0:00 AM", "%I:%M %P"),
2340            ("1:00 AM", "%I:%M %P"),
2341            ("12:00 AM", "%I:%M %P"),
2342            ("13:00 AM", "%I:%M %P"),
2343            ("0:00 PM", "%I:%M %P"),
2344            ("1:00 PM", "%I:%M %P"),
2345            ("12:00 PM", "%I:%M %P"),
2346            ("13:00 PM", "%I:%M %P"),
2347            ("1:00 pM", "%I:%M %P"),
2348            ("1:00 Pm", "%I:%M %P"),
2349            ("1:00 aM", "%I:%M %P"),
2350            ("1:00 Am", "%I:%M %P"),
2351            ("1:00:30.123456 PM", "%I:%M:%S%.f %P"),
2352            ("1:00:30.123456789 PM", "%I:%M:%S%.f %P"),
2353            ("1:00:30.123456789123 PM", "%I:%M:%S%.f %P"),
2354            ("1:00:30.1234 PM", "%I:%M:%S%.f %P"),
2355            ("1:00:30.123456 PM", "%I:%M:%S%.f %P"),
2356            ("1:00:30.123456789123456789 PM", "%I:%M:%S%.f %P"),
2357            ("1:00:30.12F456 PM", "%I:%M:%S%.f %P"),
2358        ];
2359        for (s, format) in cases {
2360            let chrono = NaiveTime::parse_from_str(s, format).ok();
2361            let custom = string_to_time(s);
2362            assert_eq!(chrono, custom, "{s}");
2363        }
2364    }
2365
2366    #[test]
2367    fn test_parse_interval() {
2368        let config = IntervalParseConfig::new(IntervalUnit::Month);
2369
2370        assert_eq!(
2371            Interval::new(1i32, 0i32, 0i64),
2372            Interval::parse("1 month", &config).unwrap(),
2373        );
2374
2375        assert_eq!(
2376            Interval::new(2i32, 0i32, 0i64),
2377            Interval::parse("2 month", &config).unwrap(),
2378        );
2379
2380        assert_eq!(
2381            Interval::new(-1i32, -18i32, -(NANOS_PER_DAY / 5)),
2382            Interval::parse("-1.5 months -3.2 days", &config).unwrap(),
2383        );
2384
2385        assert_eq!(
2386            Interval::new(0i32, 15i32, 0),
2387            Interval::parse("0.5 months", &config).unwrap(),
2388        );
2389
2390        assert_eq!(
2391            Interval::new(0i32, 15i32, 0),
2392            Interval::parse(".5 months", &config).unwrap(),
2393        );
2394
2395        assert_eq!(
2396            Interval::new(0i32, -15i32, 0),
2397            Interval::parse("-0.5 months", &config).unwrap(),
2398        );
2399
2400        assert_eq!(
2401            Interval::new(0i32, -15i32, 0),
2402            Interval::parse("-.5 months", &config).unwrap(),
2403        );
2404
2405        assert_eq!(
2406            Interval::new(2i32, 10i32, 9 * NANOS_PER_HOUR),
2407            Interval::parse("2.1 months 7.25 days 3 hours", &config).unwrap(),
2408        );
2409
2410        assert_eq!(
2411            Interval::parse("1 centurys 1 month", &config)
2412                .unwrap_err()
2413                .to_string(),
2414            r#"Parser error: Invalid input syntax for type interval: "1 centurys 1 month""#
2415        );
2416
2417        assert_eq!(
2418            Interval::new(37i32, 0i32, 0i64),
2419            Interval::parse("3 year 1 month", &config).unwrap(),
2420        );
2421
2422        assert_eq!(
2423            Interval::new(35i32, 0i32, 0i64),
2424            Interval::parse("3 year -1 month", &config).unwrap(),
2425        );
2426
2427        assert_eq!(
2428            Interval::new(-37i32, 0i32, 0i64),
2429            Interval::parse("-3 year -1 month", &config).unwrap(),
2430        );
2431
2432        assert_eq!(
2433            Interval::new(-35i32, 0i32, 0i64),
2434            Interval::parse("-3 year 1 month", &config).unwrap(),
2435        );
2436
2437        assert_eq!(
2438            Interval::new(0i32, 5i32, 0i64),
2439            Interval::parse("5 days", &config).unwrap(),
2440        );
2441
2442        assert_eq!(
2443            Interval::new(0i32, 7i32, 3 * NANOS_PER_HOUR),
2444            Interval::parse("7 days 3 hours", &config).unwrap(),
2445        );
2446
2447        assert_eq!(
2448            Interval::new(0i32, 7i32, 5 * NANOS_PER_MINUTE),
2449            Interval::parse("7 days 5 minutes", &config).unwrap(),
2450        );
2451
2452        assert_eq!(
2453            Interval::new(0i32, 7i32, -5 * NANOS_PER_MINUTE),
2454            Interval::parse("7 days -5 minutes", &config).unwrap(),
2455        );
2456
2457        assert_eq!(
2458            Interval::new(0i32, -7i32, 5 * NANOS_PER_HOUR),
2459            Interval::parse("-7 days 5 hours", &config).unwrap(),
2460        );
2461
2462        assert_eq!(
2463            Interval::new(
2464                0i32,
2465                -7i32,
2466                -5 * NANOS_PER_HOUR - 5 * NANOS_PER_MINUTE - 5 * NANOS_PER_SECOND
2467            ),
2468            Interval::parse("-7 days -5 hours -5 minutes -5 seconds", &config).unwrap(),
2469        );
2470
2471        assert_eq!(
2472            Interval::new(12i32, 0i32, 25 * NANOS_PER_MILLIS),
2473            Interval::parse("1 year 25 millisecond", &config).unwrap(),
2474        );
2475
2476        assert_eq!(
2477            Interval::new(
2478                12i32,
2479                1i32,
2480                (NANOS_PER_SECOND as f64 * 0.000000001_f64) as i64
2481            ),
2482            Interval::parse("1 year 1 day 0.000000001 seconds", &config).unwrap(),
2483        );
2484
2485        assert_eq!(
2486            Interval::new(12i32, 1i32, NANOS_PER_MILLIS / 10),
2487            Interval::parse("1 year 1 day 0.1 milliseconds", &config).unwrap(),
2488        );
2489
2490        assert_eq!(
2491            Interval::new(12i32, 1i32, 1000i64),
2492            Interval::parse("1 year 1 day 1 microsecond", &config).unwrap(),
2493        );
2494
2495        assert_eq!(
2496            Interval::new(12i32, 1i32, 1i64),
2497            Interval::parse("1 year 1 day 1 nanoseconds", &config).unwrap(),
2498        );
2499
2500        assert_eq!(
2501            Interval::new(1i32, 0i32, -NANOS_PER_SECOND),
2502            Interval::parse("1 month -1 second", &config).unwrap(),
2503        );
2504
2505        assert_eq!(
2506            Interval::new(
2507                -13i32,
2508                -8i32,
2509                -NANOS_PER_HOUR
2510                    - NANOS_PER_MINUTE
2511                    - NANOS_PER_SECOND
2512                    - (1.11_f64 * NANOS_PER_MILLIS as f64) as i64
2513            ),
2514            Interval::parse(
2515                "-1 year -1 month -1 week -1 day -1 hour -1 minute -1 second -1.11 millisecond",
2516                &config
2517            )
2518            .unwrap(),
2519        );
2520
2521        // no units
2522        assert_eq!(
2523            Interval::new(1, 0, 0),
2524            Interval::parse("1", &config).unwrap()
2525        );
2526        assert_eq!(
2527            Interval::new(42, 0, 0),
2528            Interval::parse("42", &config).unwrap()
2529        );
2530        assert_eq!(
2531            Interval::new(0, 0, 42_000_000_000),
2532            Interval::parse("42", &IntervalParseConfig::new(IntervalUnit::Second)).unwrap()
2533        );
2534
2535        // shorter units
2536        assert_eq!(
2537            Interval::new(1, 0, 0),
2538            Interval::parse("1 mon", &config).unwrap()
2539        );
2540        assert_eq!(
2541            Interval::new(1, 0, 0),
2542            Interval::parse("1 mons", &config).unwrap()
2543        );
2544        assert_eq!(
2545            Interval::new(0, 0, 1_000_000),
2546            Interval::parse("1 ms", &config).unwrap()
2547        );
2548        assert_eq!(
2549            Interval::new(0, 0, 1_000),
2550            Interval::parse("1 us", &config).unwrap()
2551        );
2552
2553        // no space
2554        assert_eq!(
2555            Interval::new(0, 0, 1_000),
2556            Interval::parse("1us", &config).unwrap()
2557        );
2558        assert_eq!(
2559            Interval::new(0, 0, NANOS_PER_SECOND),
2560            Interval::parse("1s", &config).unwrap()
2561        );
2562        assert_eq!(
2563            Interval::new(1, 2, 10_864_000_000_000),
2564            Interval::parse("1mon 2days 3hr 1min 4sec", &config).unwrap()
2565        );
2566
2567        assert_eq!(
2568            Interval::new(
2569                -13i32,
2570                -8i32,
2571                -NANOS_PER_HOUR
2572                    - NANOS_PER_MINUTE
2573                    - NANOS_PER_SECOND
2574                    - (1.11_f64 * NANOS_PER_MILLIS as f64) as i64
2575            ),
2576            Interval::parse(
2577                "-1year -1month -1week -1day -1 hour -1 minute -1 second -1.11millisecond",
2578                &config
2579            )
2580            .unwrap(),
2581        );
2582
2583        assert_eq!(
2584            Interval::parse("1h s", &config).unwrap_err().to_string(),
2585            r#"Parser error: Invalid input syntax for type interval: "1h s""#
2586        );
2587
2588        assert_eq!(
2589            Interval::parse("1XX", &config).unwrap_err().to_string(),
2590            r#"Parser error: Invalid input syntax for type interval: "1XX""#
2591        );
2592    }
2593
2594    #[test]
2595    fn test_duplicate_interval_type() {
2596        let config = IntervalParseConfig::new(IntervalUnit::Month);
2597
2598        let err = Interval::parse("1 month 1 second 1 second", &config)
2599            .expect_err("parsing interval should have failed");
2600        assert_eq!(
2601            r#"ParseError("Invalid input syntax for type interval: \"1 month 1 second 1 second\". Repeated type 'second'")"#,
2602            format!("{err:?}")
2603        );
2604
2605        // test with singular and plural forms
2606        let err = Interval::parse("1 century 2 centuries", &config)
2607            .expect_err("parsing interval should have failed");
2608        assert_eq!(
2609            r#"ParseError("Invalid input syntax for type interval: \"1 century 2 centuries\". Repeated type 'centuries'")"#,
2610            format!("{err:?}")
2611        );
2612    }
2613
2614    #[test]
2615    fn test_interval_amount_parsing() {
2616        // integer
2617        let result = IntervalAmount::from_str("123").unwrap();
2618        let expected = IntervalAmount::new(123, 0);
2619
2620        assert_eq!(result, expected);
2621
2622        // positive w/ fractional
2623        let result = IntervalAmount::from_str("0.3").unwrap();
2624        let expected = IntervalAmount::new(0, 3 * 10_i64.pow(INTERVAL_PRECISION - 1));
2625
2626        assert_eq!(result, expected);
2627
2628        // negative w/ fractional
2629        let result = IntervalAmount::from_str("-3.5").unwrap();
2630        let expected = IntervalAmount::new(-3, -5 * 10_i64.pow(INTERVAL_PRECISION - 1));
2631
2632        assert_eq!(result, expected);
2633
2634        // invalid: missing fractional
2635        let result = IntervalAmount::from_str("3.");
2636        assert!(result.is_err());
2637
2638        // invalid: sign in fractional
2639        let result = IntervalAmount::from_str("3.-5");
2640        assert!(result.is_err());
2641    }
2642
2643    #[test]
2644    fn test_interval_precision() {
2645        let config = IntervalParseConfig::new(IntervalUnit::Month);
2646
2647        let result = Interval::parse("100000.1 days", &config).unwrap();
2648        let expected = Interval::new(0_i32, 100_000_i32, NANOS_PER_DAY / 10);
2649
2650        assert_eq!(result, expected);
2651    }
2652
2653    #[test]
2654    fn test_interval_addition() {
2655        // add 4.1 centuries
2656        let start = Interval::new(1, 2, 3);
2657        let expected = Interval::new(4921, 2, 3);
2658
2659        let result = start
2660            .add(
2661                IntervalAmount::new(4, 10_i64.pow(INTERVAL_PRECISION - 1)),
2662                IntervalUnit::Century,
2663            )
2664            .unwrap();
2665
2666        assert_eq!(result, expected);
2667
2668        // add 10.25 decades
2669        let start = Interval::new(1, 2, 3);
2670        let expected = Interval::new(1231, 2, 3);
2671
2672        let result = start
2673            .add(
2674                IntervalAmount::new(10, 25 * 10_i64.pow(INTERVAL_PRECISION - 2)),
2675                IntervalUnit::Decade,
2676            )
2677            .unwrap();
2678
2679        assert_eq!(result, expected);
2680
2681        // add 30.3 years (reminder: Postgres logic does not spill to days/nanos when interval is larger than a month)
2682        let start = Interval::new(1, 2, 3);
2683        let expected = Interval::new(364, 2, 3);
2684
2685        let result = start
2686            .add(
2687                IntervalAmount::new(30, 3 * 10_i64.pow(INTERVAL_PRECISION - 1)),
2688                IntervalUnit::Year,
2689            )
2690            .unwrap();
2691
2692        assert_eq!(result, expected);
2693
2694        // add 1.5 months
2695        let start = Interval::new(1, 2, 3);
2696        let expected = Interval::new(2, 17, 3);
2697
2698        let result = start
2699            .add(
2700                IntervalAmount::new(1, 5 * 10_i64.pow(INTERVAL_PRECISION - 1)),
2701                IntervalUnit::Month,
2702            )
2703            .unwrap();
2704
2705        assert_eq!(result, expected);
2706
2707        // add -2 weeks
2708        let start = Interval::new(1, 25, 3);
2709        let expected = Interval::new(1, 11, 3);
2710
2711        let result = start
2712            .add(IntervalAmount::new(-2, 0), IntervalUnit::Week)
2713            .unwrap();
2714
2715        assert_eq!(result, expected);
2716
2717        // add 2.2 days
2718        let start = Interval::new(12, 15, 3);
2719        let expected = Interval::new(12, 17, 3 + 17_280 * NANOS_PER_SECOND);
2720
2721        let result = start
2722            .add(
2723                IntervalAmount::new(2, 2 * 10_i64.pow(INTERVAL_PRECISION - 1)),
2724                IntervalUnit::Day,
2725            )
2726            .unwrap();
2727
2728        assert_eq!(result, expected);
2729
2730        // add 12.5 hours
2731        let start = Interval::new(1, 2, 3);
2732        let expected = Interval::new(1, 2, 3 + 45_000 * NANOS_PER_SECOND);
2733
2734        let result = start
2735            .add(
2736                IntervalAmount::new(12, 5 * 10_i64.pow(INTERVAL_PRECISION - 1)),
2737                IntervalUnit::Hour,
2738            )
2739            .unwrap();
2740
2741        assert_eq!(result, expected);
2742
2743        // add -1.5 minutes
2744        let start = Interval::new(0, 0, -3);
2745        let expected = Interval::new(0, 0, -90_000_000_000 - 3);
2746
2747        let result = start
2748            .add(
2749                IntervalAmount::new(-1, -5 * 10_i64.pow(INTERVAL_PRECISION - 1)),
2750                IntervalUnit::Minute,
2751            )
2752            .unwrap();
2753
2754        assert_eq!(result, expected);
2755    }
2756
2757    #[test]
2758    fn string_to_timestamp_old() {
2759        parse_timestamp("1677-06-14T07:29:01.256")
2760            .map_err(|e| assert!(e.to_string().ends_with(ERR_NANOSECONDS_NOT_SUPPORTED)))
2761            .unwrap_err();
2762    }
2763
2764    #[test]
2765    fn test_parse_decimal_with_parameter() {
2766        let tests = [
2767            ("0", 0i128),
2768            ("123.123", 123123i128),
2769            ("123.1234", 123123i128),
2770            ("123.1", 123100i128),
2771            ("123", 123000i128),
2772            ("-123.123", -123123i128),
2773            ("-123.1234", -123123i128),
2774            ("-123.1", -123100i128),
2775            ("-123", -123000i128),
2776            ("0.0000123", 0i128),
2777            ("12.", 12000i128),
2778            ("-12.", -12000i128),
2779            ("00.1", 100i128),
2780            ("-00.1", -100i128),
2781            ("12345678912345678.1234", 12345678912345678123i128),
2782            ("-12345678912345678.1234", -12345678912345678123i128),
2783            ("99999999999999999.999", 99999999999999999999i128),
2784            ("-99999999999999999.999", -99999999999999999999i128),
2785            (".123", 123i128),
2786            ("-.123", -123i128),
2787            ("123.", 123000i128),
2788            ("-123.", -123000i128),
2789        ];
2790        for (s, i) in tests {
2791            let result_128 = parse_decimal::<Decimal128Type>(s, 20, 3);
2792            assert_eq!(i, result_128.unwrap());
2793            let result_256 = parse_decimal::<Decimal256Type>(s, 20, 3);
2794            assert_eq!(i256::from_i128(i), result_256.unwrap());
2795        }
2796
2797        let e_notation_tests = [
2798            ("1.23e3", "1230.0", 2),
2799            ("5.6714e+2", "567.14", 4),
2800            ("5.6714e-2", "0.056714", 4),
2801            ("5.6714e-2", "0.056714", 3),
2802            ("5.6741214125e2", "567.41214125", 4),
2803            ("8.91E4", "89100.0", 2),
2804            ("3.14E+5", "314000.0", 2),
2805            ("2.718e0", "2.718", 2),
2806            ("9.999999e-1", "0.9999999", 4),
2807            ("1.23e+3", "1230", 2),
2808            ("1.234559e+3", "1234.559", 2),
2809            ("1.00E-10", "0.0000000001", 11),
2810            ("1.23e-4", "0.000123", 2),
2811            ("9.876e7", "98760000.0", 2),
2812            ("5.432E+8", "543200000.0", 10),
2813            ("1.234567e9", "1234567000.0", 2),
2814            ("1.234567e2", "123.45670000", 2),
2815            ("4749.3e-5", "0.047493", 10),
2816            ("4749.3e+5", "474930000", 10),
2817            ("4749.3e-5", "0.047493", 1),
2818            ("4749.3e+5", "474930000", 1),
2819            ("0E-8", "0", 10),
2820            ("0E+6", "0", 10),
2821            ("0e0", "0", 10),
2822            ("-0e0", "0", 10),
2823            ("00e48", "0", 10),
2824            ("1E-8", "0.00000001", 10),
2825            ("12E+6", "12000000", 10),
2826            ("12E-6", "0.000012", 10),
2827            ("0.1e-6", "0.0000001", 10),
2828            ("0.1e+6", "100000", 10),
2829            ("0.12e-6", "0.00000012", 10),
2830            ("0.12e+6", "120000", 10),
2831            ("000000000001e0", "000000000001", 3),
2832            ("000001.1034567002e0", "000001.1034567002", 3),
2833            ("1.234e16", "12340000000000000", 0),
2834            ("123.4e16", "1234000000000000000", 0),
2835            ("15e-1", "1.5", 0),
2836            ("1.25e1", "12.5", 0),
2837            ("1.5e-1", "0.15", 1),
2838        ];
2839        for (e, d, scale) in e_notation_tests {
2840            let result_128_e = parse_decimal::<Decimal128Type>(e, 20, scale);
2841            let result_128_d = parse_decimal::<Decimal128Type>(d, 20, scale);
2842            assert_eq!(result_128_e.unwrap(), result_128_d.unwrap(), "{e} vs {d}");
2843            let result_256_e = parse_decimal::<Decimal256Type>(e, 20, scale);
2844            let result_256_d = parse_decimal::<Decimal256Type>(d, 20, scale);
2845            assert_eq!(result_256_e.unwrap(), result_256_d.unwrap(), "{e} vs {d}");
2846        }
2847        let can_not_parse_tests = [
2848            "123,123",
2849            ".",
2850            "123.123.123",
2851            "",
2852            "+",
2853            "-",
2854            "e",
2855            "e5",
2856            "-.",
2857            "+e-11",
2858            "-.E+3",
2859            ".e5",
2860            "1.3e+e3",
2861            "5.6714ee-2",
2862            "4.11ee-+4",
2863            "4.11e++4",
2864            "1.1e.12",
2865            "1.23e+3.",
2866            "1.23e+3.1",
2867            "1e",
2868            "1e+",
2869            "1e-",
2870            "1e5e5",
2871            "1 000",
2872            "1_000",
2873            "- 1",
2874            "1.5 x",
2875            "0x10",
2876            "NaN",
2877            "inf",
2878            "\u{661}\u{662}",
2879            "\u{ff11}",
2880        ];
2881        for s in can_not_parse_tests {
2882            let result_128 = parse_decimal::<Decimal128Type>(s, 20, 3);
2883            assert_eq!(
2884                format!("Parser error: Invalid decimal format: {s:?}"),
2885                result_128.unwrap_err().to_string()
2886            );
2887            let result_256 = parse_decimal::<Decimal256Type>(s, 20, 3);
2888            assert_eq!(
2889                format!("Parser error: Invalid decimal format: {s:?}"),
2890                result_256.unwrap_err().to_string()
2891            );
2892        }
2893        let overflow_parse_tests = [
2894            ("12345678", 3),
2895            ("1.2345678e7", 3),
2896            ("12345678.9", 3),
2897            ("1.23456789e+7", 3),
2898            ("99999999.99", 3),
2899            ("9.999999999e7", 3),
2900            ("12345678908765.123456", 3),
2901            ("123456789087651234.56e-4", 3),
2902            ("1234560000000", 0),
2903            ("12345678900.0", 0),
2904            ("1.23456e12", 0),
2905            ("9999999.9995", 3),
2906            ("1e99999", 0),
2907            ("1e40", 0),
2908        ];
2909        for (s, scale) in overflow_parse_tests {
2910            let result_128 = parse_decimal::<Decimal128Type>(s, 10, scale);
2911            let expected_128 =
2912                format!("Parser error: {s:?} does not fit in Decimal128(10, {scale})");
2913            assert_eq!(result_128.unwrap_err().to_string(), expected_128);
2914
2915            let result_256 = parse_decimal::<Decimal256Type>(s, 10, scale);
2916            let expected_256 =
2917                format!("Parser error: {s:?} does not fit in Decimal256(10, {scale})");
2918            assert_eq!(result_256.unwrap_err().to_string(), expected_256);
2919        }
2920
2921        let edge_tests_128 = [
2922            (
2923                "99999999999999999999999999999999999999",
2924                99999999999999999999999999999999999999i128,
2925                0,
2926            ),
2927            (
2928                "999999999999999999999999999999999999.99",
2929                99999999999999999999999999999999999999i128,
2930                2,
2931            ),
2932            (
2933                "9999999999999999999999999.9999999999999",
2934                99999999999999999999999999999999999999i128,
2935                13,
2936            ),
2937            (
2938                "9999999999999999999999999",
2939                99999999999999999999999990000000000000i128,
2940                13,
2941            ),
2942            (
2943                "0.99999999999999999999999999999999999999",
2944                99999999999999999999999999999999999999i128,
2945                38,
2946            ),
2947            (
2948                "0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001016744",
2949                0i128,
2950                15,
2951            ),
2952            ("1.016744e-320", 0i128, 15),
2953            ("-1e3", -1000000000i128, 6),
2954            ("+1e3", 1000000000i128, 6),
2955            ("-1e31", -10000000000000000000000000000000000000i128, 6),
2956            // More digits than an i128 can hold, but a small value
2957            ("10000000000000000000000000000000000000000e-39", 10i128, 0),
2958            // Digits beyond the scale round; here the result still fits
2959            (
2960                "99999999999999999999999999999999999994e-1",
2961                9999999999999999999999999999999999999i128,
2962                0,
2963            ),
2964        ];
2965        for (s, i, scale) in edge_tests_128 {
2966            let result_128 = parse_decimal::<Decimal128Type>(s, 38, scale);
2967            assert_eq!(i, result_128.unwrap(), "{s}");
2968        }
2969        // Rounding carries into a 39th digit, which does not fit
2970        assert!(
2971            parse_decimal::<Decimal128Type>("999999999999999999999999999999999999999e-1", 38, 0)
2972                .is_err()
2973        );
2974
2975        let edge_tests_256 = [
2976            (
2977                "9999999999999999999999999999999999999999999999999999999999999999999999999999",
2978                i256::from_string(
2979                    "9999999999999999999999999999999999999999999999999999999999999999999999999999",
2980                )
2981                .unwrap(),
2982                0,
2983            ),
2984            (
2985                "999999999999999999999999999999999999999999999999999999999999999999999999.9999",
2986                i256::from_string(
2987                    "9999999999999999999999999999999999999999999999999999999999999999999999999999",
2988                )
2989                .unwrap(),
2990                4,
2991            ),
2992            (
2993                "99999999999999999999999999999999999999999999999999.99999999999999999999999999",
2994                i256::from_string(
2995                    "9999999999999999999999999999999999999999999999999999999999999999999999999999",
2996                )
2997                .unwrap(),
2998                26,
2999            ),
3000            (
3001                "9.999999999999999999999999999999999999999999999999999999999999999999999999999e49",
3002                i256::from_string(
3003                    "9999999999999999999999999999999999999999999999999999999999999999999999999999",
3004                )
3005                .unwrap(),
3006                26,
3007            ),
3008            (
3009                "99999999999999999999999999999999999999999999999999",
3010                i256::from_string(
3011                    "9999999999999999999999999999999999999999999999999900000000000000000000000000",
3012                )
3013                .unwrap(),
3014                26,
3015            ),
3016            (
3017                "9.9999999999999999999999999999999999999999999999999e+49",
3018                i256::from_string(
3019                    "9999999999999999999999999999999999999999999999999900000000000000000000000000",
3020                )
3021                .unwrap(),
3022                26,
3023            ),
3024        ];
3025        for (s, i, scale) in edge_tests_256 {
3026            let result = parse_decimal::<Decimal256Type>(s, 76, scale);
3027            assert_eq!(i, result.unwrap());
3028        }
3029
3030        let zero_scale_tests = [
3031            (".123", 0, 3),
3032            ("0.123", 0, 3),
3033            ("1.0", 1, 3),
3034            ("1.2", 1, 3),
3035            ("1.00", 1, 3),
3036            ("1.23", 1, 3),
3037            ("1.000", 1, 3),
3038            ("1.123", 1, 3),
3039            ("1.5", 2, 3),
3040            ("1.9", 2, 3),
3041            ("123.0", 123, 3),
3042            ("123.4", 123, 3),
3043            ("123.00", 123, 3),
3044            ("123.45", 123, 3),
3045            ("123.5", 124, 3),
3046            ("123.000000000000000000004", 123, 3),
3047            ("0.123e2", 12, 3),
3048            ("0.123e4", 1230, 10),
3049            ("1.23e4", 12300, 10),
3050            ("12.3e4", 123000, 10),
3051            ("123e4", 1230000, 10),
3052            (
3053                "20000000000000000000000000000000000002.0",
3054                20000000000000000000000000000000000002,
3055                38,
3056            ),
3057        ];
3058        for (s, i, precision) in zero_scale_tests {
3059            let result_128 = parse_decimal::<Decimal128Type>(s, precision, 0).unwrap();
3060            assert_eq!(i, result_128, "{s}");
3061        }
3062
3063        let can_not_parse_zero_scale = [".", "blag", "", "+", "-", "e"];
3064        for s in can_not_parse_zero_scale {
3065            let result_128 = parse_decimal::<Decimal128Type>(s, 5, 0);
3066            assert_eq!(
3067                format!("Parser error: Invalid decimal format: {s:?}"),
3068                result_128.unwrap_err().to_string(),
3069            );
3070        }
3071    }
3072
3073    #[test]
3074    fn test_parse_decimal_rounds_half_away_from_zero() {
3075        let tests = [
3076            ("1.234", 2, 123),
3077            ("1.235", 2, 124),
3078            ("1.2350000", 2, 124),
3079            ("1.2349999", 2, 123),
3080            ("-1.234", 2, -123),
3081            ("-1.235", 2, -124),
3082            ("-0.004", 2, 0),
3083            ("-0.005", 2, -1),
3084            (".5", 0, 1),
3085            ("-.5", 0, -1),
3086            ("0.5", 0, 1),
3087            ("1.5", 0, 2),
3088            ("2.5", 0, 3),
3089            ("-2.5", 0, -3),
3090            ("1.99", 1, 20),
3091            ("0.995", 2, 100),
3092            ("9.99", 1, 100),
3093            ("123.4567891", 5, 12345679),
3094            ("123.45", 0, 123),
3095            ("0.0000123", 3, 0),
3096            ("12.", 2, 1200),
3097            (".12", 2, 12),
3098            ("+.12", 2, 12),
3099            ("-.12", 2, -12),
3100        ];
3101        for (s, scale, expected) in tests {
3102            assert_eq!(
3103                parse_decimal::<Decimal128Type>(s, 38, scale).unwrap(),
3104                expected,
3105                "{s} at scale {scale}"
3106            );
3107            assert_eq!(
3108                parse_decimal::<Decimal256Type>(s, 76, scale).unwrap(),
3109                i256::from_i128(expected),
3110                "{s} at scale {scale}"
3111            );
3112        }
3113    }
3114
3115    #[test]
3116    fn test_parse_decimal_rounding_overflow() {
3117        // Rounding up can push the value past the precision ...
3118        assert!(parse_decimal::<Decimal128Type>("99999.5", 5, 0).is_err());
3119        assert!(parse_decimal::<Decimal128Type>("9.995", 3, 2).is_err());
3120        assert_eq!(parse_decimal::<Decimal128Type>("9.994", 3, 2).unwrap(), 999);
3121        assert_eq!(parse_decimal::<Decimal128Type>("0.995", 3, 2).unwrap(), 100);
3122
3123        // ... or past the native type itself
3124        assert_eq!(
3125            parse_native::<Decimal32Type>("2147483647.5", 0),
3126            Err(DecimalParseError::Overflow)
3127        );
3128        assert_eq!(
3129            parse_native::<Decimal32Type>("-2147483648.5", 0),
3130            Err(DecimalParseError::Overflow)
3131        );
3132        assert_eq!(
3133            parse_native::<Decimal128Type>(&format!("{}.5", i128::MAX), 0),
3134            Err(DecimalParseError::Overflow)
3135        );
3136        assert_eq!(
3137            parse_native::<Decimal128Type>(&format!("{}.5", i128::MIN), 0),
3138            Err(DecimalParseError::Overflow)
3139        );
3140        assert_eq!(
3141            parse_native::<Decimal256Type>(&format!("{}.5", i256::MAX), 0),
3142            Err(DecimalParseError::Overflow)
3143        );
3144        assert_eq!(
3145            parse_native::<Decimal256Type>(&format!("{}.5", i256::MIN), 0),
3146            Err(DecimalParseError::Overflow)
3147        );
3148    }
3149
3150    #[test]
3151    fn test_parse_decimal_precision_by_digit_count() {
3152        // Rounding up can add a digit
3153        assert_eq!(
3154            parse_decimal::<Decimal128Type>("99999.4", 5, 0).unwrap(),
3155            99999
3156        );
3157        assert!(parse_decimal::<Decimal128Type>("99999.5", 5, 0).is_err());
3158        assert!(parse_decimal::<Decimal128Type>("-99999.5", 5, 0).is_err());
3159        assert_eq!(
3160            parse_decimal::<Decimal128Type>("99999.5", 6, 0).unwrap(),
3161            100000
3162        );
3163        // Leading zeros count as digits only for the shortcut; the value is
3164        // then checked by its range
3165        assert_eq!(
3166            parse_decimal::<Decimal128Type>("000000000000000000000001", 1, 0).unwrap(),
3167            1
3168        );
3169        assert_eq!(
3170            parse_decimal::<Decimal128Type>("0.000000000000000000001", 1, 21).unwrap(),
3171            1
3172        );
3173        assert!(parse_decimal::<Decimal128Type>("0.0000000000000000000012", 1, 22).is_err());
3174        // The zeros appended to reach the scale count as digits
3175        assert_eq!(parse_decimal::<Decimal128Type>("1", 3, 2).unwrap(), 100);
3176        assert!(parse_decimal::<Decimal128Type>("1", 2, 2).is_err());
3177        assert!(parse_decimal::<Decimal128Type>("1e2", 2, 0).is_err());
3178        assert_eq!(parse_decimal::<Decimal32Type>("1e2", 3, 0).unwrap(), 100);
3179        // Scaling down leaves fewer digits
3180        assert_eq!(
3181            parse_decimal::<Decimal128Type>("123456", 2, -4).unwrap(),
3182            12
3183        );
3184        assert!(parse_decimal::<Decimal128Type>("123456", 1, -4).is_err());
3185        // A precision beyond the type's maximum is invalid
3186        assert!(parse_decimal::<Decimal32Type>("1", 10, 0).is_err());
3187        assert!(parse_decimal::<Decimal32Type>("00000000001", 10, 0).is_err());
3188        assert!(parse_decimal::<Decimal128Type>("1", 39, 0).is_err());
3189        assert!(parse_decimal::<Decimal256Type>("1", 77, 0).is_err());
3190    }
3191
3192    #[test]
3193    fn test_parse_decimal_native_full_range() {
3194        // The native range exceeds the largest precision; the precision check
3195        // is the caller's responsibility
3196        assert_eq!(
3197            parse_native::<Decimal32Type>("-2147483648", 0),
3198            Ok(i32::MIN)
3199        );
3200        assert_eq!(
3201            parse_native::<Decimal32Type>("2147483648", 0),
3202            Err(DecimalParseError::Overflow)
3203        );
3204        assert_eq!(
3205            parse_native::<Decimal64Type>("-9223372036854775808", 0),
3206            Ok(i64::MIN)
3207        );
3208        assert_eq!(
3209            parse_native::<Decimal64Type>("9223372036854775808", 0),
3210            Err(DecimalParseError::Overflow)
3211        );
3212        assert_eq!(
3213            parse_native::<Decimal128Type>(&i128::MAX.to_string(), 0),
3214            Ok(i128::MAX)
3215        );
3216        assert_eq!(
3217            parse_native::<Decimal128Type>(&i128::MIN.to_string(), 0),
3218            Ok(i128::MIN)
3219        );
3220        assert_eq!(
3221            parse_native::<Decimal256Type>(&i256::MAX.to_string(), 0),
3222            Ok(i256::MAX)
3223        );
3224        assert_eq!(
3225            parse_native::<Decimal256Type>(&i256::MIN.to_string(), 0),
3226            Ok(i256::MIN)
3227        );
3228        // The unscaled value (integer digits scaled by 10^21) far exceeds the
3229        // i256 range, so this must report overflow rather than wrapping to an
3230        // arbitrary (possibly in-range) value
3231        let input = format!("{}.12345678901234567890123", "7".repeat(71));
3232        assert_eq!(
3233            parse_native::<Decimal256Type>(&input, 21),
3234            Err(DecimalParseError::Overflow)
3235        );
3236
3237        assert!(parse_decimal::<Decimal128Type>(&i128::MAX.to_string(), 38, 0).is_err());
3238        assert!(parse_decimal::<Decimal32Type>("-2147483648", 9, 0).is_err());
3239    }
3240
3241    #[test]
3242    fn test_parse_decimal_integer_widths() {
3243        assert_eq!(
3244            parse_decimal::<Decimal32Type>("123.45", 9, 2).unwrap(),
3245            12_345_i32
3246        );
3247        assert_eq!(
3248            parse_decimal::<Decimal32Type>("-9999999.994", 9, 2).unwrap(),
3249            -999_999_999_i32
3250        );
3251        assert!(parse_decimal::<Decimal32Type>("9999999.995", 9, 2).is_err());
3252        assert!(parse_decimal::<Decimal32Type>("-9999999.995", 9, 2).is_err());
3253        assert_eq!(
3254            parse_decimal::<Decimal64Type>("123.45", 18, 2).unwrap(),
3255            12_345_i64
3256        );
3257        assert_eq!(
3258            parse_decimal::<Decimal64Type>("9999999999999999.99", 18, 2).unwrap(),
3259            999_999_999_999_999_999_i64
3260        );
3261        assert!(parse_decimal::<Decimal64Type>("10000000000000000.00", 18, 2).is_err());
3262        // Fractional parts longer than any native integer type parse fine;
3263        // digits beyond the scale only matter for rounding
3264        assert_eq!(
3265            parse_decimal::<Decimal64Type>(&format!(".{}", "5".repeat(100)), 18, 4).unwrap(),
3266            5_556_i64
3267        );
3268        assert_eq!(
3269            parse_decimal::<Decimal128Type>(&format!(".{}", "1".repeat(100)), 38, 4).unwrap(),
3270            1_111_i128
3271        );
3272    }
3273
3274    #[test]
3275    fn test_parse_decimal_exponent() {
3276        let tests = [
3277            ("1e2", 0, 100),
3278            ("1E2", 0, 100),
3279            ("1e+2", 0, 100),
3280            ("1e+02", 0, 100),
3281            ("1.5e2", 0, 150),
3282            ("1.5e2", 2, 15000),
3283            ("1.5e-1", 1, 2),
3284            ("15e-1", 0, 2),
3285            ("1e-2", 1, 0),
3286            ("1e-3", 2, 0),
3287            ("0e0", 2, 0),
3288            ("-0e0", 2, 0),
3289            ("0E5", 2, 0),
3290            ("0e99999", 2, 0),
3291            ("00e48", 8, 0),
3292            ("+00.0E+41", 12, 0),
3293            ("1.25e1", 0, 13),
3294            ("1e-99999", 2, 0),
3295            ("1.5e-400", 2, 0),
3296            ("123456789e-9", 9, 123456789),
3297            ("0.000000001e9", 0, 1),
3298            ("5e-1", 0, 1),
3299            ("4e-1", 0, 0),
3300            ("-5e-1", 0, -1),
3301        ];
3302        for (s, scale, expected) in tests {
3303            assert_eq!(
3304                parse_decimal::<Decimal128Type>(s, 38, scale).unwrap(),
3305                expected,
3306                "{s} at scale {scale}"
3307            );
3308            assert_eq!(
3309                parse_decimal::<Decimal32Type>(s, 9, scale).unwrap(),
3310                expected as i32,
3311                "{s} at scale {scale}"
3312            );
3313        }
3314
3315        // Exponents shift digits across the decimal point without losing any
3316        assert_eq!(
3317            parse_decimal::<Decimal32Type>("4825037936439135476.2609835314269495255615E-14", 9, 4)
3318                .unwrap(),
3319            482503794
3320        );
3321        assert_eq!(
3322            parse_decimal::<Decimal32Type>(
3323                "+18232335063972188138031550982650807591758238.0724251287782783777442440E-58",
3324                1,
3325                0
3326            )
3327            .unwrap(),
3328            0
3329        );
3330        assert_eq!(
3331            parse_decimal::<Decimal128Type>("4825037936439135476.2609835314269495255615E-14", 9, 1)
3332                .unwrap(),
3333            482504
3334        );
3335        assert!(
3336            parse_decimal::<Decimal128Type>("4825037936439135476.2609835314269495255615E-14", 5, 1)
3337                .is_err()
3338        );
3339        // Absurdly long exponents saturate rather than wrap
3340        assert!(parse_decimal::<Decimal128Type>(&format!("1e{}", "9".repeat(30)), 38, 0).is_err());
3341        assert_eq!(
3342            parse_decimal::<Decimal128Type>(&format!("1e-{}", "9".repeat(30)), 38, 0).unwrap(),
3343            0
3344        );
3345    }
3346
3347    #[test]
3348    fn test_parse_decimal_negative_scale() {
3349        let tests = [
3350            ("1234.5", -2, 12),
3351            ("150", -2, 2),
3352            ("149", -2, 1),
3353            ("-150", -2, -2),
3354            ("-149", -2, -1),
3355            ("50", -2, 1),
3356            ("49", -2, 0),
3357            ("5", -1, 1),
3358            ("4", -1, 0),
3359            ("0.5", -1, 0),
3360            ("5.9", -1, 1),
3361            ("1e5", -2, 1000),
3362            ("1.5e5", -2, 1500),
3363            ("0.9e2", -1, 9),
3364            (".5e3", -2, 5),
3365            ("12345", -5, 0),
3366            ("12345", -4, 1),
3367            ("000123456", -3, 123),
3368            ("0", -5, 0),
3369            ("-0.0", -5, 0),
3370        ];
3371        for (s, scale, expected) in tests {
3372            assert_eq!(
3373                parse_decimal::<Decimal128Type>(s, 38, scale).unwrap(),
3374                expected,
3375                "{s} at scale {scale}"
3376            );
3377            assert_eq!(
3378                parse_decimal::<Decimal32Type>(s, 9, scale).unwrap(),
3379                expected as i32,
3380                "{s} at scale {scale}"
3381            );
3382            assert_eq!(
3383                parse_decimal::<Decimal256Type>(s, 76, scale).unwrap(),
3384                i256::from_i128(expected),
3385                "{s} at scale {scale}"
3386            );
3387        }
3388        // The integer part can be wider than the native type as long as the
3389        // scaled value fits
3390        assert_eq!(
3391            parse_decimal::<Decimal128Type>(&format!("1{}", "0".repeat(50)), 38, -40).unwrap(),
3392            10_000_000_000
3393        );
3394        assert_eq!(
3395            parse_decimal::<Decimal32Type>("123456789012", 9, -5).unwrap(),
3396            1234568
3397        );
3398        assert!(parse_decimal::<Decimal32Type>("123456789012", 9, -2).is_err());
3399    }
3400
3401    #[test]
3402    fn test_parse_decimal_whitespace_and_long_input() {
3403        for s in [" 1.5", "1.5 ", " 1.5 ", "\t1.5\n", "\r\n1.5\x0c"] {
3404            assert_eq!(
3405                parse_decimal::<Decimal128Type>(s, 38, 1).unwrap(),
3406                15,
3407                "{s:?}"
3408            );
3409        }
3410        // Only ASCII whitespace is trimmed, as for the other CSV parsers
3411        assert!(parse_decimal::<Decimal128Type>("\u{a0}1.5", 38, 1).is_err());
3412        assert!(parse_decimal::<Decimal128Type>("1.5\u{2003}", 38, 1).is_err());
3413        assert!(parse_decimal::<Decimal128Type>(" ", 38, 1).is_err());
3414
3415        // Long inputs report overflow rather than wrapping or panicking
3416        for s in [
3417            "1".repeat(255),
3418            "1".repeat(256),
3419            "1".repeat(300),
3420            format!("{}.5", "1".repeat(300)),
3421            format!("1e{}", "9".repeat(300)),
3422        ] {
3423            let err = parse_decimal::<Decimal128Type>(&s, 38, 0).unwrap_err();
3424            assert!(err.to_string().contains("does not fit"), "{err}");
3425        }
3426        // Long fractions only matter for rounding
3427        assert_eq!(
3428            parse_decimal::<Decimal128Type>(&format!("0.{}", "0".repeat(200)), 38, 10).unwrap(),
3429            0
3430        );
3431        assert_eq!(
3432            parse_decimal::<Decimal128Type>(&format!("0.{}1", "0".repeat(200)), 38, 10).unwrap(),
3433            0
3434        );
3435        assert_eq!(
3436            parse_decimal::<Decimal128Type>(&format!("1.{}", "9".repeat(300)), 38, 2).unwrap(),
3437            200
3438        );
3439        // 10^scale overflows the native type, but zero is still representable
3440        assert_eq!(parse_decimal::<Decimal32Type>("0", 9, 10).unwrap(), 0);
3441        assert_eq!(parse_decimal::<Decimal32Type>("-0.0", 9, 10).unwrap(), 0);
3442        assert_eq!(parse_decimal::<Decimal64Type>("0", 18, 20).unwrap(), 0);
3443        assert_eq!(parse_decimal::<Decimal128Type>("0", 38, 40).unwrap(), 0);
3444        assert!(parse_decimal::<Decimal32Type>("1", 9, 10).is_err());
3445    }
3446
3447    #[test]
3448    #[cfg_attr(miri, ignore)] // Takes too long under Miri (adds ~1 hour to CI)
3449    fn test_parse_decimal_matches_bigint_reference() {
3450        use num_bigint::BigInt;
3451        use rand::rngs::StdRng;
3452        use rand::{RngExt, SeedableRng};
3453
3454        /// Generates random decimal strings with a known exact value and checks
3455        /// that `parse_decimal` rounds them correctly or reports overflow
3456        fn check<T: DecimalType>(rng: &mut StdRng, iterations: usize)
3457        where
3458            T::Native: std::fmt::Display,
3459        {
3460            let random_digits = |rng: &mut StdRng, len: usize| -> String {
3461                (0..len)
3462                    .map(|_| char::from(b'0' + rng.random_range(0..10u8)))
3463                    .collect()
3464            };
3465            for _ in 0..iterations {
3466                let sign = ["", "+", "-"][rng.random_range(0..3)];
3467                let int_len = rng.random_range(0..=40);
3468                let frac_len = if rng.random_bool(0.3) {
3469                    0
3470                } else {
3471                    rng.random_range(0..=40)
3472                };
3473                if int_len == 0 && frac_len == 0 {
3474                    continue;
3475                }
3476                let int = random_digits(rng, int_len);
3477                let frac = random_digits(rng, frac_len);
3478                let mut s = format!("{sign}{int}");
3479                if frac_len > 0 || rng.random_bool(0.2) {
3480                    s.push('.');
3481                    s.push_str(&frac);
3482                }
3483                let exponent: i64 = if rng.random_bool(0.3) {
3484                    rng.random_range(-60..=60)
3485                } else {
3486                    0
3487                };
3488                if exponent != 0 || rng.random_bool(0.1) {
3489                    s.push(if rng.random_bool(0.5) { 'e' } else { 'E' });
3490                    if exponent >= 0 && rng.random_bool(0.5) {
3491                        s.push('+');
3492                    }
3493                    s.push_str(&exponent.to_string());
3494                }
3495                let precision = rng.random_range(1..=T::MAX_PRECISION);
3496                let scale = rng.random_range(-10..=T::MAX_SCALE.min(precision as i8));
3497
3498                // value = mantissa * 10^(exponent - frac_len), scaled by 10^scale
3499                // and rounded half away from zero
3500                let mantissa: BigInt = format!("{int}{frac}").parse().unwrap();
3501                let shift = exponent - frac_len as i64 + scale as i64;
3502                let mut expected = if shift >= 0 {
3503                    mantissa * BigInt::from(10).pow(shift as u32)
3504                } else {
3505                    let divisor = BigInt::from(10).pow((-shift) as u32);
3506                    let quotient = &mantissa / &divisor;
3507                    if (&mantissa % &divisor) * 2 >= divisor {
3508                        quotient + 1
3509                    } else {
3510                        quotient
3511                    }
3512                };
3513                if sign == "-" {
3514                    expected = -expected;
3515                }
3516                let limit = BigInt::from(10).pow(precision as u32);
3517                let fits = expected < limit && expected > -limit;
3518
3519                match (fits, parse_decimal::<T>(&s, precision, scale)) {
3520                    (true, Ok(actual)) => {
3521                        let actual: BigInt = actual.to_string().parse().unwrap();
3522                        assert_eq!(
3523                            actual,
3524                            expected,
3525                            "{s:?} as {}({precision}, {scale})",
3526                            T::PREFIX
3527                        );
3528                    }
3529                    (false, Err(_)) => {}
3530                    (true, Err(e)) => {
3531                        panic!(
3532                            "{s:?} as {}({precision}, {scale}): expected {expected}, got {e}",
3533                            T::PREFIX
3534                        )
3535                    }
3536                    (false, Ok(actual)) => panic!(
3537                        "{s:?} as {}({precision}, {scale}): expected overflow, got {actual}",
3538                        T::PREFIX
3539                    ),
3540                }
3541            }
3542        }
3543
3544        let mut rng = StdRng::seed_from_u64(0xDEC1_3A15);
3545        check::<Decimal32Type>(&mut rng, 5_000);
3546        check::<Decimal64Type>(&mut rng, 5_000);
3547        check::<Decimal128Type>(&mut rng, 5_000);
3548        check::<Decimal256Type>(&mut rng, 5_000);
3549    }
3550
3551    #[test]
3552    fn test_parse_empty() {
3553        assert_eq!(Int32Type::parse(""), None);
3554        assert_eq!(Int64Type::parse(""), None);
3555        assert_eq!(UInt32Type::parse(""), None);
3556        assert_eq!(UInt64Type::parse(""), None);
3557        assert_eq!(Float32Type::parse(""), None);
3558        assert_eq!(Float64Type::parse(""), None);
3559        assert_eq!(Int32Type::parse("+"), None);
3560        assert_eq!(Int64Type::parse("+"), None);
3561        assert_eq!(UInt32Type::parse("+"), None);
3562        assert_eq!(UInt64Type::parse("+"), None);
3563        assert_eq!(Float32Type::parse("+"), None);
3564        assert_eq!(Float64Type::parse("+"), None);
3565        assert_eq!(TimestampNanosecondType::parse(""), None);
3566        assert_eq!(Date32Type::parse(""), None);
3567    }
3568
3569    #[test]
3570    fn test_parse_interval_month_day_nano_config() {
3571        let interval = parse_interval_month_day_nano_config(
3572            "1",
3573            IntervalParseConfig::new(IntervalUnit::Second),
3574        )
3575        .unwrap();
3576        assert_eq!(interval.months, 0);
3577        assert_eq!(interval.days, 0);
3578        assert_eq!(interval.nanoseconds, NANOS_PER_SECOND);
3579    }
3580    #[test]
3581    fn test_parse_prefix_white_space() {
3582        assert_eq!(Float64Type::parse(" 1.5"), Some(1.5));
3583        assert_eq!(Float64Type::parse("\t\n 20.54"), Some(20.54));
3584        assert_eq!(Float64Type::parse("\n2.5"), Some(2.5));
3585        assert_eq!(Float64Type::parse("\n-942.5423"), Some(-942.5423));
3586        assert_eq!(Float64Type::parse("\n\t\n\t\n40.5123"), Some(40.5123));
3587        assert_eq!(Float64Type::parse(" 1.5"), Some(1.5));
3588        assert_eq!(Float64Type::parse("\n\t\n\t\n-40.5123"), Some(-40.5123));
3589        assert_eq!(Float64Type::parse(" -1.5"), Some(-1.5));
3590        assert_eq!(Int32Type::parse(" 3"), Some(3));
3591        assert_eq!(Int32Type::parse("          30"), Some(30));
3592        assert_eq!(Int32Type::parse("\n \n 100"), Some(100));
3593        assert_eq!(Int32Type::parse(" \n25"), Some(25));
3594        assert_eq!(Int32Type::parse("\t800"), Some(800));
3595        assert_eq!(Int32Type::parse("\t  \n \t 851"), Some(851));
3596        assert_eq!(Int32Type::parse("\t\n\t\n\n\n\t1"), Some(1));
3597        assert_eq!(Int32Type::parse(" \n-25"), Some(-25));
3598        assert_eq!(Int32Type::parse("\t-800"), Some(-800));
3599
3600        // suffix whitespace
3601        assert_eq!(Float64Type::parse("1.5 "), Some(1.5));
3602        assert_eq!(Float64Type::parse("40.5123\n"), Some(40.5123));
3603        assert_eq!(Float64Type::parse("40.5123\n\t\n\t\n"), Some(40.5123));
3604        assert_eq!(Float64Type::parse("-942.5423\t"), Some(-942.5423));
3605        assert_eq!(Int32Type::parse("3 "), Some(3));
3606        assert_eq!(Int32Type::parse("30          "), Some(30));
3607        assert_eq!(Int32Type::parse("-25 \n"), Some(-25));
3608        assert_eq!(Int32Type::parse("800\t"), Some(800));
3609        // whitespace on both sides
3610        assert_eq!(Float64Type::parse(" 1.5 "), Some(1.5));
3611        assert_eq!(Float64Type::parse("\t\n 20.54 \t"), Some(20.54));
3612        assert_eq!(Float64Type::parse("\n-942.5423\n"), Some(-942.5423));
3613        assert_eq!(Int32Type::parse(" 3 "), Some(3));
3614        assert_eq!(Int32Type::parse("\n \n 100 \n"), Some(100));
3615        assert_eq!(Int32Type::parse("\t-800\t\n"), Some(-800));
3616
3617        // trailing non-whitespace chars should not parse
3618        assert_eq!(Float64Type::parse("1.5abc"), None);
3619        assert_eq!(Float64Type::parse("40.5123x"), None);
3620        assert_eq!(Int32Type::parse("30x"), None);
3621        assert_eq!(Int32Type::parse("100px"), None);
3622        assert_eq!(Int32Type::parse("-25!"), None);
3623        assert_eq!(Int32Type::parse("3j"), None);
3624        assert_eq!(Int32Type::parse("3"), Some(3));
3625    }
3626}