1#![allow(missing_docs)]
13
14use std::collections::VecDeque;
15use std::fmt;
16use std::str::FromStr;
17
18use chrono::{NaiveDate, NaiveTime, Timelike};
19use mz_lowertest::MzReflect;
20use mz_persist_types::columnar::FixedSizeCodec;
21use mz_pgtz::timezone::Timezone;
22use mz_proto::{RustType, TryFromProtoError};
23use proptest_derive::Arbitrary;
24use serde::{Deserialize, Serialize};
25
26use crate::adt::interval::Interval;
27
28include!(concat!(env!("OUT_DIR"), "/mz_repr.adt.datetime.rs"));
29
30#[derive(
35 Arbitrary,
36 Clone,
37 Copy,
38 Debug,
39 PartialOrd,
40 Ord,
41 PartialEq,
42 Eq,
43 Hash,
44 Serialize,
45 Deserialize,
46 MzReflect,
47)]
48pub enum DateTimeUnits {
49 Epoch,
50 Millennium,
51 Century,
52 Decade,
53 Year,
54 Quarter,
55 Week,
56 Month,
57 Hour,
58 Day,
59 DayOfWeek,
60 DayOfYear,
61 IsoDayOfWeek,
62 IsoDayOfYear,
63 Minute,
64 Second,
65 Milliseconds,
66 Microseconds,
67 Timezone,
68 TimezoneHour,
69 TimezoneMinute,
70}
71
72impl fmt::Display for DateTimeUnits {
73 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74 match self {
75 Self::Epoch => f.write_str("epoch"),
76 Self::Millennium => f.write_str("millennium"),
77 Self::Century => f.write_str("century"),
78 Self::Decade => f.write_str("decade"),
79 Self::Year => f.write_str("year"),
80 Self::Quarter => f.write_str("quarter"),
81 Self::Week => f.write_str("week"),
82 Self::Month => f.write_str("month"),
83 Self::Hour => f.write_str("hour"),
84 Self::Day => f.write_str("day"),
85 Self::DayOfWeek => f.write_str("dow"),
86 Self::DayOfYear => f.write_str("doy"),
87 Self::IsoDayOfWeek => f.write_str("isodow"),
88 Self::IsoDayOfYear => f.write_str("isodoy"),
89 Self::Minute => f.write_str("minute"),
90 Self::Second => f.write_str("seconds"),
91 Self::Milliseconds => f.write_str("milliseconds"),
92 Self::Microseconds => f.write_str("microseconds"),
93 Self::Timezone => f.write_str("timezone"),
94 Self::TimezoneHour => f.write_str("timezone_hour"),
95 Self::TimezoneMinute => f.write_str("timezone_minute"),
96 }
97 }
98}
99
100impl FromStr for DateTimeUnits {
101 type Err = String;
102
103 fn from_str(s: &str) -> Result<Self, Self::Err> {
104 match s.to_lowercase().as_str() {
105 "epoch" => Ok(Self::Epoch),
106 "mil" | "millennia" | "millennium" | "millenniums" => Ok(Self::Millennium),
107 "c" | "cent" | "century" | "centuries" => Ok(Self::Century),
108 "dec" | "decs" | "decade" | "decades" => Ok(Self::Decade),
109 "y" | "year" | "years" | "yr" | "yrs" => Ok(Self::Year),
110 "qtr" | "quarter" => Ok(Self::Quarter),
111 "w" | "week" | "weeks" => Ok(Self::Week),
112 "d" | "day" | "days" => Ok(Self::Day),
113 "dow" => Ok(Self::DayOfWeek),
114 "doy" => Ok(Self::DayOfYear),
115 "isodow" => Ok(Self::IsoDayOfWeek),
116 "isodoy" => Ok(Self::IsoDayOfYear),
117 "h" | "hour" | "hours" | "hr" | "hrs" => Ok(Self::Hour),
118 "us" | "usec" | "usecs" | "useconds" | "microsecond" | "microseconds" => {
119 Ok(Self::Microseconds)
120 }
121 "m" | "min" | "mins" | "minute" | "minutes" => Ok(Self::Minute),
122 "mon" | "mons" | "month" | "months" => Ok(Self::Month),
123 "ms" | "msec" | "msecs" | "mseconds" | "millisecond" | "milliseconds" => {
124 Ok(Self::Milliseconds)
125 }
126 "s" | "sec" | "second" | "seconds" | "secs" => Ok(Self::Second),
127 "timezone" => Ok(Self::Timezone),
128 "timezone_h" | "timezone_hour" => Ok(Self::TimezoneHour),
129 "timezone_m" | "timezone_minute" => Ok(Self::TimezoneMinute),
130 _ => Err(format!("unknown units {}", s)),
131 }
132 }
133}
134
135impl RustType<ProtoDateTimeUnits> for DateTimeUnits {
136 fn into_proto(&self) -> ProtoDateTimeUnits {
137 use proto_date_time_units::Kind;
138 ProtoDateTimeUnits {
139 kind: Some(match self {
140 DateTimeUnits::Epoch => Kind::Epoch(()),
141 DateTimeUnits::Millennium => Kind::Millennium(()),
142 DateTimeUnits::Century => Kind::Century(()),
143 DateTimeUnits::Decade => Kind::Decade(()),
144 DateTimeUnits::Year => Kind::Year(()),
145 DateTimeUnits::Quarter => Kind::Quarter(()),
146 DateTimeUnits::Week => Kind::Week(()),
147 DateTimeUnits::Month => Kind::Month(()),
148 DateTimeUnits::Hour => Kind::Hour(()),
149 DateTimeUnits::Day => Kind::Day(()),
150 DateTimeUnits::DayOfWeek => Kind::DayOfWeek(()),
151 DateTimeUnits::DayOfYear => Kind::DayOfYear(()),
152 DateTimeUnits::IsoDayOfWeek => Kind::IsoDayOfWeek(()),
153 DateTimeUnits::IsoDayOfYear => Kind::IsoDayOfYear(()),
154 DateTimeUnits::Minute => Kind::Minute(()),
155 DateTimeUnits::Second => Kind::Second(()),
156 DateTimeUnits::Milliseconds => Kind::Milliseconds(()),
157 DateTimeUnits::Microseconds => Kind::Microseconds(()),
158 DateTimeUnits::Timezone => Kind::Timezone(()),
159 DateTimeUnits::TimezoneHour => Kind::TimezoneHour(()),
160 DateTimeUnits::TimezoneMinute => Kind::TimezoneMinute(()),
161 }),
162 }
163 }
164
165 fn from_proto(proto: ProtoDateTimeUnits) -> Result<Self, TryFromProtoError> {
166 use proto_date_time_units::Kind;
167 let kind = proto
168 .kind
169 .ok_or_else(|| TryFromProtoError::missing_field("ProtoDateTimeUnits.kind"))?;
170 Ok(match kind {
171 Kind::Epoch(_) => DateTimeUnits::Epoch,
172 Kind::Millennium(_) => DateTimeUnits::Millennium,
173 Kind::Century(_) => DateTimeUnits::Century,
174 Kind::Decade(_) => DateTimeUnits::Decade,
175 Kind::Year(_) => DateTimeUnits::Year,
176 Kind::Quarter(_) => DateTimeUnits::Quarter,
177 Kind::Week(_) => DateTimeUnits::Week,
178 Kind::Month(_) => DateTimeUnits::Month,
179 Kind::Hour(_) => DateTimeUnits::Hour,
180 Kind::Day(_) => DateTimeUnits::Day,
181 Kind::DayOfWeek(_) => DateTimeUnits::DayOfWeek,
182 Kind::DayOfYear(_) => DateTimeUnits::DayOfYear,
183 Kind::IsoDayOfWeek(_) => DateTimeUnits::IsoDayOfWeek,
184 Kind::IsoDayOfYear(_) => DateTimeUnits::IsoDayOfYear,
185 Kind::Minute(_) => DateTimeUnits::Minute,
186 Kind::Second(_) => DateTimeUnits::Second,
187 Kind::Milliseconds(_) => DateTimeUnits::Milliseconds,
188 Kind::Microseconds(_) => DateTimeUnits::Microseconds,
189 Kind::Timezone(_) => DateTimeUnits::Timezone,
190 Kind::TimezoneHour(_) => DateTimeUnits::TimezoneHour,
191 Kind::TimezoneMinute(_) => DateTimeUnits::TimezoneMinute,
192 })
193 }
194}
195
196#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
198pub enum DateTimePart {
199 Microseconds,
200 Milliseconds,
201 Second,
202 Minute,
203 Hour,
204 Day,
205 Week,
206 Month,
207 Quarter,
208 Year,
209 Decade,
210 Century,
211 Millennium,
212}
213
214impl FromStr for DateTimePart {
215 type Err = String;
216
217 fn from_str(s: &str) -> Result<Self, Self::Err> {
218 let units: DateTimeUnits = s.parse()?;
219
220 match units {
221 DateTimeUnits::Microseconds => Ok(DateTimePart::Microseconds),
222 DateTimeUnits::Milliseconds => Ok(DateTimePart::Milliseconds),
223 DateTimeUnits::Second => Ok(DateTimePart::Second),
224 DateTimeUnits::Minute => Ok(DateTimePart::Minute),
225 DateTimeUnits::Hour => Ok(DateTimePart::Hour),
226 DateTimeUnits::Day => Ok(DateTimePart::Day),
227 DateTimeUnits::Week => Ok(DateTimePart::Week),
228 DateTimeUnits::Month => Ok(DateTimePart::Month),
229 DateTimeUnits::Quarter => Ok(DateTimePart::Quarter),
230 DateTimeUnits::Year => Ok(DateTimePart::Year),
231 DateTimeUnits::Decade => Ok(DateTimePart::Decade),
232 DateTimeUnits::Century => Ok(DateTimePart::Century),
233 DateTimeUnits::Millennium => Ok(DateTimePart::Millennium),
234 _ => Err(s.to_string()),
235 }
236 }
237}
238
239#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
241pub enum DateTimeField {
242 Microseconds,
243 Milliseconds,
244 Second,
245 Minute,
246 Hour,
247 Day,
248 Month,
249 Year,
250 Decade,
251 Century,
252 Millennium,
253}
254
255impl fmt::Display for DateTimeField {
256 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
257 f.write_str(match self {
258 DateTimeField::Millennium => "MILLENNIUM",
259 DateTimeField::Century => "CENTURY",
260 DateTimeField::Decade => "DECADE",
261 DateTimeField::Year => "YEAR",
262 DateTimeField::Month => "MONTH",
263 DateTimeField::Day => "DAY",
264 DateTimeField::Hour => "HOUR",
265 DateTimeField::Minute => "MINUTE",
266 DateTimeField::Second => "SECOND",
267 DateTimeField::Milliseconds => "MILLISECONDS",
268 DateTimeField::Microseconds => "MICROSECONDS",
269 })
270 }
271}
272
273impl IntoIterator for DateTimeField {
275 type Item = DateTimeField;
276 type IntoIter = DateTimeFieldIterator;
277 fn into_iter(self) -> DateTimeFieldIterator {
278 DateTimeFieldIterator(Some(self))
279 }
280}
281
282impl FromStr for DateTimeField {
283 type Err = String;
284
285 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
286 match s.to_uppercase().as_ref() {
287 "MILLENNIUM" | "MILLENNIUMS" | "MILLENNIA" | "MIL" | "MILS" => Ok(Self::Millennium),
288 "CENTURY" | "CENTURIES" | "CENT" | "C" => Ok(Self::Century),
289 "DECADE" | "DECADES" | "DEC" | "DECS" => Ok(Self::Decade),
290 "YEAR" | "YEARS" | "YR" | "YRS" | "Y" => Ok(Self::Year),
291 "MONTH" | "MONTHS" | "MON" | "MONS" => Ok(Self::Month),
292 "DAY" | "DAYS" | "D" => Ok(Self::Day),
293 "HOUR" | "HOURS" | "HR" | "HRS" | "H" => Ok(Self::Hour),
294 "MINUTE" | "MINUTES" | "MIN" | "MINS" | "M" => Ok(Self::Minute),
295 "SECOND" | "SECONDS" | "SEC" | "SECS" | "S" => Ok(Self::Second),
296 "MILLISECOND" | "MILLISECONDS" | "MILLISECON" | "MILLISECONS" | "MSECOND"
297 | "MSECONDS" | "MSEC" | "MSECS" | "MS" => Ok(Self::Milliseconds),
298 "MICROSECOND" | "MICROSECONDS" | "MICROSECON" | "MICROSECONS" | "USECOND"
299 | "USECONDS" | "USEC" | "USECS" | "US" => Ok(Self::Microseconds),
300 _ => Err(format!("invalid DateTimeField: {}", s)),
301 }
302 }
303}
304
305impl DateTimeField {
306 pub fn next_smallest(self) -> Self {
310 self.into_iter()
311 .next()
312 .unwrap_or_else(|| panic!("Cannot get smaller DateTimeField than {}", self))
313 }
314 pub fn next_largest(self) -> Self {
318 self.into_iter()
319 .next_back()
320 .unwrap_or_else(|| panic!("Cannot get larger DateTimeField than {}", self))
321 }
322
323 pub fn micros_multiplier(self) -> i64 {
329 use DateTimeField::*;
330 match self {
331 Day | Hour | Minute | Second | Milliseconds | Microseconds => {}
332 _other => unreachable!("Do not call with a non-time/day field"),
333 }
334
335 Interval::convert_date_time_unit(self, Self::Microseconds, 1i64).unwrap()
336 }
337
338 pub fn month_multiplier(self) -> i64 {
344 use DateTimeField::*;
345 match self {
346 Millennium | Century | Decade | Year => {}
347 _other => unreachable!("Do not call with a duration field"),
348 }
349
350 Interval::convert_date_time_unit(self, Self::Microseconds, 1i64).unwrap()
351 }
352}
353
354#[derive(Debug)]
368pub struct DateTimeFieldIterator(Option<DateTimeField>);
369
370impl Iterator for DateTimeFieldIterator {
372 type Item = DateTimeField;
373 fn next(&mut self) -> Option<Self::Item> {
374 use DateTimeField::*;
375 self.0 = match self.0 {
376 Some(Millennium) => Some(Century),
377 Some(Century) => Some(Decade),
378 Some(Decade) => Some(Year),
379 Some(Year) => Some(Month),
380 Some(Month) => Some(Day),
381 Some(Day) => Some(Hour),
382 Some(Hour) => Some(Minute),
383 Some(Minute) => Some(Second),
384 Some(Second) => Some(Milliseconds),
385 Some(Milliseconds) => Some(Microseconds),
386 Some(Microseconds) => None,
387 None => None,
388 };
389 self.0.clone()
390 }
391}
392
393impl DoubleEndedIterator for DateTimeFieldIterator {
394 fn next_back(&mut self) -> Option<Self::Item> {
395 use DateTimeField::*;
396 self.0 = match self.0 {
397 Some(Millennium) => None,
398 Some(Century) => Some(Millennium),
399 Some(Decade) => Some(Century),
400 Some(Year) => Some(Decade),
401 Some(Month) => Some(Year),
402 Some(Day) => Some(Month),
403 Some(Hour) => Some(Day),
404 Some(Minute) => Some(Hour),
405 Some(Second) => Some(Minute),
406 Some(Milliseconds) => Some(Second),
407 Some(Microseconds) => Some(Milliseconds),
408 None => None,
409 };
410 self.0.clone()
411 }
412}
413
414#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
417pub struct DateTimeFieldValue {
418 pub unit: i64,
420 pub fraction: i64,
423}
424
425impl Default for DateTimeFieldValue {
426 fn default() -> Self {
427 DateTimeFieldValue {
428 unit: 0,
429 fraction: 0,
430 }
431 }
432}
433
434impl DateTimeFieldValue {
435 pub fn new(unit: i64, fraction: i64) -> Self {
437 DateTimeFieldValue { unit, fraction }
438 }
439
440 const FRACTIONAL_DIGIT_PRECISION: i64 = 1_000_000_000;
443}
444
445#[derive(Debug, Clone, PartialEq, Eq, Hash)]
448pub struct ParsedDateTime {
449 pub millennium: Option<DateTimeFieldValue>,
450 pub century: Option<DateTimeFieldValue>,
451 pub decade: Option<DateTimeFieldValue>,
452 pub year: Option<DateTimeFieldValue>,
453 pub month: Option<DateTimeFieldValue>,
454 pub day: Option<DateTimeFieldValue>,
455 pub hour: Option<DateTimeFieldValue>,
456 pub minute: Option<DateTimeFieldValue>,
457 pub second: Option<DateTimeFieldValue>,
459 pub millisecond: Option<DateTimeFieldValue>,
460 pub microsecond: Option<DateTimeFieldValue>,
461 pub timezone_offset_second: Option<Timezone>,
462}
463
464impl Default for ParsedDateTime {
465 fn default() -> Self {
466 ParsedDateTime {
467 millennium: None,
468 century: None,
469 decade: None,
470 year: None,
471 month: None,
472 day: None,
473 hour: None,
474 minute: None,
475 second: None,
476 millisecond: None,
477 microsecond: None,
478 timezone_offset_second: None,
479 }
480 }
481}
482
483impl ParsedDateTime {
484 pub fn compute_interval(&self) -> Result<Interval, String> {
489 use DateTimeField::*;
490 let mut months = 0i32;
491 let mut days = 0i32;
492 let mut micros = 0i64;
493
494 self.add_field(Millennium, &mut months, &mut days, &mut micros)?;
496
497 for field in Millennium.into_iter().take_while(|f| *f >= Microseconds) {
498 self.add_field(field, &mut months, &mut days, &mut micros)?;
499 }
500
501 Ok(Interval::new(months, days, micros))
502 }
503 fn add_field(
510 &self,
511 d: DateTimeField,
512 months: &mut i32,
513 days: &mut i32,
514 micros: &mut i64,
515 ) -> Result<(), String> {
516 use DateTimeField::*;
517 fn div_and_round(i: i128, d: i64) -> Option<i64> {
519 let mut res = i / i128::from(d);
520 let round_digit = (i / (i128::from(d) / 10)) % 10;
521 if round_digit > 4 {
522 res += 1;
523 } else if round_digit < -4 {
524 res -= 1;
525 }
526 i64::try_from(res).ok()
527 }
528 match d {
529 Millennium | Century | Decade | Year => {
530 let (y, y_f) = match self.units_of(d) {
531 Some(y) => (y.unit, y.fraction),
532 None => return Ok(()),
533 };
534 *months = Interval::convert_date_time_unit(d, DateTimeField::Month, y)
536 .and_then(|y_m| i32::try_from(y_m).ok())
537 .and_then(|y_m| months.checked_add(y_m))
538 .ok_or_else(|| {
539 format!(
540 "Overflows maximum months; cannot exceed {}/{} months",
541 i32::MAX,
542 i32::MIN,
543 )
544 })?;
545
546 *months = Interval::convert_date_time_unit(d, DateTimeField::Month, y_f)
548 .and_then(|y_f_m| {
549 y_f_m.checked_div(DateTimeFieldValue::FRACTIONAL_DIGIT_PRECISION)
550 })
551 .and_then(|y_f_m| i32::try_from(y_f_m).ok())
552 .and_then(|y_f_m| months.checked_add(y_f_m))
553 .ok_or_else(|| {
554 format!(
555 "Overflows maximum months; cannot exceed {}/{} months",
556 i32::MAX,
557 i32::MIN,
558 )
559 })?;
560 Ok(())
561 }
562 Month => {
563 let (m, m_f) = match self.units_of(Month) {
564 Some(m) => (m.unit, m.fraction),
565 None => return Ok(()),
566 };
567
568 *months = i32::try_from(m)
570 .ok()
571 .and_then(|m_month| months.checked_add(m_month))
572 .ok_or_else(|| {
573 format!(
574 "Overflows maximum months; cannot exceed {}/{} months",
575 i32::MAX,
576 i32::MIN,
577 )
578 })?;
579
580 let m_f_days = Interval::convert_date_time_unit(d, DateTimeField::Day, m_f)
581 .ok_or_else(|| "Intermediate overflow in MONTH fraction".to_owned())?;
582 *days = m_f_days
584 .checked_div(DateTimeFieldValue::FRACTIONAL_DIGIT_PRECISION)
585 .and_then(|m_f_days| i32::try_from(m_f_days).ok())
586 .and_then(|m_f_days| days.checked_add(m_f_days))
587 .ok_or_else(|| {
588 format!(
589 "Overflows maximum seconds; cannot exceed {}/{} days",
590 i32::MAX,
591 i32::MIN,
592 )
593 })?;
594
595 *micros = i128::from(m_f_days)
597 .checked_rem(DateTimeFieldValue::FRACTIONAL_DIGIT_PRECISION.into())
598 .and_then(|m_f_us| {
599 Interval::convert_date_time_unit(
600 DateTimeField::Day,
601 DateTimeField::Microseconds,
602 m_f_us,
603 )
604 })
605 .and_then(|m_f_us| {
606 div_and_round(m_f_us, DateTimeFieldValue::FRACTIONAL_DIGIT_PRECISION)
607 })
608 .and_then(|m_f_us| micros.checked_add(m_f_us))
609 .ok_or_else(|| {
610 format!(
611 "Overflows maximum microseconds; cannot exceed {}/{} microseconds",
612 i64::MAX,
613 i64::MIN
614 )
615 })?;
616
617 Ok(())
618 }
619 Day => {
620 let (t, t_f) = match self.units_of(d) {
621 Some(t) => (t.unit, t.fraction),
622 None => return Ok(()),
623 };
624
625 *days = i32::try_from(t)
627 .ok()
628 .and_then(|t_day| days.checked_add(t_day))
629 .ok_or_else(|| {
630 format!(
631 "Overflows maximum days; cannot exceed {}/{} days",
632 i32::MAX,
633 i32::MIN,
634 )
635 })?;
636
637 *micros = Interval::convert_date_time_unit(
639 d,
640 DateTimeField::Microseconds,
641 i128::from(t_f),
642 )
643 .and_then(|t_f_us| {
644 div_and_round(t_f_us, DateTimeFieldValue::FRACTIONAL_DIGIT_PRECISION)
645 })
646 .and_then(|t_f_us| micros.checked_add(t_f_us))
647 .ok_or_else(|| {
648 format!(
649 "Overflows maximum microseconds; cannot exceed {}/{} microseconds",
650 i64::MAX,
651 i64::MIN
652 )
653 })?;
654
655 Ok(())
656 }
657 Hour | Minute | Second | Milliseconds | Microseconds => {
658 let (t, t_f) = match self.units_of(d) {
659 Some(t) => (t.unit, t.fraction),
660 None => return Ok(()),
661 };
662
663 *micros = Interval::convert_date_time_unit(d, DateTimeField::Microseconds, t)
665 .and_then(|t_s| micros.checked_add(t_s))
666 .ok_or_else(|| {
667 format!(
668 "Overflows maximum microseconds; cannot exceed {}/{} microseconds",
669 i64::MAX,
670 i64::MIN,
671 )
672 })?;
673
674 *micros = Interval::convert_date_time_unit(d, DateTimeField::Microseconds, t_f)
676 .and_then(|t_f_ns| {
677 div_and_round(
678 t_f_ns.into(),
679 DateTimeFieldValue::FRACTIONAL_DIGIT_PRECISION,
680 )
681 })
682 .and_then(|t_f_ns| micros.checked_add(t_f_ns))
683 .ok_or_else(|| {
684 format!(
685 "Overflows maximum microseconds; cannot exceed {}/{} microseconds",
686 i64::MAX,
687 i64::MIN,
688 )
689 })?;
690 Ok(())
691 }
692 }
693 }
694
695 pub fn compute_date(&self) -> Result<chrono::NaiveDate, String> {
705 match (self.year, self.month, self.day) {
706 (Some(year), Some(month), Some(day)) => {
707 let year = if year.unit < 0 {
709 year.unit + 1
710 } else {
711 year.unit
712 };
713 let p_err = |e, field| format!("{} in date is invalid: {}", field, e);
714 let year = year.try_into().map_err(|e| p_err(e, "Year"))?;
715 let month = month.unit.try_into().map_err(|e| p_err(e, "Month"))?;
716 let day = day.unit.try_into().map_err(|e| p_err(e, "Day"))?;
717 NaiveDate::from_ymd_opt(year, month, day)
718 .ok_or_else(|| "invalid or out-of-range date".into())
719 }
720 (_, _, _) => Err("YEAR, MONTH, DAY are all required".into()),
721 }
722 }
723
724 pub fn compute_time(&self) -> Result<chrono::NaiveTime, String> {
729 let p_err = |e, field| format!("invalid {}: {}", field, e);
730 let hour = match self.hour {
731 Some(hour) => hour.unit.try_into().map_err(|e| p_err(e, "HOUR"))?,
732 None => 0,
733 };
734 let minute = match self.minute {
735 Some(minute) => minute.unit.try_into().map_err(|e| p_err(e, "MINUTE"))?,
736 None => 0,
737 };
738 let (second, nano) = match self.second {
739 Some(second) => {
740 let nano: u32 = second
741 .fraction
742 .try_into()
743 .map_err(|e| p_err(e, "NANOSECOND"))?;
744 let second: u32 = second.unit.try_into().map_err(|e| p_err(e, "MINUTE"))?;
745 (second, nano)
746 }
747 None => (0, 0),
748 };
749 Ok(NaiveTime::from_hms_nano_opt(hour, minute, second, nano).unwrap())
750 }
751
752 pub fn build_parsed_datetime_interval(
763 value: &str,
764 leading_time_precision: Option<DateTimeField>,
765 ambiguous_resolver: DateTimeField,
766 ) -> Result<ParsedDateTime, String> {
767 use DateTimeField::*;
768
769 let mut pdt = ParsedDateTime::default();
770 let mut value_parts = VecDeque::new();
771 let mut value_tokens = tokenize_time_str(value.trim())?;
772 let mut token_buffer = VecDeque::new();
773
774 while let Some(t) = value_tokens.pop_front() {
775 match t {
776 TimeStrToken::Delim => {
777 if !token_buffer.is_empty() {
778 value_parts.push_back(token_buffer.clone());
779 token_buffer.clear();
780 }
781 }
782 TimeStrToken::Colon if token_buffer.is_empty() => {}
784 _ => token_buffer.push_back(t),
785 }
786 }
787
788 if !token_buffer.is_empty() {
789 value_parts.push_back(token_buffer)
790 }
791
792 let mut annotated_parts = Vec::new();
793
794 while let Some(part) = value_parts.pop_front() {
795 let mut fmt = determine_format_w_datetimefield(part.clone(), leading_time_precision)?;
796 if fmt.is_none() {
799 fmt = match value_parts.pop_front() {
800 Some(next_part) => {
801 match determine_format_w_datetimefield(next_part.clone(), None)? {
802 Some(TimePartFormat::SqlStandard(f)) => {
803 match f {
804 Year | Month | Day => None,
807 _ => {
811 annotated_parts.push(AnnotatedIntervalPart {
814 fmt: TimePartFormat::SqlStandard(f),
815 tokens: next_part.clone(),
816 });
817 Some(TimePartFormat::PostgreSql(Day))
818 }
819 }
820 }
821 next_fmt => next_fmt,
828 }
829 }
830 None => Some(TimePartFormat::PostgreSql(ambiguous_resolver)),
832 }
833 }
834 match fmt {
835 Some(fmt) => annotated_parts.push(AnnotatedIntervalPart {
836 fmt,
837 tokens: part.clone(),
838 }),
839 None => {
840 return Err("Cannot determine format of all parts. Add \
841 explicit time components, e.g. INTERVAL '1 day' or INTERVAL '1' DAY"
842 .into());
843 }
844 }
845 }
846
847 for mut ap in annotated_parts {
848 match ap.fmt {
849 TimePartFormat::SqlStandard(f) => {
850 fill_pdt_interval_sql(&mut ap.tokens, f, &mut pdt)?;
851 pdt.check_interval_bounds(f)?;
852 }
853 TimePartFormat::PostgreSql(f) => fill_pdt_interval_pg(&mut ap.tokens, f, &mut pdt)?,
854 }
855
856 while let Some(TimeStrToken::TimeUnit(_)) = ap.tokens.front() {
858 ap.tokens.pop_front();
859 }
860
861 if !ap.tokens.is_empty() {
862 return Err(format!(
863 "have unprocessed tokens {}",
864 itertools::join(ap.tokens, "").trim_end(),
865 ));
866 }
867 }
868
869 Ok(pdt)
870 }
871 pub fn build_parsed_datetime_timestamp(
877 value: &str,
878 era: CalendarEra,
879 ) -> Result<ParsedDateTime, String> {
880 let mut pdt = ParsedDateTime::default();
881
882 let mut ts_actual = tokenize_time_str(value)?;
883
884 fill_pdt_date(&mut pdt, &mut ts_actual)?;
885
886 if let CalendarEra::BC = era {
887 pdt.year = pdt.year.map(|mut y| {
888 y.unit = -y.unit;
889 y
890 });
891 }
892
893 if let Some(TimeStrToken::DateTimeDelimiter) = ts_actual.front() {
894 ts_actual.pop_front();
895 ltrim_delim_or_colon(&mut ts_actual);
896 }
897
898 fill_pdt_time(&mut pdt, &mut ts_actual)?;
899 pdt.check_datelike_bounds()?;
900
901 if ts_actual.is_empty() {
902 Ok(pdt)
903 } else {
904 Err(format!(
905 "have unprocessed tokens {}",
906 itertools::join(ts_actual, "").trim_end(),
907 ))
908 }
909 }
910 pub fn build_parsed_datetime_time(value: &str) -> Result<ParsedDateTime, String> {
916 let mut pdt = ParsedDateTime::default();
917
918 let mut time_actual = tokenize_time_str(value)?;
919 fill_pdt_time(&mut pdt, &mut time_actual)?;
920 pdt.check_datelike_bounds()?;
921
922 if time_actual.is_empty() {
923 Ok(pdt)
924 } else {
925 Err(format!(
926 "have unprocessed tokens {}",
927 itertools::join(time_actual, "").trim_end(),
928 ))
929 }
930 }
931
932 pub fn write_field_iff_none(
935 &mut self,
936 f: DateTimeField,
937 u: Option<DateTimeFieldValue>,
938 ) -> Result<(), String> {
939 use DateTimeField::*;
940
941 if u.is_some() {
942 match f {
943 Millennium if self.millennium.is_none() => {
944 self.millennium = u;
945 }
946 Century if self.century.is_none() => {
947 self.century = u;
948 }
949 Decade if self.decade.is_none() => {
950 self.decade = u;
951 }
952 Year if self.year.is_none() => {
953 self.year = u;
954 }
955 Month if self.month.is_none() => {
956 self.month = u;
957 }
958 Day if self.day.is_none() => {
959 self.day = u;
960 }
961 Hour if self.hour.is_none() => {
962 self.hour = u;
963 }
964 Minute if self.minute.is_none() => {
965 self.minute = u;
966 }
967 Second if self.second.is_none() => {
968 if u.as_ref().unwrap().fraction != 0
969 && (self.millisecond.is_some() || self.microsecond.is_some())
970 {
971 return Err(format!(
972 "Cannot set {} or {} field if {} field has a fraction component",
973 Milliseconds, Microseconds, f
974 ));
975 }
976 self.second = u;
977 }
978 Milliseconds if self.millisecond.is_none() => {
979 if self.seconds_has_fraction() {
980 return Err(format!(
981 "Cannot set {} or {} field if {} field has a fraction component",
982 f, Microseconds, Second
983 ));
984 }
985 self.millisecond = u;
986 }
987 Microseconds if self.microsecond.is_none() => {
988 if self.seconds_has_fraction() {
989 return Err(format!(
990 "Cannot set {} or {} field if {} field has a fraction component",
991 Milliseconds, f, Second
992 ));
993 }
994 self.microsecond = u;
995 }
996 _ => return Err(format!("{} field set twice", f)),
997 }
998 }
999 Ok(())
1000 }
1001
1002 fn seconds_has_fraction(&self) -> bool {
1003 self.second.is_some() && self.second.as_ref().unwrap().fraction != 0
1004 }
1005
1006 pub fn check_datelike_bounds(&mut self) -> Result<(), String> {
1007 if let Some(year) = self.year {
1008 if year.unit == 0 {
1010 return Err("YEAR cannot be zero".to_string());
1011 }
1012 }
1013 if let Some(month) = self.month {
1014 if month.unit < 1 || month.unit > 12 {
1015 return Err(format!("MONTH must be [1, 12], got {}", month.unit));
1016 };
1017 }
1018 if let Some(day) = self.day {
1019 if day.unit < 1 || day.unit > 31 {
1020 return Err(format!("DAY must be [1, 31], got {}", day.unit));
1021 };
1022 }
1023 if let Some(hour) = self.hour {
1024 if hour.unit < 0 || hour.unit > 23 {
1025 return Err(format!("HOUR must be [0, 23], got {}", hour.unit));
1026 };
1027 }
1028 if let Some(minute) = self.minute {
1029 if minute.unit < 0 || minute.unit > 59 {
1030 return Err(format!("MINUTE must be [0, 59], got {}", minute.unit));
1031 };
1032 }
1033
1034 if let Some(second) = &mut self.second {
1035 if second.unit == 60 {
1040 second.unit = 59;
1041 second.fraction = second.fraction.saturating_add(1_000_000_000);
1042 }
1043 if second.unit < 0 || second.unit > 60 {
1044 return Err(format!("SECOND must be [0, 60], got {}", second.unit));
1045 };
1046 if second.fraction < 0 || second.fraction > 1_000_000_000 {
1047 return Err(format!(
1048 "NANOSECOND must be [0, 1_000_000_000], got {}",
1049 second.fraction
1050 ));
1051 };
1052 }
1053
1054 Ok(())
1055 }
1056 pub fn check_interval_bounds(&self, d: DateTimeField) -> Result<(), String> {
1057 use DateTimeField::*;
1058
1059 match d {
1060 Millennium | Century | Decade | Year | Month => {
1061 if let Some(month) = self.month {
1062 if month.unit < -12 || month.unit > 12 {
1063 return Err(format!("MONTH must be [-12, 12], got {}", month.unit));
1064 };
1065 }
1066 }
1067 Hour | Minute | Second | Milliseconds | Microseconds => {
1068 if let Some(minute) = self.minute {
1069 if minute.unit < -59 || minute.unit > 59 {
1070 return Err(format!("MINUTE must be [-59, 59], got {}", minute.unit));
1071 };
1072 }
1073
1074 let mut seconds = 0;
1075 let mut nanoseconds = 0;
1076
1077 if let Some(second) = self.second {
1078 seconds += second.unit;
1079 nanoseconds += second.fraction;
1080 }
1081
1082 if let Some(millisecond) = self.millisecond {
1083 seconds += millisecond.unit / 1_000;
1084 nanoseconds += (millisecond.unit % 1_000) * 1_000_000;
1085 nanoseconds += (millisecond.fraction / 1_000) % 1_000_000_000;
1086 }
1087
1088 if let Some(microsecond) = self.microsecond {
1089 seconds += microsecond.unit / 1_000_000;
1090 nanoseconds += (microsecond.unit % 1_000_000) * 1_000;
1091 nanoseconds += (microsecond.fraction / 1_000_000) % 1_000_000_000;
1092 }
1093
1094 if seconds < -60 || seconds > 60 {
1095 return Err(format!("SECOND must be [-60, 60], got {}", seconds));
1096 };
1097 if nanoseconds < -1_000_000_000 || nanoseconds > 1_000_000_000 {
1098 return Err(format!(
1099 "NANOSECOND must be [-1_000_000_000, 1_000_000_000], got {}",
1100 nanoseconds
1101 ));
1102 };
1103 }
1104 Day => {}
1105 }
1106
1107 Ok(())
1108 }
1109
1110 pub fn clear_date(&mut self) {
1111 self.year = None;
1112 self.month = None;
1113 self.day = None;
1114 }
1115
1116 fn units_of(&self, field: DateTimeField) -> Option<DateTimeFieldValue> {
1119 match field {
1120 DateTimeField::Millennium => self.millennium,
1121 DateTimeField::Century => self.century,
1122 DateTimeField::Decade => self.decade,
1123 DateTimeField::Year => self.year,
1124 DateTimeField::Month => self.month,
1125 DateTimeField::Day => self.day,
1126 DateTimeField::Hour => self.hour,
1127 DateTimeField::Minute => self.minute,
1128 DateTimeField::Second => self.second,
1129 DateTimeField::Milliseconds => self.millisecond,
1130 DateTimeField::Microseconds => self.microsecond,
1131 }
1132 }
1133}
1134
1135fn fill_pdt_date(
1144 pdt: &mut ParsedDateTime,
1145 actual: &mut VecDeque<TimeStrToken>,
1146) -> Result<(), String> {
1147 use TimeStrToken::*;
1148
1149 match actual.front() {
1151 Some(&Num(mut val, ref digits)) if 6 <= *digits && *digits <= 8 => {
1152 let unit = i64::try_from(val % 100)
1153 .expect("modulo between u64 and constant 100 should fit signed 64-bit integer");
1154 pdt.day = Some(DateTimeFieldValue::new(unit, 0));
1155 val /= 100;
1156
1157 let unit = i64::try_from(val % 100)
1158 .expect("modulo between u64 and constant 100 should fit signed 64-bit integer");
1159 pdt.month = Some(DateTimeFieldValue::new(unit, 0));
1160 val /= 100;
1161 if *digits == 6 {
1163 if val < 70 {
1164 val += 2000;
1165 } else {
1166 val += 1900;
1167 }
1168 }
1169
1170 let unit = i64::try_from(val)
1171 .map_err(|_| "number should fit in signed 64-bit integer".to_string())?;
1172 pdt.year = Some(DateTimeFieldValue::new(unit, 0));
1173 actual.pop_front();
1174 if let Some(Delim) = actual.front() {
1177 actual.pop_front();
1178 ltrim_delim_or_colon(actual);
1179 }
1180 return Ok(());
1181 }
1182 _ => (),
1183 }
1184
1185 let valid_formats = [
1186 [
1187 Num(0, 1), Dash,
1189 Num(0, 1), Dash,
1191 Num(0, 1), ],
1193 [
1194 Num(0, 1), Delim,
1196 Num(0, 1), Dash,
1198 Num(0, 1), ],
1200 [
1201 Num(0, 1), Delim,
1203 Num(0, 1), Delim,
1205 Num(0, 1), ],
1207 ];
1208
1209 let original_actual = actual.clone();
1210
1211 for expected in valid_formats {
1212 match fill_pdt_from_tokens(pdt, actual, &expected, DateTimeField::Year, 1) {
1213 Ok(()) => {
1214 return Ok(());
1215 }
1216 Err(_) => {
1217 actual.clone_from(&original_actual);
1218 pdt.clear_date();
1219 }
1220 }
1221 }
1222
1223 Err("does not match any format for date component".into())
1224}
1225
1226fn fill_pdt_time(
1235 pdt: &mut ParsedDateTime,
1236 actual: &mut VecDeque<TimeStrToken>,
1237) -> Result<(), String> {
1238 match determine_format_w_datetimefield(actual.clone(), None)? {
1239 Some(TimePartFormat::SqlStandard(leading_field)) => {
1240 let expected = expected_dur_like_tokens(leading_field)?;
1241
1242 fill_pdt_from_tokens(pdt, actual, expected, leading_field, 1)
1243 }
1244 _ => Ok(()),
1245 }
1246}
1247
1248fn fill_pdt_interval_sql(
1259 actual: &mut VecDeque<TimeStrToken>,
1260 leading_field: DateTimeField,
1261 pdt: &mut ParsedDateTime,
1262) -> Result<(), String> {
1263 use DateTimeField::*;
1264
1265 match leading_field {
1267 Year | Month => {
1268 if pdt.year.is_some() || pdt.month.is_some() {
1269 return Err("YEAR or MONTH field set twice".into());
1270 }
1271 }
1272 Day => {
1273 if pdt.day.is_some() {
1274 return Err("DAY field set twice".into());
1275 }
1276 }
1277 Hour | Minute | Second => {
1278 if pdt.hour.is_some() || pdt.minute.is_some() || pdt.second.is_some() {
1279 return Err("HOUR, MINUTE, SECOND field set twice".into());
1280 }
1281 }
1282 Millennium | Century | Decade | Milliseconds | Microseconds => {
1283 return Err(format!(
1284 "Cannot specify {} field for SQL standard-style interval parts",
1285 leading_field
1286 ));
1287 }
1288 }
1289
1290 let expected = expected_sql_standard_interval_tokens(leading_field);
1291
1292 let sign = trim_and_return_sign(actual);
1293
1294 fill_pdt_from_tokens(pdt, actual, expected, leading_field, sign)?;
1295
1296 match leading_field {
1300 Year | Month => {
1301 if pdt.year.is_none() {
1302 pdt.year = Some(DateTimeFieldValue::default());
1303 }
1304 if pdt.month.is_none() {
1305 pdt.month = Some(DateTimeFieldValue::default());
1306 }
1307 }
1308 Day => {
1309 if pdt.day.is_none() {
1310 pdt.day = Some(DateTimeFieldValue::default());
1311 }
1312 }
1313 Hour | Minute | Second => {
1314 if pdt.hour.is_none() {
1315 pdt.hour = Some(DateTimeFieldValue::default());
1316 }
1317 if pdt.minute.is_none() {
1318 pdt.minute = Some(DateTimeFieldValue::default());
1319 }
1320 if pdt.second.is_none() {
1321 pdt.second = Some(DateTimeFieldValue::default());
1322 }
1323 }
1324 Millennium | Century | Decade | Milliseconds | Microseconds => {
1325 return Err(format!(
1326 "Cannot specify {} field for SQL standard-style interval parts",
1327 leading_field
1328 ));
1329 }
1330 }
1331
1332 Ok(())
1333}
1334
1335fn fill_pdt_interval_pg(
1346 actual: &mut VecDeque<TimeStrToken>,
1347 time_unit: DateTimeField,
1348 pdt: &mut ParsedDateTime,
1349) -> Result<(), String> {
1350 use TimeStrToken::*;
1351
1352 let expected = [Num(0, 1), Dot, Nanos(0), TimeUnit(DateTimeField::Year)];
1356
1357 let sign = trim_and_return_sign(actual);
1358
1359 fill_pdt_from_tokens(pdt, actual, &expected, time_unit, sign)?;
1360
1361 Ok(())
1362}
1363
1364fn fill_pdt_from_tokens<'a, E: IntoIterator<Item = &'a TimeStrToken>>(
1375 pdt: &mut ParsedDateTime,
1376 actual: &mut VecDeque<TimeStrToken>,
1377 expected: E,
1378 leading_field: DateTimeField,
1379 sign: i64,
1380) -> Result<(), String> {
1381 use TimeStrToken::*;
1382 let mut current_field = leading_field;
1383
1384 let mut i = 0u8;
1385
1386 let mut unit_buf: Option<DateTimeFieldValue> = None;
1387
1388 let mut expected = expected.into_iter().peekable();
1389
1390 while let (Some(atok), Some(etok)) = (actual.front(), expected.peek()) {
1391 match (atok, etok) {
1392 (Dash, Dash) | (Colon, Colon) => {
1395 pdt.write_field_iff_none(current_field, unit_buf)?;
1396 unit_buf = None;
1397 current_field = current_field.next_smallest();
1398 }
1399 (Delim, Delim) => {
1400 pdt.write_field_iff_none(current_field, unit_buf)?;
1401 unit_buf = None;
1402 current_field = current_field.next_smallest();
1403
1404 actual.pop_front();
1408 expected.next();
1409 i += 1;
1410
1411 while let Some(Delim) = actual.front() {
1412 actual.pop_front();
1413 }
1414
1415 continue;
1416 }
1417 (TimeUnit(f), TimeUnit(_)) => {
1418 if unit_buf.is_some() && *f != current_field {
1419 return Err(format!(
1420 "Invalid syntax at offset {}: provided TimeUnit({}) but expected TimeUnit({})",
1421 i, f, current_field
1422 ));
1423 }
1424 }
1425 (DateTimeUnit(u), TimeUnit(_)) => {
1427 let f = match u {
1428 DateTimeUnits::Hour => DateTimeField::Hour,
1429 DateTimeUnits::Minute => DateTimeField::Minute,
1430 DateTimeUnits::Second => DateTimeField::Second,
1431 DateTimeUnits::Milliseconds => DateTimeField::Milliseconds,
1432 DateTimeUnits::Microseconds => DateTimeField::Microseconds,
1433 _ => return Err(format!("unsupported unit {}", u)),
1434 };
1435 if unit_buf.is_some() && f != current_field {
1436 return Err(format!(
1437 "Invalid syntax at offset {}: provided DateTimeUnit({}) but expected TimeUnit({})",
1438 u, f, current_field
1439 ));
1440 }
1441 }
1442 (Dot, Dot) => {}
1443 (Num(val, _), Num(_, _)) => match unit_buf {
1444 Some(_) => {
1445 return Err(
1446 "Invalid syntax; parts must be separated by '-', ':', or ' '".to_string(),
1447 );
1448 }
1449 None => {
1450 let unit = i64::try_from(i128::from(*val) * i128::from(sign))
1452 .map_err(|_| format!("Unable to parse value {val} as a number: number too large to fit in target type"))?;
1453 unit_buf = Some(DateTimeFieldValue { unit, fraction: 0 });
1454 }
1455 },
1456 (Nanos(val), Nanos(_)) => match unit_buf {
1457 Some(ref mut u) => {
1458 u.fraction = *val * sign;
1459 }
1460 None => {
1461 unit_buf = Some(DateTimeFieldValue {
1462 unit: 0,
1463 fraction: *val * sign,
1464 });
1465 }
1466 },
1467 (Num(n, _), Nanos(_)) => {
1468 let mut nc = *n;
1470
1471 let mut width = 0;
1472 while nc != 0 {
1474 nc /= 10;
1475 width += 1;
1476 }
1477
1478 let mut n = *n;
1479
1480 let precision = 9;
1482
1483 if width > precision {
1484 n /= 10_u64.pow(width - precision);
1486 } else {
1487 n *= 10_u64.pow(precision - width);
1489 }
1490
1491 let sn = i64::try_from(i128::from(n) * i128::from(sign))
1493 .map_err(|_| format!("Unable to parse value {n} as a number: number too large to fit in target type"))?;
1494
1495 match unit_buf {
1496 Some(ref mut u) => {
1497 u.fraction = sn;
1498 }
1499 None => {
1500 unit_buf = Some(DateTimeFieldValue {
1501 unit: 0,
1502 fraction: sn,
1503 });
1504 }
1505 }
1506 }
1507 (_, Num(_, _)) | (_, Dot) | (_, Nanos(_)) | (_, Delim) => {
1509 expected.next();
1510 continue;
1511 }
1512 (provided, expected) => {
1513 return Err(format!(
1514 "Invalid syntax at offset {i}: provided {provided:?} but expected {expected:?}",
1515 ));
1516 }
1517 }
1518 i += 1;
1519 actual.pop_front();
1520 expected.next();
1521 }
1522
1523 ltrim_delim_or_colon(actual);
1524
1525 pdt.write_field_iff_none(current_field, unit_buf)?;
1526
1527 Ok(())
1528}
1529
1530#[derive(Debug, Eq, PartialEq, Clone)]
1537enum TimePartFormat {
1538 SqlStandard(DateTimeField),
1539 PostgreSql(DateTimeField),
1540}
1541
1542#[derive(Debug, Eq, PartialEq, Clone)]
1545struct AnnotatedIntervalPart {
1546 pub tokens: VecDeque<TimeStrToken>,
1547 pub fmt: TimePartFormat,
1548}
1549
1550fn determine_format_w_datetimefield(
1557 mut toks: VecDeque<TimeStrToken>,
1558 leading_time_precision: Option<DateTimeField>,
1559) -> Result<Option<TimePartFormat>, String> {
1560 use DateTimeField::*;
1561 use TimePartFormat::*;
1562 use TimeStrToken::*;
1563
1564 trim_and_return_sign(&mut toks);
1565
1566 if let Some(Num(_, _)) = toks.front() {
1567 toks.pop_front();
1568 }
1569
1570 match toks.pop_front() {
1571 None | Some(Delim) => Ok(None),
1573 Some(Dot) => {
1574 match toks.front() {
1575 Some(Num(_, _)) | Some(Nanos(_)) => {
1576 toks.pop_front();
1577 }
1578 _ => {}
1579 }
1580 match toks.pop_front() {
1581 Some(TimeUnit(f)) => Ok(Some(PostgreSql(f))),
1583 _ => Ok(None),
1585 }
1586 }
1587 Some(Dash) => Ok(Some(SqlStandard(Year))),
1589 Some(Colon) => {
1591 if let Some(Num(_, _)) = toks.front() {
1592 toks.pop_front();
1593 }
1594
1595 match toks.pop_front() {
1596 Some(Colon) | Some(Delim) => Ok(Some(SqlStandard(Hour))),
1598 Some(Dot) => Ok(Some(SqlStandard(Minute))),
1600 None => Ok(leading_time_precision
1603 .map(SqlStandard)
1604 .or(Some(SqlStandard(Hour)))),
1605 _ => Err("Cannot determine format of all parts".into()),
1606 }
1607 }
1608 Some(TimeUnit(f)) => Ok(Some(PostgreSql(f))),
1610 Some(DateTimeUnit(DateTimeUnits::Hour)) => Ok(Some(PostgreSql(Hour))),
1611 Some(DateTimeUnit(DateTimeUnits::Minute)) => Ok(Some(PostgreSql(Minute))),
1612 Some(DateTimeUnit(DateTimeUnits::Second)) => Ok(Some(PostgreSql(Second))),
1613 Some(DateTimeUnit(DateTimeUnits::Milliseconds)) => Ok(Some(PostgreSql(Milliseconds))),
1614 Some(DateTimeUnit(DateTimeUnits::Microseconds)) => Ok(Some(PostgreSql(Microseconds))),
1615 Some(DateTimeUnit(_)) => Ok(None),
1616 _ => Err("Cannot determine format of all parts".into()),
1617 }
1618}
1619
1620fn expected_dur_like_tokens(from: DateTimeField) -> Result<&'static [TimeStrToken], String> {
1627 use DateTimeField::*;
1628 use TimeStrToken::*;
1629
1630 const ALL_TOKS: [TimeStrToken; 7] = [
1631 Num(0, 1), Colon,
1633 Num(0, 1), Colon,
1635 Num(0, 1), Dot,
1637 Nanos(0), ];
1639 let start = match from {
1640 Hour => 0,
1641 Minute => 2,
1642 Second => 4,
1643 _ => {
1644 return Err(format!(
1645 "expected_dur_like_tokens can only be called with HOUR, MINUTE, SECOND; got {}",
1646 from
1647 ));
1648 }
1649 };
1650
1651 Ok(&ALL_TOKS[start..ALL_TOKS.len()])
1652}
1653
1654fn expected_sql_standard_interval_tokens(from: DateTimeField) -> &'static [TimeStrToken] {
1659 use DateTimeField::*;
1660 use TimeStrToken::*;
1661
1662 const ALL_TOKS: [TimeStrToken; 6] = [
1663 Num(0, 1), Dash,
1665 Num(0, 1), Delim,
1667 Num(0, 1), Delim,
1669 ];
1670
1671 let (start, end) = match from {
1672 Year => (0, 4),
1673 Month => (2, 4),
1674 Day => (4, 6),
1675 _ => {
1676 return expected_dur_like_tokens(from)
1677 .expect("input to expected_dur_like_tokens shown to be valid");
1678 }
1679 };
1680
1681 &ALL_TOKS[start..end]
1682}
1683
1684fn trim_and_return_sign(z: &mut VecDeque<TimeStrToken>) -> i64 {
1685 use TimeStrToken::*;
1686
1687 match z.front() {
1688 Some(Dash) => {
1689 z.pop_front();
1690 -1
1691 }
1692 Some(Plus) => {
1693 z.pop_front();
1694 1
1695 }
1696 _ => 1,
1697 }
1698}
1699
1700fn ltrim_delim_or_colon(z: &mut VecDeque<TimeStrToken>) {
1703 while Some(&TimeStrToken::Colon) == z.front() || Some(&TimeStrToken::Delim) == z.front() {
1704 z.pop_front();
1705 }
1706}
1707
1708#[derive(Debug, Clone, PartialEq, Eq)]
1711pub(crate) enum TimeStrToken {
1712 Dash,
1713 Colon,
1714 Dot,
1715 Plus,
1716 Num(u64, usize),
1718 Nanos(i64),
1719 TimeUnit(DateTimeField),
1721 DateTimeUnit(DateTimeUnits),
1723 DateTimeDelimiter,
1725 Delim,
1728}
1729
1730impl std::fmt::Display for TimeStrToken {
1731 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1732 use TimeStrToken::*;
1733 match self {
1734 Dash => write!(f, "-"),
1735 Colon => write!(f, ":"),
1736 Dot => write!(f, "."),
1737 Plus => write!(f, "+"),
1738 Num(i, digits) => write!(f, "{:01$}", i, digits - 1),
1739 Nanos(i) => write!(f, "{}", i),
1740 TimeUnit(d) => write!(f, "{:?}", d),
1741 DateTimeUnit(u) => write!(f, "{}", u),
1742 DateTimeDelimiter => write!(f, "T"),
1743 Delim => write!(f, " "),
1744 }
1745 }
1746}
1747
1748pub(crate) fn tokenize_time_str(value: &str) -> Result<VecDeque<TimeStrToken>, String> {
1760 let mut toks = VecDeque::new();
1761 let mut num_buf = String::with_capacity(4);
1762 let mut char_buf = String::with_capacity(7);
1763 fn parse_num(n: &str, idx: usize) -> Result<TimeStrToken, String> {
1764 Ok(TimeStrToken::Num(
1765 n.parse().map_err(|e| {
1766 format!("Unable to parse value as a number at index {}: {}", idx, e)
1767 })?,
1768 n.len(),
1769 ))
1770 }
1771 fn maybe_tokenize_num_buf(
1772 n: &mut String,
1773 i: usize,
1774 is_frac: &mut bool,
1775 t: &mut VecDeque<TimeStrToken>,
1776 ) -> Result<(), String> {
1777 if !n.is_empty() {
1778 if *is_frac {
1779 n.truncate(9);
1781 let len = u32::try_from(n.len()).expect("length known to fit in a u32");
1782 let raw: i64 = n
1783 .parse()
1784 .map_err(|e| format!("couldn't parse fraction {}: {}", n, e))?;
1785 let multiplicand = 1_000_000_000 / 10_i64.pow(len);
1786 t.push_back(TimeStrToken::Nanos(raw * multiplicand));
1787 n.clear();
1788 } else {
1789 t.push_back(parse_num(n, i)?);
1790 n.clear();
1791 }
1792 }
1793 *is_frac = false;
1794 Ok(())
1795 }
1796 fn maybe_tokenize_char_buf(
1797 c: &mut String,
1798 t: &mut VecDeque<TimeStrToken>,
1799 ) -> Result<(), String> {
1800 if !c.is_empty() {
1801 if c == "T" || c == "t" {
1803 t.push_back(TimeStrToken::DateTimeDelimiter);
1804 } else {
1805 match c.to_uppercase().parse() {
1806 Ok(u) => t.push_back(TimeStrToken::TimeUnit(u)),
1807 Err(_) => t.push_back(TimeStrToken::DateTimeUnit(c.parse()?)),
1808 }
1809 }
1810 c.clear();
1811 }
1812 Ok(())
1813 }
1814 let mut next_num_is_frac = false;
1815 for (i, chr) in value.chars().enumerate() {
1816 if !num_buf.is_empty() && !char_buf.is_empty() {
1817 return Err("Could not tokenize".into());
1818 }
1819 match chr {
1820 '+' => {
1821 maybe_tokenize_num_buf(&mut num_buf, i, &mut next_num_is_frac, &mut toks)?;
1822 maybe_tokenize_char_buf(&mut char_buf, &mut toks)?;
1823 toks.push_back(TimeStrToken::Plus);
1824 }
1825 '-' => {
1826 maybe_tokenize_num_buf(&mut num_buf, i, &mut next_num_is_frac, &mut toks)?;
1827 maybe_tokenize_char_buf(&mut char_buf, &mut toks)?;
1828 toks.push_back(TimeStrToken::Dash);
1829 }
1830 ':' => {
1831 maybe_tokenize_num_buf(&mut num_buf, i, &mut next_num_is_frac, &mut toks)?;
1832 maybe_tokenize_char_buf(&mut char_buf, &mut toks)?;
1833 toks.push_back(TimeStrToken::Colon);
1834 }
1835 '.' => {
1836 maybe_tokenize_num_buf(&mut num_buf, i, &mut next_num_is_frac, &mut toks)?;
1837 maybe_tokenize_char_buf(&mut char_buf, &mut toks)?;
1838 toks.push_back(TimeStrToken::Dot);
1839 next_num_is_frac = true;
1840 }
1841 chr if chr.is_digit(10) => {
1842 maybe_tokenize_char_buf(&mut char_buf, &mut toks)?;
1843 num_buf.push(chr);
1844 }
1845 chr if chr.is_ascii_alphabetic() => {
1846 maybe_tokenize_num_buf(&mut num_buf, i, &mut next_num_is_frac, &mut toks)?;
1847 char_buf.push(chr);
1848 }
1849 chr if chr.is_ascii_whitespace() || chr.is_ascii_punctuation() => {
1850 maybe_tokenize_num_buf(&mut num_buf, i, &mut next_num_is_frac, &mut toks)?;
1851 maybe_tokenize_char_buf(&mut char_buf, &mut toks)?;
1852 toks.push_back(TimeStrToken::Delim);
1853 }
1854 _ => {
1855 return Err(format!(
1856 "Invalid character at offset {} in {}: {:?}",
1857 i, value, chr
1858 ));
1859 }
1860 }
1861 }
1862
1863 maybe_tokenize_num_buf(&mut num_buf, value.len(), &mut next_num_is_frac, &mut toks)?;
1864 maybe_tokenize_char_buf(&mut char_buf, &mut toks)?;
1865
1866 ltrim_delim_or_colon(&mut toks);
1867
1868 Ok(toks)
1869}
1870
1871#[derive(Debug, PartialEq, Eq)]
1872pub enum CalendarEra {
1873 BC,
1874 AD,
1875}
1876
1877impl CalendarEra {
1878 fn as_str(&self) -> &'static str {
1879 match self {
1880 CalendarEra::BC => "BC",
1881 CalendarEra::AD => "AD",
1882 }
1883 }
1884}
1885
1886pub(crate) fn split_timestamp_string(value: &str) -> (&str, &str, CalendarEra) {
1890 let cut = value.find(" +").or_else(|| value.find(" -"));
1894
1895 if let Some(cut) = cut {
1896 let (datetime, timezone) = value.split_at(cut);
1897
1898 let (timezone, era) = strip_era_from_timezone(timezone);
1899
1900 return (datetime.trim(), timezone.trim(), era);
1901 }
1902
1903 let colon = value.find(':');
1906
1907 if let Some(colon) = colon {
1908 let substring = value.get(colon..);
1909 if let Some(substring) = substring {
1910 let tz = substring
1911 .find(|c: char| (c == '-') || (c == '+') || (c == ' ') || c.is_ascii_alphabetic());
1912
1913 if let Some(tz) = tz {
1914 let (datetime, timezone) = value.split_at(colon + tz);
1915
1916 let (timezone, era) = strip_era_from_timezone(timezone);
1917
1918 return (datetime.trim(), timezone.trim(), era);
1919 }
1920 }
1921
1922 (value.trim(), "", CalendarEra::AD)
1923 } else {
1924 let cut = value.find(|c: char| c.is_ascii_alphabetic());
1928
1929 if let Some(cut) = cut {
1930 let (datetime, timezone) = value.split_at(cut);
1931
1932 let (timezone, era) = strip_era_from_timezone(timezone);
1933
1934 return (datetime.trim(), timezone.trim(), era);
1935 }
1936
1937 (value.trim(), "", CalendarEra::AD)
1938 }
1939}
1940
1941fn strip_era_from_timezone(timezone: &str) -> (&str, CalendarEra) {
1942 use CalendarEra::{AD, BC};
1943 let timezone = timezone.trim();
1944 let timezone_upper = timezone.to_uppercase();
1945
1946 match (
1947 timezone_upper.strip_suffix(BC.as_str()),
1948 timezone_upper.strip_suffix(AD.as_str()),
1949 ) {
1950 (Some(remainder), None) => (&timezone[..remainder.len()], BC),
1951 (None, Some(remainder)) => (&timezone[..remainder.len()], AD),
1952 _ => (timezone, AD),
1953 }
1954}
1955
1956#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
1961pub struct PackedNaiveTime([u8; Self::SIZE]);
1962
1963impl FixedSizeCodec<NaiveTime> for PackedNaiveTime {
1964 const SIZE: usize = 8;
1965
1966 fn as_bytes(&self) -> &[u8] {
1967 &self.0
1968 }
1969
1970 fn from_bytes(slice: &[u8]) -> Result<Self, String> {
1971 let buf: [u8; Self::SIZE] = slice.try_into().map_err(|_| {
1972 format!(
1973 "size for PackedNaiveTime is {} bytes, got {}",
1974 Self::SIZE,
1975 slice.len()
1976 )
1977 })?;
1978 Ok(PackedNaiveTime(buf))
1979 }
1980
1981 #[inline]
1982 fn from_value(value: NaiveTime) -> Self {
1983 let secs = value.num_seconds_from_midnight();
1984 let nano = value.nanosecond();
1985
1986 let mut buf = [0u8; Self::SIZE];
1987
1988 (buf[..4]).copy_from_slice(&secs.to_be_bytes());
1989 (buf[4..]).copy_from_slice(&nano.to_be_bytes());
1990
1991 PackedNaiveTime(buf)
1992 }
1993
1994 #[inline]
1995 fn into_value(self) -> NaiveTime {
1996 let mut secs = [0u8; 4];
1997 secs.copy_from_slice(&self.0[..4]);
1998 let secs = u32::from_be_bytes(secs);
1999
2000 let mut nano = [0u8; 4];
2001 nano.copy_from_slice(&self.0[4..]);
2002 let nano = u32::from_be_bytes(nano);
2003
2004 NaiveTime::from_num_seconds_from_midnight_opt(secs, nano)
2005 .expect("NaiveTime roundtrips with PackedNaiveTime")
2006 }
2007}
2008
2009#[cfg(test)]
2010mod tests {
2011 use mz_ore::assert_ok;
2012 use mz_proto::protobuf_roundtrip;
2013 use proptest::prelude::any;
2014 use proptest::{prop_assert_eq, proptest};
2015
2016 use crate::scalar::add_arb_duration;
2017
2018 use super::*;
2019
2020 #[mz_ore::test]
2021 fn iterate_datetimefield() {
2022 use DateTimeField::*;
2023 assert_eq!(
2024 Millennium.into_iter().take(10).collect::<Vec<_>>(),
2025 vec![
2026 Century,
2027 Decade,
2028 Year,
2029 Month,
2030 Day,
2031 Hour,
2032 Minute,
2033 Second,
2034 Milliseconds,
2035 Microseconds
2036 ]
2037 )
2038 }
2039
2040 #[mz_ore::test]
2041 fn test_expected_dur_like_tokens() {
2042 use DateTimeField::*;
2043 use TimeStrToken::*;
2044 assert_eq!(
2045 expected_sql_standard_interval_tokens(Hour),
2046 vec![Num(0, 1), Colon, Num(0, 1), Colon, Num(0, 1), Dot, Nanos(0)]
2047 );
2048 assert_eq!(
2049 expected_sql_standard_interval_tokens(Minute),
2050 vec![Num(0, 1), Colon, Num(0, 1), Dot, Nanos(0)]
2051 );
2052 assert_eq!(
2053 expected_sql_standard_interval_tokens(Second),
2054 vec![Num(0, 1), Dot, Nanos(0)]
2055 );
2056 }
2057
2058 #[mz_ore::test]
2059 fn test_expected_sql_standard_interval_tokens() {
2060 use DateTimeField::*;
2061 use TimeStrToken::*;
2062 assert_eq!(
2063 expected_sql_standard_interval_tokens(Year),
2064 vec![Num(0, 1), Dash, Num(0, 1), Delim]
2065 );
2066
2067 assert_eq!(
2068 expected_sql_standard_interval_tokens(Day),
2069 vec![Num(0, 1), Delim]
2070 );
2071 assert_eq!(
2072 expected_sql_standard_interval_tokens(Hour),
2073 vec![Num(0, 1), Colon, Num(0, 1), Colon, Num(0, 1), Dot, Nanos(0)]
2074 );
2075 }
2076 #[mz_ore::test]
2077 fn test_trim_and_return_sign() {
2078 let test_cases = [
2079 ("-2", -1, "2"),
2080 ("3", 1, "3"),
2081 ("+5", 1, "5"),
2082 ("-", -1, ""),
2083 ("-YEAR", -1, "YEAR"),
2084 ("YEAR", 1, "YEAR"),
2085 ];
2086
2087 for test in test_cases.iter() {
2088 let mut s = tokenize_time_str(test.0).unwrap();
2089
2090 assert_eq!(trim_and_return_sign(&mut s), test.1);
2091 assert_eq!(s.front(), tokenize_time_str(test.2).unwrap().front());
2092 }
2093 }
2094 #[mz_ore::test]
2095 fn test_determine_format_w_datetimefield() {
2096 use DateTimeField::*;
2097 use TimePartFormat::*;
2098
2099 let test_cases = [
2100 ("1-2 3", Some(SqlStandard(Year))),
2101 ("4:5", Some(SqlStandard(Hour))),
2102 ("4:5.6", Some(SqlStandard(Minute))),
2103 ("-4:5.6", Some(SqlStandard(Minute))),
2104 ("+4:5.6", Some(SqlStandard(Minute))),
2105 ("year", Some(PostgreSql(Year))),
2106 ("4year", Some(PostgreSql(Year))),
2107 ("-4year", Some(PostgreSql(Year))),
2108 ("5", None),
2109 ("5.6", None),
2110 ("3 4:5:6.7", None),
2111 ];
2112
2113 for test in test_cases.iter() {
2114 let s = tokenize_time_str(test.0).unwrap();
2115
2116 match (
2117 determine_format_w_datetimefield(s, None).unwrap(),
2118 test.1.as_ref(),
2119 ) {
2120 (Some(a), Some(b)) => {
2121 if a != *b {
2122 panic!(
2123 "determine_format_w_datetimefield_and_time returned {:?}, expected {:?}",
2124 a, b,
2125 )
2126 }
2127 }
2128 (None, None) => {}
2129 (x, y) => panic!(
2130 "determine_format_w_datetimefield_and_time returned {:?}, expected {:?}",
2131 x, y,
2132 ),
2133 }
2134 }
2135 }
2136 #[mz_ore::test]
2137 fn test_determine_format_w_datetimefield_and_leading_time() {
2138 use DateTimeField::*;
2139 use TimePartFormat::*;
2140
2141 assert_eq!(
2142 determine_format_w_datetimefield(tokenize_time_str("4:5").unwrap(), None,).unwrap(),
2143 Some(SqlStandard(Hour))
2144 );
2145 assert_eq!(
2146 determine_format_w_datetimefield(
2147 tokenize_time_str("4:5").unwrap(),
2148 Some(DateTimeField::Minute),
2149 )
2150 .unwrap(),
2151 Some(SqlStandard(Minute))
2152 );
2153 assert_eq!(
2154 determine_format_w_datetimefield(
2155 tokenize_time_str("4:5").unwrap(),
2156 Some(DateTimeField::Hour),
2157 )
2158 .unwrap(),
2159 Some(SqlStandard(Hour))
2160 );
2161 }
2162 #[mz_ore::test]
2163 fn test_determine_format_w_datetimefield_error() {
2164 let test_cases = [
2165 ("1+2", "Cannot determine format of all parts"),
2166 ("1:2+3", "Cannot determine format of all parts"),
2167 ("1:1YEAR2", "Cannot determine format of all parts"),
2168 ];
2169
2170 for test in test_cases.iter() {
2171 let s = tokenize_time_str(test.0).unwrap();
2172 match determine_format_w_datetimefield(s, None) {
2173 Err(e) => assert_eq!(e.to_string(), test.1),
2174 Ok(f) => panic!(
2175 "Test passed when expected to fail: {}, generated {:?}",
2176 test.0, f
2177 ),
2178 };
2179 }
2180 }
2181
2182 #[mz_ore::test]
2183 fn test_fill_pdt_from_tokens() {
2184 use DateTimeField::*;
2185 let test_cases = [
2186 (
2187 ParsedDateTime {
2188 year: Some(DateTimeFieldValue::new(1, 0)),
2189 month: Some(DateTimeFieldValue::new(2, 0)),
2190 day: Some(DateTimeFieldValue::new(3, 0)),
2191 hour: Some(DateTimeFieldValue::new(4, 0)),
2192 minute: Some(DateTimeFieldValue::new(5, 0)),
2193 second: Some(DateTimeFieldValue::new(6, 0)),
2194 ..Default::default()
2195 },
2196 "1 2 3 4 5 6",
2197 "0 0 0 0 0 0",
2198 Year,
2199 1,
2200 ),
2201 (
2202 ParsedDateTime {
2203 day: Some(DateTimeFieldValue::new(4, 0)),
2204 hour: Some(DateTimeFieldValue::new(5, 0)),
2205 minute: Some(DateTimeFieldValue::new(6, 0)),
2206 ..Default::default()
2207 },
2208 "4 5 6",
2209 "0 0 0",
2210 Day,
2211 1,
2212 ),
2213 (
2214 ParsedDateTime {
2215 day: Some(DateTimeFieldValue::new(-4, 0)),
2216 hour: Some(DateTimeFieldValue::new(-5, 0)),
2217 minute: Some(DateTimeFieldValue::new(-6, 0)),
2218 ..Default::default()
2219 },
2220 "4 5 6",
2221 "0 0 0",
2222 Day,
2223 -1,
2224 ),
2225 (
2227 ParsedDateTime {
2228 year: Some(DateTimeFieldValue::new(1, 0)),
2229 month: Some(DateTimeFieldValue::new(2, 0)),
2230 day: Some(DateTimeFieldValue::new(3, 0)),
2231 hour: Some(DateTimeFieldValue::new(4, 0)),
2232 minute: Some(DateTimeFieldValue::new(5, 0)),
2233 second: Some(DateTimeFieldValue::new(6, 0)),
2234 ..Default::default()
2235 },
2236 "1-2:3-4 5 6",
2237 "0-0:0-0 0 0",
2238 Year,
2239 1,
2240 ),
2241 (
2243 ParsedDateTime {
2244 year: Some(DateTimeFieldValue::new(1, 0)),
2245 month: Some(DateTimeFieldValue::new(2, 0)),
2246 day: Some(DateTimeFieldValue::new(3, 0)),
2247 hour: Some(DateTimeFieldValue::new(5, 0)),
2248 minute: Some(DateTimeFieldValue::new(6, 0)),
2249 ..Default::default()
2250 },
2251 "1 2 3 5 6",
2252 "0 0 0 0 0 0",
2253 Year,
2254 1,
2255 ),
2256 (
2258 ParsedDateTime {
2259 year: Some(DateTimeFieldValue::new(1, 0)),
2260 month: Some(DateTimeFieldValue::new(2, 0)),
2261 day: Some(DateTimeFieldValue::new(3, 0)),
2262 minute: Some(DateTimeFieldValue::new(5, 0)),
2263 second: Some(DateTimeFieldValue::new(6, 0)),
2264 ..Default::default()
2265 },
2266 "1-2:3- 5 6",
2267 "0-0:0-0 0 0",
2268 Year,
2269 1,
2270 ),
2271 (
2273 ParsedDateTime {
2274 year: Some(DateTimeFieldValue::new(1, 0)),
2275 month: Some(DateTimeFieldValue::new(2, 0)),
2276 day: Some(DateTimeFieldValue::new(3, 0)),
2277 hour: Some(DateTimeFieldValue::new(4, 0)),
2278 minute: Some(DateTimeFieldValue::new(5, 0)),
2279 second: Some(DateTimeFieldValue::new(6, 700_000_000)),
2280 ..Default::default()
2281 },
2282 "1-2:3-4 5 6.7",
2283 "0-0:0-0 0 0.0",
2284 Year,
2285 1,
2286 ),
2287 (
2289 ParsedDateTime {
2290 year: Some(DateTimeFieldValue::new(1, 200_000_000)),
2291 ..Default::default()
2292 },
2293 "1.2",
2294 "0.0",
2295 Year,
2296 1,
2297 ),
2298 (
2299 ParsedDateTime {
2300 minute: Some(DateTimeFieldValue::new(1, 200_000_000)),
2301 ..Default::default()
2302 },
2303 "1.2",
2304 "0.0",
2305 Minute,
2306 1,
2307 ),
2308 (
2310 ParsedDateTime {
2311 month: Some(DateTimeFieldValue::new(3, 0)),
2312 ..Default::default()
2313 },
2314 "3MONTHS",
2315 "0YEAR",
2316 Month,
2317 1,
2318 ),
2319 (
2320 ParsedDateTime {
2321 month: Some(DateTimeFieldValue::new(1, 0)),
2322 day: Some(DateTimeFieldValue::new(2, 0)),
2323 hour: Some(DateTimeFieldValue::new(3, 0)),
2324 ..Default::default()
2325 },
2326 "1MONTHS 2DAYS 3HOURS",
2327 "0YEAR 0YEAR 0YEAR",
2328 Month,
2329 1,
2330 ),
2331 (
2332 ParsedDateTime {
2333 month: Some(DateTimeFieldValue::new(1, 0)),
2334 day: Some(DateTimeFieldValue::new(2, 0)),
2335 ..Default::default()
2336 },
2337 "1MONTHS-2",
2338 "0YEAR-0",
2339 Month,
2340 1,
2341 ),
2342 ];
2343 for test in test_cases.iter() {
2344 let mut pdt = ParsedDateTime::default();
2345 let mut actual = tokenize_time_str(test.1).unwrap();
2346 let expected = tokenize_time_str(test.2).unwrap();
2347
2348 fill_pdt_from_tokens(&mut pdt, &mut actual, &expected, test.3, test.4).unwrap();
2349
2350 assert_eq!(pdt, test.0);
2351 }
2352 }
2353
2354 #[mz_ore::test]
2355 fn test_fill_pdt_from_tokens_errors() {
2356 use DateTimeField::*;
2357 let test_cases = [
2358 (
2360 "1 2 3",
2361 "0-0 0",
2362 Year,
2363 1,
2364 "Invalid syntax at offset 1: provided Delim but expected Dash",
2365 ),
2366 ];
2367 for test in test_cases.iter() {
2368 let mut pdt = ParsedDateTime::default();
2369 let mut actual = tokenize_time_str(test.0).unwrap();
2370 let expected = tokenize_time_str(test.1).unwrap();
2371
2372 match fill_pdt_from_tokens(&mut pdt, &mut actual, &expected, test.2, test.3) {
2373 Err(e) => assert_eq!(e.to_string(), test.4),
2374 Ok(_) => panic!("Test passed when expected to fail, generated {:?}", pdt),
2375 };
2376 }
2377 }
2378 #[mz_ore::test]
2379 #[should_panic(expected = "Cannot get smaller DateTimeField than MICROSECONDS")]
2380 fn test_fill_pdt_from_tokens_panic() {
2381 use DateTimeField::*;
2382 let test_cases = [
2383 ("1 2", "0 0", Microseconds, 1),
2385 ];
2386 for test in test_cases.iter() {
2387 let mut pdt = ParsedDateTime::default();
2388 let mut actual = tokenize_time_str(test.0).unwrap();
2389 let expected = tokenize_time_str(test.1).unwrap();
2390
2391 if fill_pdt_from_tokens(&mut pdt, &mut actual, &expected, test.2, test.3).is_ok() {
2392 panic!(
2393 "test_fill_pdt_from_tokens_panic should have panicked. input {}\nformat {}\
2394 \nDateTimeField {}\nGenerated ParsedDateTime {:?}",
2395 test.0, test.1, test.2, pdt
2396 );
2397 };
2398 }
2399 }
2400
2401 #[mz_ore::test]
2402 fn test_fill_pdt_interval_pg() {
2403 use DateTimeField::*;
2404 let test_cases = [
2405 (
2406 ParsedDateTime {
2407 year: Some(DateTimeFieldValue::new(2, 0)),
2408 ..Default::default()
2409 },
2410 "2",
2411 Year,
2412 ),
2413 (
2414 ParsedDateTime {
2415 month: Some(DateTimeFieldValue::new(2, 300_000_000)),
2416 ..Default::default()
2417 },
2418 "2.3",
2419 Month,
2420 ),
2421 (
2422 ParsedDateTime {
2423 day: Some(DateTimeFieldValue::new(-2, -300_000_000)),
2424 ..Default::default()
2425 },
2426 "-2.3",
2427 Day,
2428 ),
2429 (
2430 ParsedDateTime {
2431 hour: Some(DateTimeFieldValue::new(2, 0)),
2432 ..Default::default()
2433 },
2434 "2",
2435 Hour,
2436 ),
2437 (
2438 ParsedDateTime {
2439 minute: Some(DateTimeFieldValue::new(2, 300_000_000)),
2440 ..Default::default()
2441 },
2442 "2.3",
2443 Minute,
2444 ),
2445 (
2446 ParsedDateTime {
2447 second: Some(DateTimeFieldValue::new(-2, -300_000_000)),
2448 ..Default::default()
2449 },
2450 "-2.3",
2451 Second,
2452 ),
2453 (
2454 ParsedDateTime {
2455 year: Some(DateTimeFieldValue::new(2, 0)),
2456 ..Default::default()
2457 },
2458 "2year",
2459 Year,
2460 ),
2461 (
2462 ParsedDateTime {
2463 month: Some(DateTimeFieldValue::new(2, 300_000_000)),
2464 ..Default::default()
2465 },
2466 "2.3month",
2467 Month,
2468 ),
2469 (
2470 ParsedDateTime {
2471 day: Some(DateTimeFieldValue::new(-2, -300_000_000)),
2472 ..Default::default()
2473 },
2474 "-2.3day",
2475 Day,
2476 ),
2477 (
2478 ParsedDateTime {
2479 hour: Some(DateTimeFieldValue::new(2, 0)),
2480 ..Default::default()
2481 },
2482 "2hour",
2483 Hour,
2484 ),
2485 (
2486 ParsedDateTime {
2487 minute: Some(DateTimeFieldValue::new(2, 300_000_000)),
2488 ..Default::default()
2489 },
2490 "2.3minute",
2491 Minute,
2492 ),
2493 (
2494 ParsedDateTime {
2495 second: Some(DateTimeFieldValue::new(-2, -300_000_000)),
2496 ..Default::default()
2497 },
2498 "-2.3second",
2499 Second,
2500 ),
2501 (
2502 ParsedDateTime {
2503 second: Some(DateTimeFieldValue::new(-2, -300_000_000)),
2504 ..Default::default()
2505 },
2506 ":::::::::-2.3second",
2507 Second,
2508 ),
2509 (
2510 ParsedDateTime {
2511 second: Some(DateTimeFieldValue::new(2, 300_000_000)),
2512 ..Default::default()
2513 },
2514 ":::::::::+2.3second",
2515 Second,
2516 ),
2517 (
2518 ParsedDateTime {
2519 millisecond: Some(DateTimeFieldValue::new(1, 200_000_000)),
2520 ..Default::default()
2521 },
2522 "1.2milliseconds",
2523 Milliseconds,
2524 ),
2525 (
2526 ParsedDateTime {
2527 microsecond: Some(DateTimeFieldValue::new(2, 300_000_000)),
2528 ..Default::default()
2529 },
2530 "2.3microseconds",
2531 Microseconds,
2532 ),
2533 (
2534 ParsedDateTime {
2535 millennium: Some(DateTimeFieldValue::new(4, 500_000_000)),
2536 ..Default::default()
2537 },
2538 "4.5millennium",
2539 Millennium,
2540 ),
2541 (
2542 ParsedDateTime {
2543 century: Some(DateTimeFieldValue::new(6, 700_000_000)),
2544 ..Default::default()
2545 },
2546 "6.7century",
2547 Century,
2548 ),
2549 (
2550 ParsedDateTime {
2551 decade: Some(DateTimeFieldValue::new(8, 900_000_000)),
2552 ..Default::default()
2553 },
2554 "8.9decade",
2555 Decade,
2556 ),
2557 ];
2558 for test in test_cases.iter() {
2559 let mut pdt = ParsedDateTime::default();
2560 let mut actual = tokenize_time_str(test.1).unwrap();
2561 fill_pdt_interval_pg(&mut actual, test.2, &mut pdt).unwrap();
2562
2563 assert_eq!(pdt, test.0);
2564 }
2565 }
2566
2567 #[mz_ore::test]
2568 fn fill_pdt_interval_pg_errors() {
2569 use DateTimeField::*;
2570 let test_cases = [
2571 (
2573 "1.2.",
2574 Month,
2575 "Invalid syntax at offset 3: provided Dot but expected TimeUnit(Year)",
2576 ),
2577 (
2580 "1YEAR",
2581 Month,
2582 "Invalid syntax at offset 1: provided TimeUnit(YEAR) but expected TimeUnit(MONTH)",
2583 ),
2584 ];
2585 for test in test_cases.iter() {
2586 let mut pdt = ParsedDateTime::default();
2587 let mut actual = tokenize_time_str(test.0).unwrap();
2588 match fill_pdt_interval_pg(&mut actual, test.1, &mut pdt) {
2589 Err(e) => assert_eq!(e.to_string(), test.2),
2590 Ok(_) => panic!(
2591 "Test passed when expected to fail, generated {:?}, expected error {}",
2592 pdt, test.2,
2593 ),
2594 };
2595 }
2596 }
2597
2598 #[mz_ore::test]
2599 fn test_fill_pdt_interval_sql() {
2600 use DateTimeField::*;
2601 let test_cases = [
2602 (
2603 ParsedDateTime {
2604 year: Some(DateTimeFieldValue::new(1, 0)),
2605 month: Some(DateTimeFieldValue::new(2, 0)),
2606 ..Default::default()
2607 },
2608 "1-2",
2609 Year,
2610 ),
2611 (
2612 ParsedDateTime {
2613 hour: Some(DateTimeFieldValue::new(1, 0)),
2614 minute: Some(DateTimeFieldValue::new(2, 0)),
2615 second: Some(DateTimeFieldValue::new(3, 400_000_000)),
2616 ..Default::default()
2617 },
2618 "1:2:3.4",
2619 Hour,
2620 ),
2621 (
2622 ParsedDateTime {
2623 hour: Some(DateTimeFieldValue::new(1, 0)),
2624 minute: Some(DateTimeFieldValue::new(0, 0)),
2625 second: Some(DateTimeFieldValue::new(3, 400_000_000)),
2626 ..Default::default()
2627 },
2628 "1::3.4",
2629 Hour,
2630 ),
2631 (
2632 ParsedDateTime {
2633 hour: Some(DateTimeFieldValue::new(1, 0)),
2634 minute: Some(DateTimeFieldValue::new(0, 0)),
2635 second: Some(DateTimeFieldValue::new(0, 400_000_000)),
2636 ..Default::default()
2637 },
2638 "1::.4",
2639 Hour,
2640 ),
2641 (
2642 ParsedDateTime {
2643 hour: Some(DateTimeFieldValue::new(0, 0)),
2644 minute: Some(DateTimeFieldValue::new(0, 0)),
2645 second: Some(DateTimeFieldValue::new(0, 400_000_000)),
2646 ..Default::default()
2647 },
2648 ".4",
2649 Second,
2650 ),
2651 (
2652 ParsedDateTime {
2653 hour: Some(DateTimeFieldValue::new(0, 0)),
2654 minute: Some(DateTimeFieldValue::new(1, 0)),
2655 second: Some(DateTimeFieldValue::new(2, 300_000_000)),
2656 ..Default::default()
2657 },
2658 "1:2.3",
2659 Minute,
2660 ),
2661 (
2662 ParsedDateTime {
2663 year: Some(DateTimeFieldValue::new(-1, 0)),
2664 month: Some(DateTimeFieldValue::new(-2, 0)),
2665 ..Default::default()
2666 },
2667 "-1-2",
2668 Year,
2669 ),
2670 (
2671 ParsedDateTime {
2672 hour: Some(DateTimeFieldValue::new(-1, 0)),
2673 minute: Some(DateTimeFieldValue::new(-2, 0)),
2674 second: Some(DateTimeFieldValue::new(-3, -400_000_000)),
2675 ..Default::default()
2676 },
2677 "-1:2:3.4",
2678 Hour,
2679 ),
2680 (
2681 ParsedDateTime {
2682 year: Some(DateTimeFieldValue::new(1, 0)),
2683 month: Some(DateTimeFieldValue::new(2, 0)),
2684 ..Default::default()
2685 },
2686 "+1-2",
2687 Year,
2688 ),
2689 (
2690 ParsedDateTime {
2691 hour: Some(DateTimeFieldValue::new(1, 0)),
2692 minute: Some(DateTimeFieldValue::new(2, 0)),
2693 second: Some(DateTimeFieldValue::new(3, 400_000_000)),
2694 ..Default::default()
2695 },
2696 "+1:2:3.4",
2697 Hour,
2698 ),
2699 (
2700 ParsedDateTime {
2701 year: Some(DateTimeFieldValue::new(-1, 0)),
2702 month: Some(DateTimeFieldValue::new(-2, 0)),
2703 ..Default::default()
2704 },
2705 "::::::-1-2",
2706 Year,
2707 ),
2708 (
2709 ParsedDateTime {
2710 hour: Some(DateTimeFieldValue::new(-1, 0)),
2711 minute: Some(DateTimeFieldValue::new(-2, 0)),
2712 second: Some(DateTimeFieldValue::new(-3, -400_000_000)),
2713 ..Default::default()
2714 },
2715 ":::::::-1:2:3.4",
2716 Hour,
2717 ),
2718 ];
2719 for test in test_cases.iter() {
2720 let mut pdt = ParsedDateTime::default();
2721 let mut actual = tokenize_time_str(test.1).unwrap();
2722 fill_pdt_interval_sql(&mut actual, test.2, &mut pdt).unwrap();
2723
2724 assert_eq!(pdt, test.0);
2725 }
2726 }
2727
2728 #[mz_ore::test]
2729 fn test_fill_pdt_interval_sql_errors() {
2730 use DateTimeField::*;
2731 let test_cases = [
2732 (
2734 "1.2",
2735 Year,
2736 "Invalid syntax at offset 1: provided Dot but expected Dash",
2737 ),
2738 (
2739 "1-2:3.4",
2740 Minute,
2741 "Invalid syntax at offset 1: provided Dash but expected Colon",
2742 ),
2743 (
2744 "1YEAR",
2745 Year,
2746 "Invalid syntax at offset 1: provided TimeUnit(Year) but expected Dash",
2747 ),
2748 ];
2749 for test in test_cases.iter() {
2750 let mut pdt = ParsedDateTime::default();
2751 let mut actual = tokenize_time_str(test.0).unwrap();
2752 match fill_pdt_interval_sql(&mut actual, test.1, &mut pdt) {
2753 Err(e) => assert_eq!(e.to_string(), test.2),
2754 Ok(_) => panic!("Test passed when expected to fail, generated {:?}", pdt),
2755 };
2756 }
2757 }
2758
2759 #[mz_ore::test]
2760 fn test_build_parsed_datetime_time() {
2761 run_test_build_parsed_datetime_time(
2762 "3:4:5.6",
2763 ParsedDateTime {
2764 hour: Some(DateTimeFieldValue::new(3, 0)),
2765 minute: Some(DateTimeFieldValue::new(4, 0)),
2766 second: Some(DateTimeFieldValue::new(5, 600_000_000)),
2767 ..Default::default()
2768 },
2769 );
2770 run_test_build_parsed_datetime_time(
2771 "3:4",
2772 ParsedDateTime {
2773 hour: Some(DateTimeFieldValue::new(3, 0)),
2774 minute: Some(DateTimeFieldValue::new(4, 0)),
2775 ..Default::default()
2776 },
2777 );
2778 run_test_build_parsed_datetime_time(
2779 "3:4.5",
2780 ParsedDateTime {
2781 minute: Some(DateTimeFieldValue::new(3, 0)),
2782 second: Some(DateTimeFieldValue::new(4, 500_000_000)),
2783 ..Default::default()
2784 },
2785 );
2786 run_test_build_parsed_datetime_time(
2787 "0::4.5",
2788 ParsedDateTime {
2789 hour: Some(DateTimeFieldValue::new(0, 0)),
2790 second: Some(DateTimeFieldValue::new(4, 500_000_000)),
2791 ..Default::default()
2792 },
2793 );
2794 run_test_build_parsed_datetime_time(
2795 "0::.5",
2796 ParsedDateTime {
2797 hour: Some(DateTimeFieldValue::new(0, 0)),
2798 second: Some(DateTimeFieldValue::new(0, 500_000_000)),
2799 ..Default::default()
2800 },
2801 );
2802
2803 fn run_test_build_parsed_datetime_time(test: &str, res: ParsedDateTime) {
2804 assert_eq!(
2805 ParsedDateTime::build_parsed_datetime_time(test).unwrap(),
2806 res
2807 );
2808 }
2809 }
2810
2811 #[mz_ore::test]
2812 fn test_build_parsed_datetime_timestamp() {
2813 run_test_build_parsed_datetime_timestamp(
2814 "2000-01-02",
2815 ParsedDateTime {
2816 year: Some(DateTimeFieldValue::new(2000, 0)),
2817 month: Some(DateTimeFieldValue::new(1, 0)),
2818 day: Some(DateTimeFieldValue::new(2, 0)),
2819 ..Default::default()
2820 },
2821 );
2822 run_test_build_parsed_datetime_timestamp(
2823 "2000",
2824 ParsedDateTime {
2825 year: Some(DateTimeFieldValue::new(2000, 0)),
2826 ..Default::default()
2827 },
2828 );
2829 run_test_build_parsed_datetime_timestamp(
2830 "2000-1-",
2831 ParsedDateTime {
2832 year: Some(DateTimeFieldValue::new(2000, 0)),
2833 month: Some(DateTimeFieldValue::new(1, 0)),
2834 ..Default::default()
2835 },
2836 );
2837 run_test_build_parsed_datetime_timestamp(
2838 "2000-01-02 3:4:5.6",
2839 ParsedDateTime {
2840 year: Some(DateTimeFieldValue::new(2000, 0)),
2841 month: Some(DateTimeFieldValue::new(1, 0)),
2842 day: Some(DateTimeFieldValue::new(2, 0)),
2843 hour: Some(DateTimeFieldValue::new(3, 0)),
2844 minute: Some(DateTimeFieldValue::new(4, 0)),
2845 second: Some(DateTimeFieldValue::new(5, 600_000_000)),
2846 ..Default::default()
2847 },
2848 );
2849 run_test_build_parsed_datetime_timestamp(
2850 "2000-01-02T3:4:5.6",
2851 ParsedDateTime {
2852 year: Some(DateTimeFieldValue::new(2000, 0)),
2853 month: Some(DateTimeFieldValue::new(1, 0)),
2854 day: Some(DateTimeFieldValue::new(2, 0)),
2855 hour: Some(DateTimeFieldValue::new(3, 0)),
2856 minute: Some(DateTimeFieldValue::new(4, 0)),
2857 second: Some(DateTimeFieldValue::new(5, 600_000_000)),
2858 ..Default::default()
2859 },
2860 );
2861
2862 fn run_test_build_parsed_datetime_timestamp(test: &str, res: ParsedDateTime) {
2863 assert_eq!(
2864 ParsedDateTime::build_parsed_datetime_timestamp(test, CalendarEra::AD).unwrap(),
2865 res
2866 );
2867 }
2868 }
2869
2870 #[mz_ore::test]
2871 fn test_build_parsed_datetime_interval() {
2872 use DateTimeField::*;
2873 let test_cases = [
2874 (
2875 ParsedDateTime {
2876 year: Some(DateTimeFieldValue::new(1, 0)),
2877 month: Some(DateTimeFieldValue::new(2, 0)),
2878 day: Some(DateTimeFieldValue::new(3, 0)),
2879 hour: Some(DateTimeFieldValue::new(4, 0)),
2880 minute: Some(DateTimeFieldValue::new(5, 0)),
2881 second: Some(DateTimeFieldValue::new(6, 700_000_000)),
2882 ..Default::default()
2883 },
2884 "1-2 3 4:5:6.7",
2885 Second,
2886 ),
2887 (
2888 ParsedDateTime {
2889 year: Some(DateTimeFieldValue::new(1, 0)),
2890 month: Some(DateTimeFieldValue::new(2, 0)),
2891 day: Some(DateTimeFieldValue::new(3, 0)),
2892 hour: Some(DateTimeFieldValue::new(4, 0)),
2893 minute: Some(DateTimeFieldValue::new(5, 0)),
2894 second: Some(DateTimeFieldValue::new(6, 700_000_000)),
2895 ..Default::default()
2896 },
2897 "1 year 2 months 3 days 4 hours 5 minutes 6.7 seconds",
2898 Second,
2899 ),
2900 (
2901 ParsedDateTime {
2902 second: Some(DateTimeFieldValue::new(1, 0)),
2903 ..Default::default()
2904 },
2905 "1",
2906 Second,
2907 ),
2908 (
2909 ParsedDateTime {
2910 day: Some(DateTimeFieldValue::new(1, 0)),
2911 ..Default::default()
2912 },
2913 "1",
2914 Day,
2915 ),
2916 (
2917 ParsedDateTime {
2918 month: Some(DateTimeFieldValue::new(1, 0)),
2919 ..Default::default()
2920 },
2921 "1",
2922 Month,
2923 ),
2924 (
2925 ParsedDateTime {
2926 hour: Some(DateTimeFieldValue::new(1, 0)),
2927 minute: Some(DateTimeFieldValue::new(0, 0)),
2928 second: Some(DateTimeFieldValue::new(0, 0)),
2929 ..Default::default()
2930 },
2931 "1:",
2932 Second,
2933 ),
2934 (
2935 ParsedDateTime {
2936 year: Some(DateTimeFieldValue::new(1, 0)),
2937 month: Some(DateTimeFieldValue::new(0, 0)),
2938 ..Default::default()
2939 },
2940 "1-",
2941 Second,
2942 ),
2943 (
2944 ParsedDateTime {
2945 day: Some(DateTimeFieldValue::new(1, 0)),
2946 hour: Some(DateTimeFieldValue::new(2, 0)),
2947 minute: Some(DateTimeFieldValue::new(0, 0)),
2948 second: Some(DateTimeFieldValue::new(0, 0)),
2949 ..Default::default()
2950 },
2951 "1 2:",
2952 Second,
2953 ),
2954 (
2955 ParsedDateTime {
2956 year: Some(DateTimeFieldValue::new(1, 0)),
2957 month: Some(DateTimeFieldValue::new(2, 0)),
2958 hour: Some(DateTimeFieldValue::new(3, 0)),
2959 minute: Some(DateTimeFieldValue::new(4, 0)),
2960 second: Some(DateTimeFieldValue::new(0, 0)),
2961 ..Default::default()
2962 },
2963 "1-2 3:4",
2964 Second,
2965 ),
2966 (
2967 ParsedDateTime {
2968 year: Some(DateTimeFieldValue::new(1, 0)),
2969 month: Some(DateTimeFieldValue::new(0, 0)),
2970 day: Some(DateTimeFieldValue::new(2, 0)),
2971 hour: Some(DateTimeFieldValue::new(3, 0)),
2972 minute: Some(DateTimeFieldValue::new(0, 0)),
2973 second: Some(DateTimeFieldValue::new(0, 0)),
2974 ..Default::default()
2975 },
2976 "1- 2 3:",
2977 Second,
2978 ),
2979 (
2980 ParsedDateTime {
2981 year: Some(DateTimeFieldValue::new(5, 0)),
2982 month: Some(DateTimeFieldValue::new(6, 0)),
2983 hour: Some(DateTimeFieldValue::new(1, 0)),
2984 minute: Some(DateTimeFieldValue::new(2, 0)),
2985 second: Some(DateTimeFieldValue::new(3, 400_000_000)),
2986 ..Default::default()
2987 },
2988 "1:2:3.4 5-6",
2989 Second,
2990 ),
2991 (
2992 ParsedDateTime {
2993 year: Some(DateTimeFieldValue::new(1, 0)),
2994 month: Some(DateTimeFieldValue::new(2, 0)),
2995 hour: Some(DateTimeFieldValue::new(3, 0)),
2996 ..Default::default()
2997 },
2998 "1-2 3",
2999 Hour,
3000 ),
3001 (
3002 ParsedDateTime {
3003 year: Some(DateTimeFieldValue::new(-1, 0)),
3004 month: Some(DateTimeFieldValue::new(-2, 0)),
3005 day: Some(DateTimeFieldValue::new(-3, 0)),
3006 hour: Some(DateTimeFieldValue::new(-4, 0)),
3007 minute: Some(DateTimeFieldValue::new(-5, 0)),
3008 second: Some(DateTimeFieldValue::new(-6, -700_000_000)),
3009 ..Default::default()
3010 },
3011 "-1-2 -3 -4:5:6.7",
3012 Second,
3013 ),
3014 (
3015 ParsedDateTime {
3016 year: Some(DateTimeFieldValue::new(-1, 0)),
3017 month: Some(DateTimeFieldValue::new(-2, 0)),
3018 day: Some(DateTimeFieldValue::new(3, 0)),
3019 hour: Some(DateTimeFieldValue::new(-4, 0)),
3020 minute: Some(DateTimeFieldValue::new(-5, 0)),
3021 second: Some(DateTimeFieldValue::new(-6, -700_000_000)),
3022 ..Default::default()
3023 },
3024 "-1-2 3 -4:5:6.7",
3025 Second,
3026 ),
3027 (
3028 ParsedDateTime {
3029 year: Some(DateTimeFieldValue::new(-1, 0)),
3030 month: Some(DateTimeFieldValue::new(-2, 0)),
3031 day: Some(DateTimeFieldValue::new(-3, 0)),
3032 hour: Some(DateTimeFieldValue::new(4, 0)),
3033 minute: Some(DateTimeFieldValue::new(0, 0)),
3034 second: Some(DateTimeFieldValue::new(0, 500_000_000)),
3035 ..Default::default()
3036 },
3037 "-1-2 -3 4::.5",
3038 Second,
3039 ),
3040 (
3041 ParsedDateTime {
3042 hour: Some(DateTimeFieldValue::new(0, 0)),
3043 minute: Some(DateTimeFieldValue::new(0, 0)),
3044 second: Some(DateTimeFieldValue::new(-1, -270_000_000)),
3045 ..Default::default()
3046 },
3047 "-::1.27",
3048 Second,
3049 ),
3050 (
3051 ParsedDateTime {
3052 second: Some(DateTimeFieldValue::new(1, 270_000_000)),
3053 ..Default::default()
3054 },
3055 ":::::1.27",
3056 Second,
3057 ),
3058 (
3059 ParsedDateTime {
3060 year: Some(DateTimeFieldValue::new(1, 0)),
3061 month: Some(DateTimeFieldValue::new(0, 0)),
3062 day: Some(DateTimeFieldValue::new(2, 0)),
3063 hour: Some(DateTimeFieldValue::new(3, 0)),
3064 minute: Some(DateTimeFieldValue::new(0, 0)),
3065 second: Some(DateTimeFieldValue::new(0, 0)),
3066 ..Default::default()
3067 },
3068 ":::1- ::2 ::::3:",
3069 Second,
3070 ),
3071 (
3072 ParsedDateTime {
3073 year: Some(DateTimeFieldValue::new(1, 0)),
3074 month: Some(DateTimeFieldValue::new(2, 0)),
3075 day: Some(DateTimeFieldValue::new(3, 0)),
3076 hour: Some(DateTimeFieldValue::new(4, 0)),
3077 minute: Some(DateTimeFieldValue::new(5, 0)),
3078 second: Some(DateTimeFieldValue::new(6, 700_000_000)),
3079 ..Default::default()
3080 },
3081 "1 years 2 months 3 days 4 hours 5 minutes 6.7 seconds",
3082 Second,
3083 ),
3084 (
3085 ParsedDateTime {
3086 year: Some(DateTimeFieldValue::new(1, 0)),
3087 month: Some(DateTimeFieldValue::new(2, 0)),
3088 day: Some(DateTimeFieldValue::new(3, 0)),
3089 hour: Some(DateTimeFieldValue::new(4, 0)),
3090 minute: Some(DateTimeFieldValue::new(5, 0)),
3091 second: Some(DateTimeFieldValue::new(6, 700_000_000)),
3092 ..Default::default()
3093 },
3094 "1y 2mon 3d 4h 5m 6.7s",
3095 Second,
3096 ),
3097 (
3098 ParsedDateTime {
3099 year: Some(DateTimeFieldValue::new(1, 0)),
3100 month: Some(DateTimeFieldValue::new(2, 0)),
3101 day: Some(DateTimeFieldValue::new(3, 0)),
3102 hour: Some(DateTimeFieldValue::new(4, 0)),
3103 minute: Some(DateTimeFieldValue::new(5, 0)),
3104 second: Some(DateTimeFieldValue::new(6, 700_000_000)),
3105 ..Default::default()
3106 },
3107 "6.7 seconds 5 minutes 3 days 4 hours 1 year 2 month",
3108 Second,
3109 ),
3110 (
3111 ParsedDateTime {
3112 year: Some(DateTimeFieldValue::new(-1, 0)),
3113 month: Some(DateTimeFieldValue::new(2, 0)),
3114 day: Some(DateTimeFieldValue::new(-3, 0)),
3115 hour: Some(DateTimeFieldValue::new(4, 0)),
3116 minute: Some(DateTimeFieldValue::new(5, 0)),
3117 second: Some(DateTimeFieldValue::new(-6, -700_000_000)),
3118 ..Default::default()
3119 },
3120 "-6.7 seconds 5 minutes -3 days 4 hours -1 year 2 month",
3121 Second,
3122 ),
3123 (
3124 ParsedDateTime {
3125 year: Some(DateTimeFieldValue::new(1, 0)),
3126 month: Some(DateTimeFieldValue::new(2, 300_000_000)),
3127 day: Some(DateTimeFieldValue::new(4, 500_000_000)),
3128 ..Default::default()
3129 },
3130 "1y 2.3mon 4.5d",
3131 Second,
3132 ),
3133 (
3134 ParsedDateTime {
3135 year: Some(DateTimeFieldValue::new(-1, -200_000_000)),
3136 month: Some(DateTimeFieldValue::new(2, 300_000_000)),
3137 day: Some(DateTimeFieldValue::new(-3, -400_000_000)),
3138 hour: Some(DateTimeFieldValue::new(4, 500_000_000)),
3139 minute: Some(DateTimeFieldValue::new(5, 600_000_000)),
3140 second: Some(DateTimeFieldValue::new(-6, -700_000_000)),
3141 ..Default::default()
3142 },
3143 "-6.7 seconds 5.6 minutes -3.4 days 4.5 hours -1.2 year 2.3 month",
3144 Second,
3145 ),
3146 (
3147 ParsedDateTime {
3148 day: Some(DateTimeFieldValue::new(1, 0)),
3149 second: Some(DateTimeFieldValue::new(0, -270_000_000)),
3150 ..Default::default()
3151 },
3152 "1 day -0.27 seconds",
3153 Second,
3154 ),
3155 (
3156 ParsedDateTime {
3157 day: Some(DateTimeFieldValue::new(-1, 0)),
3158 second: Some(DateTimeFieldValue::new(0, 270_000_000)),
3159 ..Default::default()
3160 },
3161 "-1 day 0.27 seconds",
3162 Second,
3163 ),
3164 (
3165 ParsedDateTime {
3166 year: Some(DateTimeFieldValue::new(10, 333_000_000)),
3167 ..Default::default()
3168 },
3169 "10.333 years",
3170 Second,
3171 ),
3172 (
3173 ParsedDateTime {
3174 year: Some(DateTimeFieldValue::new(10, 333_000_000)),
3175 ..Default::default()
3176 },
3177 "10.333",
3178 Year,
3179 ),
3180 (
3181 ParsedDateTime {
3182 year: Some(DateTimeFieldValue::new(1, 0)),
3183 month: Some(DateTimeFieldValue::new(2, 0)),
3184 day: Some(DateTimeFieldValue::new(5, 0)),
3185 hour: Some(DateTimeFieldValue::new(3, 0)),
3186 minute: Some(DateTimeFieldValue::new(4, 0)),
3187 second: Some(DateTimeFieldValue::new(0, 0)),
3188 ..Default::default()
3189 },
3190 "1-2 3:4 5 day",
3191 Second,
3192 ),
3193 (
3194 ParsedDateTime {
3195 year: Some(DateTimeFieldValue::new(1, 0)),
3196 month: Some(DateTimeFieldValue::new(2, 0)),
3197 day: Some(DateTimeFieldValue::new(5, 0)),
3198 hour: Some(DateTimeFieldValue::new(3, 0)),
3199 minute: Some(DateTimeFieldValue::new(4, 0)),
3200 second: Some(DateTimeFieldValue::new(0, 0)),
3201 ..Default::default()
3202 },
3203 "5 day 3:4 1-2",
3204 Second,
3205 ),
3206 (
3207 ParsedDateTime {
3208 year: Some(DateTimeFieldValue::new(1, 0)),
3209 month: Some(DateTimeFieldValue::new(2, 0)),
3210 day: Some(DateTimeFieldValue::new(5, 0)),
3211 hour: Some(DateTimeFieldValue::new(3, 0)),
3212 minute: Some(DateTimeFieldValue::new(4, 0)),
3213 second: Some(DateTimeFieldValue::new(0, 0)),
3214 ..Default::default()
3215 },
3216 "1-2 5 day 3:4",
3217 Second,
3218 ),
3219 (
3220 ParsedDateTime {
3221 year: Some(DateTimeFieldValue::new(1, 0)),
3222 day: Some(DateTimeFieldValue::new(2, 0)),
3223 hour: Some(DateTimeFieldValue::new(3, 0)),
3224 minute: Some(DateTimeFieldValue::new(4, 0)),
3225 second: Some(DateTimeFieldValue::new(5, 600_000_000)),
3226 ..Default::default()
3227 },
3228 "+1 year +2 days +3:4:5.6",
3229 Second,
3230 ),
3231 (
3232 ParsedDateTime {
3233 year: Some(DateTimeFieldValue::new(1, 0)),
3234 month: Some(DateTimeFieldValue::new(2, 0)),
3235 ..Default::default()
3236 },
3237 "1-2",
3238 Month,
3239 ),
3240 (
3241 ParsedDateTime {
3242 year: Some(DateTimeFieldValue::new(1, 0)),
3243 month: Some(DateTimeFieldValue::new(2, 0)),
3244 ..Default::default()
3245 },
3246 "1-2",
3247 Minute,
3248 ),
3249 (
3250 ParsedDateTime {
3251 day: Some(DateTimeFieldValue::new(1, 999_999_999)),
3252 ..Default::default()
3253 },
3254 "1.999999999999999999 days",
3255 Second,
3256 ),
3257 (
3258 ParsedDateTime {
3259 millisecond: Some(DateTimeFieldValue::new(1, 200_000_000)),
3260 ..Default::default()
3261 },
3262 "1.2ms",
3263 Second,
3264 ),
3265 (
3266 ParsedDateTime {
3267 millisecond: Some(DateTimeFieldValue::new(1, 0)),
3268 ..Default::default()
3269 },
3270 "1ms",
3271 Second,
3272 ),
3273 (
3274 ParsedDateTime {
3275 millisecond: Some(DateTimeFieldValue::new(2100, 0)),
3276 ..Default::default()
3277 },
3278 "2100ms",
3279 Second,
3280 ),
3281 (
3282 ParsedDateTime {
3283 hour: Some(DateTimeFieldValue::new(1, 0)),
3284 millisecond: Some(DateTimeFieldValue::new(2, 0)),
3285 ..Default::default()
3286 },
3287 "1h 2ms",
3288 Second,
3289 ),
3290 (
3291 ParsedDateTime {
3292 millisecond: Some(DateTimeFieldValue::new(42, 900_000_000)),
3293 ..Default::default()
3294 },
3295 "42.9 milliseconds",
3296 Second,
3297 ),
3298 (
3299 ParsedDateTime {
3300 second: Some(DateTimeFieldValue::new(5, 0)),
3301 millisecond: Some(DateTimeFieldValue::new(37, 660_000_000)),
3302 ..Default::default()
3303 },
3304 "5.0 seconds 37.66 milliseconds",
3305 Second,
3306 ),
3307 (
3308 ParsedDateTime {
3309 day: Some(DateTimeFieldValue::new(14, 0)),
3310 millisecond: Some(DateTimeFieldValue::new(60, 0)),
3311 ..Default::default()
3312 },
3313 "14 days 60 ms",
3314 Second,
3315 ),
3316 (
3317 ParsedDateTime {
3318 microsecond: Some(DateTimeFieldValue::new(42, 900_000_000)),
3319 ..Default::default()
3320 },
3321 "42.9 microseconds",
3322 Second,
3323 ),
3324 (
3325 ParsedDateTime {
3326 second: Some(DateTimeFieldValue::new(5, 0)),
3327 microsecond: Some(DateTimeFieldValue::new(37, 660_000_000)),
3328 ..Default::default()
3329 },
3330 "5.0 seconds 37.66 microseconds",
3331 Second,
3332 ),
3333 (
3334 ParsedDateTime {
3335 millennium: Some(DateTimeFieldValue::new(9, 800_000_000)),
3336 ..Default::default()
3337 },
3338 "9.8 millenniums",
3339 Second,
3340 ),
3341 (
3342 ParsedDateTime {
3343 century: Some(DateTimeFieldValue::new(7, 600_000_000)),
3344 ..Default::default()
3345 },
3346 "7.6 centuries",
3347 Second,
3348 ),
3349 (
3350 ParsedDateTime {
3351 decade: Some(DateTimeFieldValue::new(5, 400_000_000)),
3352 ..Default::default()
3353 },
3354 "5.4 decades",
3355 Second,
3356 ),
3357 (
3358 ParsedDateTime {
3359 year: Some(DateTimeFieldValue::new(1, 200_000_000)),
3360 decade: Some(DateTimeFieldValue::new(4, 300_000_000)),
3361 century: Some(DateTimeFieldValue::new(5, 600_000_000)),
3362 millennium: Some(DateTimeFieldValue::new(8, 700_000_000)),
3363 ..Default::default()
3364 },
3365 "8.7 mils 5.6 cent 4.3 decs 1.2 y",
3366 Second,
3367 ),
3368 ];
3369
3370 for test in test_cases.iter() {
3371 let actual =
3372 ParsedDateTime::build_parsed_datetime_interval(test.1, None, test.2).unwrap();
3373 if actual != test.0 {
3374 panic!(
3375 "In test INTERVAL '{}' {}\n actual: {:?} \n expected: {:?}",
3376 test.1, test.2, actual, test.0
3377 );
3378 }
3379 }
3380 }
3381
3382 #[mz_ore::test]
3383 fn test_build_parsed_datetime_interval_errors() {
3384 use DateTimeField::*;
3385 let test_cases = [
3386 ("1 year 2 years", Second, "YEAR field set twice"),
3387 ("1-2 3-4", Second, "YEAR or MONTH field set twice"),
3388 ("1-2 3 year", Second, "YEAR field set twice"),
3389 ("1-2 3", Month, "MONTH field set twice"),
3390 ("1-2 3:4 5", Second, "SECOND field set twice"),
3391 ("1:2:3.4 5-6 7", Year, "YEAR field set twice"),
3392 ("-:::::1.27", Second, "have unprocessed tokens 1.270000000"),
3393 (
3394 "-1 ::.27",
3395 Second,
3396 "Cannot determine format of all parts. Add explicit time components, e.g. \
3397 INTERVAL '1 day' or INTERVAL '1' DAY",
3398 ),
3399 ("1:2:3.4.5", Second, "have unprocessed tokens .500000000"),
3400 ("1+2:3.4", Second, "Cannot determine format of all parts"),
3401 ("1x2:3.4", Second, "unknown units x"),
3402 ("0 foo", Second, "unknown units foo"),
3403 ("1-2 3:4 5 second", Second, "SECOND field set twice"),
3404 (
3405 "1-2 5 second 3:4",
3406 Second,
3407 "HOUR, MINUTE, SECOND field set twice",
3408 ),
3409 (
3410 "1 2-3 4:5",
3411 Day,
3412 "Cannot determine format of all parts. Add explicit time components, e.g. \
3413 INTERVAL '1 day' or INTERVAL '1' DAY",
3414 ),
3415 (
3416 "9223372036854775808 months",
3417 Day,
3418 "Unable to parse value 9223372036854775808 as a number: number too large to fit in target type",
3419 ),
3420 (
3421 "-9223372036854775809 months",
3422 Day,
3423 "Unable to parse value 9223372036854775809 as a number: number too large to fit in target type",
3424 ),
3425 (
3426 "9223372036854775808 seconds",
3427 Day,
3428 "Unable to parse value 9223372036854775808 as a number: number too large to fit in target type",
3429 ),
3430 (
3431 "-9223372036854775809 seconds",
3432 Day,
3433 "Unable to parse value 9223372036854775809 as a number: number too large to fit in target type",
3434 ),
3435 (
3436 "1.234 second 5 ms",
3437 Second,
3438 "Cannot set MILLISECONDS or MICROSECONDS field if SECOND field has a fraction component",
3439 ),
3440 (
3441 "1.234 second 5 us",
3442 Second,
3443 "Cannot set MILLISECONDS or MICROSECONDS field if SECOND field has a fraction component",
3444 ),
3445 (
3446 "7 ms 4.321 second",
3447 Second,
3448 "Cannot set MILLISECONDS or MICROSECONDS field if SECOND field has a fraction component",
3449 ),
3450 (
3451 "7 us 4.321 second",
3452 Second,
3453 "Cannot set MILLISECONDS or MICROSECONDS field if SECOND field has a fraction component",
3454 ),
3455 ];
3456 for test in test_cases.iter() {
3457 match ParsedDateTime::build_parsed_datetime_interval(test.0, None, test.1) {
3458 Err(e) => assert_eq!(e.to_string(), test.2),
3459 Ok(pdt) => panic!(
3460 "Test INTERVAL '{}' {} passed when expected to fail with {}, generated ParsedDateTime {:?}",
3461 test.0, test.1, test.2, pdt,
3462 ),
3463 }
3464 }
3465 }
3466
3467 #[mz_ore::test]
3468 fn test_split_timestamp_string() {
3469 let test_cases = [
3470 (
3471 "1969-06-01 10:10:10.410 UTC",
3472 "1969-06-01 10:10:10.410",
3473 "UTC",
3474 ),
3475 (
3476 "1969-06-01 10:10:10.410+4:00",
3477 "1969-06-01 10:10:10.410",
3478 "+4:00",
3479 ),
3480 (
3481 "1969-06-01 10:10:10.410-4:00",
3482 "1969-06-01 10:10:10.410",
3483 "-4:00",
3484 ),
3485 ("1969-06-01 10:10:10.410", "1969-06-01 10:10:10.410", ""),
3486 ("1969-06-01 10:10:10.410+4", "1969-06-01 10:10:10.410", "+4"),
3487 ("1969-06-01 10:10:10.410-4", "1969-06-01 10:10:10.410", "-4"),
3488 ("1969-06-01 10:10:10+4:00", "1969-06-01 10:10:10", "+4:00"),
3489 ("1969-06-01 10:10:10-4:00", "1969-06-01 10:10:10", "-4:00"),
3490 ("1969-06-01 10:10:10 UTC", "1969-06-01 10:10:10", "UTC"),
3491 ("1969-06-01 10:10:10", "1969-06-01 10:10:10", ""),
3492 ("1969-06-01 10:10+4:00", "1969-06-01 10:10", "+4:00"),
3493 ("1969-06-01 10:10-4:00", "1969-06-01 10:10", "-4:00"),
3494 ("1969-06-01 10:10 UTC", "1969-06-01 10:10", "UTC"),
3495 ("1969-06-01 10:10", "1969-06-01 10:10", ""),
3496 ("1969-06-01 UTC", "1969-06-01", "UTC"),
3497 ("1969-06-01 +4:00", "1969-06-01", "+4:00"),
3498 ("1969-06-01 -4:00", "1969-06-01", "-4:00"),
3499 ("1969-06-01 +4", "1969-06-01", "+4"),
3500 ("1969-06-01 -4", "1969-06-01", "-4"),
3501 ("1969-06-01", "1969-06-01", ""),
3502 ("1969-06-01 10:10:10.410Z", "1969-06-01 10:10:10.410", "Z"),
3503 ("1969-06-01 10:10:10.410z", "1969-06-01 10:10:10.410", "z"),
3504 ("1969-06-01Z", "1969-06-01", "Z"),
3505 ("1969-06-01z", "1969-06-01", "z"),
3506 ("1969-06-01 10:10:10.410 ", "1969-06-01 10:10:10.410", ""),
3507 (
3508 "1969-06-01 10:10:10.410 ",
3509 "1969-06-01 10:10:10.410",
3510 "",
3511 ),
3512 (" 1969-06-01 10:10:10.412", "1969-06-01 10:10:10.412", ""),
3513 (
3514 " 1969-06-01 10:10:10.413 ",
3515 "1969-06-01 10:10:10.413",
3516 "",
3517 ),
3518 (
3519 "1969-06-01 10:10:10.410 +4:00",
3520 "1969-06-01 10:10:10.410",
3521 "+4:00",
3522 ),
3523 (
3524 "1969-06-01 10:10:10.410+4 :00",
3525 "1969-06-01 10:10:10.410",
3526 "+4 :00",
3527 ),
3528 (
3529 "1969-06-01 10:10:10.410 +4:00",
3530 "1969-06-01 10:10:10.410",
3531 "+4:00",
3532 ),
3533 (
3534 "1969-06-01 10:10:10.410+4:00 ",
3535 "1969-06-01 10:10:10.410",
3536 "+4:00",
3537 ),
3538 (
3539 "1969-06-01 10:10:10.410 Z ",
3540 "1969-06-01 10:10:10.410",
3541 "Z",
3542 ),
3543 ("1969-06-01 +4 ", "1969-06-01", "+4"),
3544 ("1969-06-01 Z ", "1969-06-01", "Z"),
3545 ];
3546
3547 for test in test_cases.iter() {
3548 let (ts, tz, era) = split_timestamp_string(test.0);
3549
3550 assert_eq!(ts, test.1);
3551 assert_eq!(tz, test.2);
3552 assert_eq!(era, CalendarEra::AD);
3553 }
3554 }
3555
3556 proptest! {
3557 #[mz_ore::test]
3558 #[cfg_attr(miri, ignore)] fn datetimeunits_serialization_roundtrip(expect in any::<DateTimeUnits>() ) {
3560 let actual = protobuf_roundtrip::<_, ProtoDateTimeUnits>(&expect);
3561 assert_ok!(actual);
3562 assert_eq!(actual.unwrap(), expect);
3563 }
3564 }
3565
3566 #[mz_ore::test]
3567 fn proptest_packed_naive_time_roundtrips() {
3568 let strat = add_arb_duration(NaiveTime::from_hms_opt(0, 0, 0).unwrap());
3569 proptest!(|(time in strat)| {
3570 let packed = PackedNaiveTime::from_value(time);
3571 let rnd = packed.into_value();
3572 prop_assert_eq!(time, rnd);
3573 });
3574 }
3575
3576 #[mz_ore::test]
3577 fn proptest_packed_naive_time_sort_order() {
3578 let time = add_arb_duration(NaiveTime::from_hms_opt(0, 0, 0).unwrap());
3579 let strat = proptest::collection::vec(time, 0..128);
3580 proptest!(|(mut times in strat)| {
3581 let mut packed: Vec<_> = times.iter().copied().map(PackedNaiveTime::from_value).collect();
3582
3583 times.sort();
3584 packed.sort();
3585
3586 for (time, packed) in times.into_iter().zip(packed.into_iter()) {
3587 let rnd = packed.into_value();
3588 prop_assert_eq!(time, rnd);
3589 }
3590 });
3591 }
3592}
3593
3594#[mz_ore::test]
3595fn test_parseddatetime_add_field() {
3596 use DateTimeField::*;
3597 let pdt_unit = ParsedDateTime {
3598 millennium: Some(DateTimeFieldValue::new(8, 0)),
3599 century: Some(DateTimeFieldValue::new(9, 0)),
3600 decade: Some(DateTimeFieldValue::new(10, 0)),
3601 year: Some(DateTimeFieldValue::new(1, 0)),
3602 month: Some(DateTimeFieldValue::new(2, 0)),
3603 day: Some(DateTimeFieldValue::new(2, 0)),
3604 hour: Some(DateTimeFieldValue::new(3, 0)),
3605 minute: Some(DateTimeFieldValue::new(4, 0)),
3606 second: Some(DateTimeFieldValue::new(5, 0)),
3607 millisecond: Some(DateTimeFieldValue::new(6, 0)),
3608 microsecond: Some(DateTimeFieldValue::new(7, 0)),
3609 ..Default::default()
3610 };
3611
3612 let pdt_frac = ParsedDateTime {
3613 millennium: Some(DateTimeFieldValue::new(8, 555_555_555)),
3614 century: Some(DateTimeFieldValue::new(9, 555_555_555)),
3615 decade: Some(DateTimeFieldValue::new(10, 555_555_555)),
3616 year: Some(DateTimeFieldValue::new(1, 555_555_555)),
3617 month: Some(DateTimeFieldValue::new(2, 555_555_555)),
3618 day: Some(DateTimeFieldValue::new(2, 555_555_555)),
3619 hour: Some(DateTimeFieldValue::new(3, 555_555_555)),
3620 minute: Some(DateTimeFieldValue::new(4, 555_555_555)),
3621 second: Some(DateTimeFieldValue::new(5, 555_555_555)),
3622 millisecond: Some(DateTimeFieldValue::new(6, 555_555_555)),
3623 microsecond: Some(DateTimeFieldValue::new(7, 555_555_555)),
3624 ..Default::default()
3625 };
3626
3627 let pdt_frac_neg = ParsedDateTime {
3628 millennium: Some(DateTimeFieldValue::new(-8, -555_555_555)),
3629 century: Some(DateTimeFieldValue::new(-9, -555_555_555)),
3630 decade: Some(DateTimeFieldValue::new(-10, -555_555_555)),
3631 year: Some(DateTimeFieldValue::new(-1, -555_555_555)),
3632 month: Some(DateTimeFieldValue::new(-2, -555_555_555)),
3633 day: Some(DateTimeFieldValue::new(-2, -555_555_555)),
3634 hour: Some(DateTimeFieldValue::new(-3, -555_555_555)),
3635 minute: Some(DateTimeFieldValue::new(-4, -555_555_555)),
3636 second: Some(DateTimeFieldValue::new(-5, -555_555_555)),
3637 millisecond: Some(DateTimeFieldValue::new(-6, -555_555_555)),
3638 microsecond: Some(DateTimeFieldValue::new(-7, -555_555_555)),
3639 ..Default::default()
3640 };
3641
3642 let pdt_s_rollover = ParsedDateTime {
3643 millisecond: Some(DateTimeFieldValue::new(1002, 666_666_666)),
3644 microsecond: Some(DateTimeFieldValue::new(1000003, 777_777_777)),
3645 ..Default::default()
3646 };
3647
3648 run_test_parseddatetime_add_field(pdt_unit.clone(), Millennium, (8 * 12 * 1_000, 0, 0));
3649 run_test_parseddatetime_add_field(pdt_unit.clone(), Century, (9 * 12 * 100, 0, 0));
3650 run_test_parseddatetime_add_field(pdt_unit.clone(), Decade, (10 * 12 * 10, 0, 0));
3651 run_test_parseddatetime_add_field(pdt_unit.clone(), Year, (12, 0, 0));
3652 run_test_parseddatetime_add_field(pdt_unit.clone(), Month, (2, 0, 0));
3653 run_test_parseddatetime_add_field(pdt_unit.clone(), Day, (0, 2, 0));
3654 run_test_parseddatetime_add_field(pdt_unit.clone(), Hour, (0, 0, 3 * 60 * 60 * 1_000_000));
3655 run_test_parseddatetime_add_field(pdt_unit.clone(), Minute, (0, 0, 4 * 60 * 1_000_000));
3656 run_test_parseddatetime_add_field(pdt_unit.clone(), Second, (0, 0, 5 * 1_000_000));
3657 run_test_parseddatetime_add_field(pdt_unit.clone(), Milliseconds, (0, 0, 6 * 1_000));
3658 run_test_parseddatetime_add_field(pdt_unit, Microseconds, (0, 0, 7));
3659 run_test_parseddatetime_add_field(pdt_frac.clone(), Millennium, (102_666, 0, 0));
3660 run_test_parseddatetime_add_field(pdt_frac.clone(), Century, (11466, 0, 0));
3661 run_test_parseddatetime_add_field(pdt_frac.clone(), Decade, (1266, 0, 0));
3662 run_test_parseddatetime_add_field(pdt_frac.clone(), Year, (18, 0, 0));
3663 run_test_parseddatetime_add_field(
3664 pdt_frac.clone(),
3665 Month,
3666 (
3667 2,
3668 16,
3669 (15 * 60 * 60 * 1_000_000) + (59 * 60 * 1_000_000) + (59 * 1_000_000) + 998_560,
3671 ),
3672 );
3673 run_test_parseddatetime_add_field(
3674 pdt_frac.clone(),
3675 Day,
3676 (
3677 0,
3678 2,
3679 (13 * 60 * 60 * 1_000_000) + (19 * 60 * 1_000_000) + (59 * 1_000_000) + 999_952,
3681 ),
3682 );
3683 run_test_parseddatetime_add_field(
3684 pdt_frac.clone(),
3685 Hour,
3686 (
3687 0,
3688 0,
3689 (3 * 60 * 60 * 1_000_000) + (33 * 60 * 1_000_000) + (19 * 1_000_000) + 999_998,
3691 ),
3692 );
3693 run_test_parseddatetime_add_field(
3694 pdt_frac.clone(),
3695 Minute,
3696 (
3697 0,
3698 0,
3699 (4 * 60 * 1_000_000) + (33 * 1_000_000) + 333_333,
3701 ),
3702 );
3703 run_test_parseddatetime_add_field(
3704 pdt_frac.clone(),
3705 Second,
3706 (
3707 0,
3708 0,
3709 (5 * 1_000_000) + 555_556,
3711 ),
3712 );
3713 run_test_parseddatetime_add_field(
3714 pdt_frac.clone(),
3715 Milliseconds,
3716 (
3717 0, 0, 6_556,
3719 ),
3720 );
3721 run_test_parseddatetime_add_field(
3722 pdt_frac,
3723 Microseconds,
3724 (
3725 0, 0, 8,
3727 ),
3728 );
3729 run_test_parseddatetime_add_field(pdt_frac_neg.clone(), Year, (-18, 0, 0));
3730 run_test_parseddatetime_add_field(
3731 pdt_frac_neg.clone(),
3732 Month,
3733 (
3734 -2,
3735 -16,
3736 (-15 * 60 * 60 * 1_000_000) + (-59 * 60 * 1_000_000) + (-59 * 1_000_000) + -998_560,
3738 ),
3739 );
3740 run_test_parseddatetime_add_field(
3741 pdt_frac_neg.clone(),
3742 Day,
3743 (
3744 0,
3745 -2,
3746 (-13 * 60 * 60 * 1_000_000) + (-19 * 60 * 1_000_000) + (-59 * 1_000_000) + -999_952,
3748 ),
3749 );
3750 run_test_parseddatetime_add_field(
3751 pdt_frac_neg.clone(),
3752 Hour,
3753 (
3754 0,
3755 0,
3756 (-3 * 60 * 60 * 1_000_000) + (-33 * 60 * 1_000_000) + (-19 * 1_000_000) + -999_998,
3758 ),
3759 );
3760 run_test_parseddatetime_add_field(
3761 pdt_frac_neg.clone(),
3762 Minute,
3763 (
3764 0,
3765 0,
3766 (-4 * 60 * 1_000_000) + (-33 * 1_000_000) + -333_333,
3768 ),
3769 );
3770 run_test_parseddatetime_add_field(
3771 pdt_frac_neg.clone(),
3772 Second,
3773 (
3774 0,
3775 0,
3776 (-5 * 1_000_000) + -555_556,
3778 ),
3779 );
3780 run_test_parseddatetime_add_field(
3781 pdt_frac_neg.clone(),
3782 Milliseconds,
3783 (
3784 0, 0, -6_556,
3786 ),
3787 );
3788 run_test_parseddatetime_add_field(
3789 pdt_frac_neg,
3790 Microseconds,
3791 (
3792 0, 0, -8,
3794 ),
3795 );
3796 run_test_parseddatetime_add_field(
3797 pdt_s_rollover.clone(),
3798 Milliseconds,
3799 (
3800 0,
3801 0, (1 * 1_000_000) + 2_667,
3803 ),
3804 );
3805 run_test_parseddatetime_add_field(
3806 pdt_s_rollover,
3807 Microseconds,
3808 (
3809 0,
3810 0, (1 * 1_000_000) + 4,
3812 ),
3813 );
3814
3815 fn run_test_parseddatetime_add_field(
3816 pdt: ParsedDateTime,
3817 f: DateTimeField,
3818 expected: (i32, i32, i64),
3819 ) {
3820 let mut res = (0, 0, 0);
3821
3822 pdt.add_field(f, &mut res.0, &mut res.1, &mut res.2)
3823 .unwrap();
3824
3825 if res.0 != expected.0 || res.1 != expected.1 || res.2 != expected.2 {
3826 panic!(
3827 "test_parseddatetime_add_field failed \n actual: {:?} \n expected: {:?}",
3828 res, expected
3829 );
3830 }
3831 }
3832}
3833
3834#[mz_ore::test]
3835fn test_parseddatetime_compute_interval() {
3836 run_test_parseddatetime_compute_interval(
3837 ParsedDateTime {
3838 year: Some(DateTimeFieldValue::new(1, 0)),
3839 month: Some(DateTimeFieldValue::new(1, 0)),
3840 ..Default::default()
3841 },
3842 Interval {
3843 months: 13,
3844 ..Default::default()
3845 },
3846 );
3847 run_test_parseddatetime_compute_interval(
3848 ParsedDateTime {
3849 year: Some(DateTimeFieldValue::new(1, 0)),
3850 month: Some(DateTimeFieldValue::new(-1, 0)),
3851 ..Default::default()
3852 },
3853 Interval {
3854 months: 11,
3855 ..Default::default()
3856 },
3857 );
3858 run_test_parseddatetime_compute_interval(
3859 ParsedDateTime {
3860 year: Some(DateTimeFieldValue::new(-1, 0)),
3861 month: Some(DateTimeFieldValue::new(1, 0)),
3862 ..Default::default()
3863 },
3864 Interval {
3865 months: -11,
3866 ..Default::default()
3867 },
3868 );
3869 run_test_parseddatetime_compute_interval(
3870 ParsedDateTime {
3871 day: Some(DateTimeFieldValue::new(1, 0)),
3872 hour: Some(DateTimeFieldValue::new(-2, 0)),
3873 minute: Some(DateTimeFieldValue::new(-3, 0)),
3874 second: Some(DateTimeFieldValue::new(-4, -500_000_000)),
3875 ..Default::default()
3876 },
3877 Interval::new(
3879 0,
3880 1,
3881 (-2 * 60 * 60 * 1_000_000) + (-3 * 60 * 1_000_000) + (-4 * 1_000_000) + -500_000,
3882 ),
3883 );
3884 run_test_parseddatetime_compute_interval(
3885 ParsedDateTime {
3886 day: Some(DateTimeFieldValue::new(-1, 0)),
3887 hour: Some(DateTimeFieldValue::new(2, 0)),
3888 minute: Some(DateTimeFieldValue::new(3, 0)),
3889 second: Some(DateTimeFieldValue::new(4, 500_000_000)),
3890 ..Default::default()
3891 },
3892 Interval::new(
3894 0,
3895 -1,
3896 (2 * 60 * 60 * 1_000_000) + (3 * 60 * 1_000_000) + (4 * 1_000_000) + 500_000,
3897 ),
3898 );
3899 run_test_parseddatetime_compute_interval(
3900 ParsedDateTime {
3901 day: Some(DateTimeFieldValue::new(1, 0)),
3902 second: Some(DateTimeFieldValue::new(0, -270_000_000)),
3903 ..Default::default()
3904 },
3905 Interval::new(0, 1, -270_000),
3907 );
3908 run_test_parseddatetime_compute_interval(
3909 ParsedDateTime {
3910 day: Some(DateTimeFieldValue::new(-1, 0)),
3911 second: Some(DateTimeFieldValue::new(0, 270_000_000)),
3912 ..Default::default()
3913 },
3914 Interval::new(0, -1, 270_000),
3916 );
3917 run_test_parseddatetime_compute_interval(
3918 ParsedDateTime {
3919 year: Some(DateTimeFieldValue::new(-1, -555_555_555)),
3920 month: Some(DateTimeFieldValue::new(2, 555_555_555)),
3921 day: Some(DateTimeFieldValue::new(-3, -555_555_555)),
3922 hour: Some(DateTimeFieldValue::new(4, 555_555_555)),
3923 minute: Some(DateTimeFieldValue::new(-5, -555_555_555)),
3924 second: Some(DateTimeFieldValue::new(6, 555_555_555)),
3925 ..Default::default()
3926 },
3927 Interval::new(
3929 -16,
3930 13,
3931 (7 * 60 * 60 * 1_000_000) + (7 * 60 * 1_000_000) + (53 * 1_000_000) + 220_829,
3932 ),
3933 );
3934 run_test_parseddatetime_compute_interval(
3935 ParsedDateTime {
3936 second: Some(DateTimeFieldValue::new(1, 0)),
3937 millisecond: Some(DateTimeFieldValue::new(2_003, 0)),
3938 ..Default::default()
3939 },
3940 Interval::new(0, 0, (3 * 1_000_000) + 3_000),
3942 );
3943 run_test_parseddatetime_compute_interval(
3944 ParsedDateTime {
3945 second: Some(DateTimeFieldValue::new(1, 0)),
3946 microsecond: Some(DateTimeFieldValue::new(2_000_003, 0)),
3947 ..Default::default()
3948 },
3949 Interval::new(0, 0, (3 * 1_000_000) + 3),
3951 );
3952 run_test_parseddatetime_compute_interval(
3953 ParsedDateTime {
3954 millisecond: Some(DateTimeFieldValue::new(1, 200_000_000)),
3955 microsecond: Some(DateTimeFieldValue::new(3, 400_000_000)),
3956 ..Default::default()
3957 },
3958 Interval::new(0, 0, 1_203),
3960 );
3961 run_test_parseddatetime_compute_interval(
3962 ParsedDateTime {
3963 millennium: Some(DateTimeFieldValue::new(1, 0)),
3964 century: Some(DateTimeFieldValue::new(2, 0)),
3965 decade: Some(DateTimeFieldValue::new(3, 0)),
3966 year: Some(DateTimeFieldValue::new(4, 0)),
3967 ..Default::default()
3968 },
3969 Interval::new(1234 * 12, 0, 0),
3971 );
3972
3973 fn run_test_parseddatetime_compute_interval(pdt: ParsedDateTime, expected: Interval) {
3974 let actual = pdt.compute_interval().unwrap();
3975
3976 if actual != expected {
3977 panic!(
3978 "test_interval_compute_interval failed\n input {:?}\nactual {:?}\nexpected {:?}",
3979 pdt, actual, expected
3980 )
3981 }
3982 }
3983}