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
1877pub(crate) fn split_timestamp_string(value: &str) -> (&str, &str, CalendarEra) {
1881 let cut = value.find(" +").or_else(|| value.find(" -"));
1885
1886 if let Some(cut) = cut {
1887 let (datetime, timezone) = value.split_at(cut);
1888
1889 let (timezone, era) = strip_era_from_timezone(timezone);
1890
1891 return (datetime.trim(), timezone.trim(), era);
1892 }
1893
1894 let colon = value.find(':');
1897
1898 if let Some(colon) = colon {
1899 let substring = value.get(colon..);
1900 if let Some(substring) = substring {
1901 let tz = substring
1902 .find(|c: char| (c == '-') || (c == '+') || (c == ' ') || c.is_ascii_alphabetic());
1903
1904 if let Some(tz) = tz {
1905 let (datetime, timezone) = value.split_at(colon + tz);
1906
1907 let (timezone, era) = strip_era_from_timezone(timezone);
1908
1909 return (datetime.trim(), timezone.trim(), era);
1910 }
1911 }
1912
1913 (value.trim(), "", CalendarEra::AD)
1914 } else {
1915 let cut = value.find(|c: char| c.is_ascii_alphabetic());
1919
1920 if let Some(cut) = cut {
1921 let (datetime, timezone) = value.split_at(cut);
1922
1923 let (timezone, era) = strip_era_from_timezone(timezone);
1924
1925 return (datetime.trim(), timezone.trim(), era);
1926 }
1927
1928 (value.trim(), "", CalendarEra::AD)
1929 }
1930}
1931
1932fn strip_era_from_timezone(timezone: &str) -> (&str, CalendarEra) {
1939 use CalendarEra::{AD, BC};
1940 let timezone = timezone.trim();
1941 let timezone_upper = timezone.to_uppercase();
1942
1943 if timezone.len() < 3 {
1945 return match (
1946 timezone_upper.strip_suffix("BC"),
1947 timezone_upper.strip_suffix("AD"),
1948 ) {
1949 (Some(_), None) => ("", BC),
1950 (None, Some(_)) => ("", AD),
1951 _ => (timezone, AD),
1954 };
1955 }
1956
1957 match (
1962 timezone_upper.strip_suffix(" BC"),
1963 timezone_upper.strip_suffix(" AD"),
1964 ) {
1965 (Some(_), None) => (&timezone[..timezone.len() - 3], BC),
1966 (None, Some(_)) => (&timezone[..timezone.len() - 3], AD),
1967 _ => (timezone, AD),
1968 }
1969}
1970
1971#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
1976pub struct PackedNaiveTime([u8; Self::SIZE]);
1977
1978impl FixedSizeCodec<NaiveTime> for PackedNaiveTime {
1979 const SIZE: usize = 8;
1980
1981 fn as_bytes(&self) -> &[u8] {
1982 &self.0
1983 }
1984
1985 fn from_bytes(slice: &[u8]) -> Result<Self, String> {
1986 let buf: [u8; Self::SIZE] = slice.try_into().map_err(|_| {
1987 format!(
1988 "size for PackedNaiveTime is {} bytes, got {}",
1989 Self::SIZE,
1990 slice.len()
1991 )
1992 })?;
1993 Ok(PackedNaiveTime(buf))
1994 }
1995
1996 #[inline]
1997 fn from_value(value: NaiveTime) -> Self {
1998 let secs = value.num_seconds_from_midnight();
1999 let nano = value.nanosecond();
2000
2001 let mut buf = [0u8; Self::SIZE];
2002
2003 (buf[..4]).copy_from_slice(&secs.to_be_bytes());
2004 (buf[4..]).copy_from_slice(&nano.to_be_bytes());
2005
2006 PackedNaiveTime(buf)
2007 }
2008
2009 #[inline]
2010 fn into_value(self) -> NaiveTime {
2011 let mut secs = [0u8; 4];
2012 secs.copy_from_slice(&self.0[..4]);
2013 let secs = u32::from_be_bytes(secs);
2014
2015 let mut nano = [0u8; 4];
2016 nano.copy_from_slice(&self.0[4..]);
2017 let nano = u32::from_be_bytes(nano);
2018
2019 NaiveTime::from_num_seconds_from_midnight_opt(secs, nano)
2020 .expect("NaiveTime roundtrips with PackedNaiveTime")
2021 }
2022}
2023
2024#[cfg(test)]
2025mod tests {
2026 use mz_ore::assert_ok;
2027 use mz_proto::protobuf_roundtrip;
2028 use proptest::prelude::any;
2029 use proptest::{prop_assert_eq, proptest};
2030
2031 use crate::scalar::add_arb_duration;
2032
2033 use super::*;
2034
2035 #[mz_ore::test]
2036 fn iterate_datetimefield() {
2037 use DateTimeField::*;
2038 assert_eq!(
2039 Millennium.into_iter().take(10).collect::<Vec<_>>(),
2040 vec![
2041 Century,
2042 Decade,
2043 Year,
2044 Month,
2045 Day,
2046 Hour,
2047 Minute,
2048 Second,
2049 Milliseconds,
2050 Microseconds
2051 ]
2052 )
2053 }
2054
2055 #[mz_ore::test]
2056 fn test_expected_dur_like_tokens() {
2057 use DateTimeField::*;
2058 use TimeStrToken::*;
2059 assert_eq!(
2060 expected_sql_standard_interval_tokens(Hour),
2061 vec![Num(0, 1), Colon, Num(0, 1), Colon, Num(0, 1), Dot, Nanos(0)]
2062 );
2063 assert_eq!(
2064 expected_sql_standard_interval_tokens(Minute),
2065 vec![Num(0, 1), Colon, Num(0, 1), Dot, Nanos(0)]
2066 );
2067 assert_eq!(
2068 expected_sql_standard_interval_tokens(Second),
2069 vec![Num(0, 1), Dot, Nanos(0)]
2070 );
2071 }
2072
2073 #[mz_ore::test]
2074 fn test_expected_sql_standard_interval_tokens() {
2075 use DateTimeField::*;
2076 use TimeStrToken::*;
2077 assert_eq!(
2078 expected_sql_standard_interval_tokens(Year),
2079 vec![Num(0, 1), Dash, Num(0, 1), Delim]
2080 );
2081
2082 assert_eq!(
2083 expected_sql_standard_interval_tokens(Day),
2084 vec![Num(0, 1), Delim]
2085 );
2086 assert_eq!(
2087 expected_sql_standard_interval_tokens(Hour),
2088 vec![Num(0, 1), Colon, Num(0, 1), Colon, Num(0, 1), Dot, Nanos(0)]
2089 );
2090 }
2091 #[mz_ore::test]
2092 fn test_trim_and_return_sign() {
2093 let test_cases = [
2094 ("-2", -1, "2"),
2095 ("3", 1, "3"),
2096 ("+5", 1, "5"),
2097 ("-", -1, ""),
2098 ("-YEAR", -1, "YEAR"),
2099 ("YEAR", 1, "YEAR"),
2100 ];
2101
2102 for test in test_cases.iter() {
2103 let mut s = tokenize_time_str(test.0).unwrap();
2104
2105 assert_eq!(trim_and_return_sign(&mut s), test.1);
2106 assert_eq!(s.front(), tokenize_time_str(test.2).unwrap().front());
2107 }
2108 }
2109 #[mz_ore::test]
2110 fn test_determine_format_w_datetimefield() {
2111 use DateTimeField::*;
2112 use TimePartFormat::*;
2113
2114 let test_cases = [
2115 ("1-2 3", Some(SqlStandard(Year))),
2116 ("4:5", Some(SqlStandard(Hour))),
2117 ("4:5.6", Some(SqlStandard(Minute))),
2118 ("-4:5.6", Some(SqlStandard(Minute))),
2119 ("+4:5.6", Some(SqlStandard(Minute))),
2120 ("year", Some(PostgreSql(Year))),
2121 ("4year", Some(PostgreSql(Year))),
2122 ("-4year", Some(PostgreSql(Year))),
2123 ("5", None),
2124 ("5.6", None),
2125 ("3 4:5:6.7", None),
2126 ];
2127
2128 for test in test_cases.iter() {
2129 let s = tokenize_time_str(test.0).unwrap();
2130
2131 match (
2132 determine_format_w_datetimefield(s, None).unwrap(),
2133 test.1.as_ref(),
2134 ) {
2135 (Some(a), Some(b)) => {
2136 if a != *b {
2137 panic!(
2138 "determine_format_w_datetimefield_and_time returned {:?}, expected {:?}",
2139 a, b,
2140 )
2141 }
2142 }
2143 (None, None) => {}
2144 (x, y) => panic!(
2145 "determine_format_w_datetimefield_and_time returned {:?}, expected {:?}",
2146 x, y,
2147 ),
2148 }
2149 }
2150 }
2151 #[mz_ore::test]
2152 fn test_determine_format_w_datetimefield_and_leading_time() {
2153 use DateTimeField::*;
2154 use TimePartFormat::*;
2155
2156 assert_eq!(
2157 determine_format_w_datetimefield(tokenize_time_str("4:5").unwrap(), None,).unwrap(),
2158 Some(SqlStandard(Hour))
2159 );
2160 assert_eq!(
2161 determine_format_w_datetimefield(
2162 tokenize_time_str("4:5").unwrap(),
2163 Some(DateTimeField::Minute),
2164 )
2165 .unwrap(),
2166 Some(SqlStandard(Minute))
2167 );
2168 assert_eq!(
2169 determine_format_w_datetimefield(
2170 tokenize_time_str("4:5").unwrap(),
2171 Some(DateTimeField::Hour),
2172 )
2173 .unwrap(),
2174 Some(SqlStandard(Hour))
2175 );
2176 }
2177 #[mz_ore::test]
2178 fn test_determine_format_w_datetimefield_error() {
2179 let test_cases = [
2180 ("1+2", "Cannot determine format of all parts"),
2181 ("1:2+3", "Cannot determine format of all parts"),
2182 ("1:1YEAR2", "Cannot determine format of all parts"),
2183 ];
2184
2185 for test in test_cases.iter() {
2186 let s = tokenize_time_str(test.0).unwrap();
2187 match determine_format_w_datetimefield(s, None) {
2188 Err(e) => assert_eq!(e.to_string(), test.1),
2189 Ok(f) => panic!(
2190 "Test passed when expected to fail: {}, generated {:?}",
2191 test.0, f
2192 ),
2193 };
2194 }
2195 }
2196
2197 #[mz_ore::test]
2198 fn test_fill_pdt_from_tokens() {
2199 use DateTimeField::*;
2200 let test_cases = [
2201 (
2202 ParsedDateTime {
2203 year: Some(DateTimeFieldValue::new(1, 0)),
2204 month: Some(DateTimeFieldValue::new(2, 0)),
2205 day: Some(DateTimeFieldValue::new(3, 0)),
2206 hour: Some(DateTimeFieldValue::new(4, 0)),
2207 minute: Some(DateTimeFieldValue::new(5, 0)),
2208 second: Some(DateTimeFieldValue::new(6, 0)),
2209 ..Default::default()
2210 },
2211 "1 2 3 4 5 6",
2212 "0 0 0 0 0 0",
2213 Year,
2214 1,
2215 ),
2216 (
2217 ParsedDateTime {
2218 day: Some(DateTimeFieldValue::new(4, 0)),
2219 hour: Some(DateTimeFieldValue::new(5, 0)),
2220 minute: Some(DateTimeFieldValue::new(6, 0)),
2221 ..Default::default()
2222 },
2223 "4 5 6",
2224 "0 0 0",
2225 Day,
2226 1,
2227 ),
2228 (
2229 ParsedDateTime {
2230 day: Some(DateTimeFieldValue::new(-4, 0)),
2231 hour: Some(DateTimeFieldValue::new(-5, 0)),
2232 minute: Some(DateTimeFieldValue::new(-6, 0)),
2233 ..Default::default()
2234 },
2235 "4 5 6",
2236 "0 0 0",
2237 Day,
2238 -1,
2239 ),
2240 (
2242 ParsedDateTime {
2243 year: Some(DateTimeFieldValue::new(1, 0)),
2244 month: Some(DateTimeFieldValue::new(2, 0)),
2245 day: Some(DateTimeFieldValue::new(3, 0)),
2246 hour: Some(DateTimeFieldValue::new(4, 0)),
2247 minute: Some(DateTimeFieldValue::new(5, 0)),
2248 second: Some(DateTimeFieldValue::new(6, 0)),
2249 ..Default::default()
2250 },
2251 "1-2:3-4 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 hour: Some(DateTimeFieldValue::new(5, 0)),
2263 minute: 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 minute: Some(DateTimeFieldValue::new(5, 0)),
2278 second: Some(DateTimeFieldValue::new(6, 0)),
2279 ..Default::default()
2280 },
2281 "1-2:3- 5 6",
2282 "0-0:0-0 0 0",
2283 Year,
2284 1,
2285 ),
2286 (
2288 ParsedDateTime {
2289 year: Some(DateTimeFieldValue::new(1, 0)),
2290 month: Some(DateTimeFieldValue::new(2, 0)),
2291 day: Some(DateTimeFieldValue::new(3, 0)),
2292 hour: Some(DateTimeFieldValue::new(4, 0)),
2293 minute: Some(DateTimeFieldValue::new(5, 0)),
2294 second: Some(DateTimeFieldValue::new(6, 700_000_000)),
2295 ..Default::default()
2296 },
2297 "1-2:3-4 5 6.7",
2298 "0-0:0-0 0 0.0",
2299 Year,
2300 1,
2301 ),
2302 (
2304 ParsedDateTime {
2305 year: Some(DateTimeFieldValue::new(1, 200_000_000)),
2306 ..Default::default()
2307 },
2308 "1.2",
2309 "0.0",
2310 Year,
2311 1,
2312 ),
2313 (
2314 ParsedDateTime {
2315 minute: Some(DateTimeFieldValue::new(1, 200_000_000)),
2316 ..Default::default()
2317 },
2318 "1.2",
2319 "0.0",
2320 Minute,
2321 1,
2322 ),
2323 (
2325 ParsedDateTime {
2326 month: Some(DateTimeFieldValue::new(3, 0)),
2327 ..Default::default()
2328 },
2329 "3MONTHS",
2330 "0YEAR",
2331 Month,
2332 1,
2333 ),
2334 (
2335 ParsedDateTime {
2336 month: Some(DateTimeFieldValue::new(1, 0)),
2337 day: Some(DateTimeFieldValue::new(2, 0)),
2338 hour: Some(DateTimeFieldValue::new(3, 0)),
2339 ..Default::default()
2340 },
2341 "1MONTHS 2DAYS 3HOURS",
2342 "0YEAR 0YEAR 0YEAR",
2343 Month,
2344 1,
2345 ),
2346 (
2347 ParsedDateTime {
2348 month: Some(DateTimeFieldValue::new(1, 0)),
2349 day: Some(DateTimeFieldValue::new(2, 0)),
2350 ..Default::default()
2351 },
2352 "1MONTHS-2",
2353 "0YEAR-0",
2354 Month,
2355 1,
2356 ),
2357 ];
2358 for test in test_cases.iter() {
2359 let mut pdt = ParsedDateTime::default();
2360 let mut actual = tokenize_time_str(test.1).unwrap();
2361 let expected = tokenize_time_str(test.2).unwrap();
2362
2363 fill_pdt_from_tokens(&mut pdt, &mut actual, &expected, test.3, test.4).unwrap();
2364
2365 assert_eq!(pdt, test.0);
2366 }
2367 }
2368
2369 #[mz_ore::test]
2370 fn test_fill_pdt_from_tokens_errors() {
2371 use DateTimeField::*;
2372 let test_cases = [
2373 (
2375 "1 2 3",
2376 "0-0 0",
2377 Year,
2378 1,
2379 "Invalid syntax at offset 1: provided Delim but expected Dash",
2380 ),
2381 ];
2382 for test in test_cases.iter() {
2383 let mut pdt = ParsedDateTime::default();
2384 let mut actual = tokenize_time_str(test.0).unwrap();
2385 let expected = tokenize_time_str(test.1).unwrap();
2386
2387 match fill_pdt_from_tokens(&mut pdt, &mut actual, &expected, test.2, test.3) {
2388 Err(e) => assert_eq!(e.to_string(), test.4),
2389 Ok(_) => panic!("Test passed when expected to fail, generated {:?}", pdt),
2390 };
2391 }
2392 }
2393 #[mz_ore::test]
2394 #[should_panic(expected = "Cannot get smaller DateTimeField than MICROSECONDS")]
2395 fn test_fill_pdt_from_tokens_panic() {
2396 use DateTimeField::*;
2397 let test_cases = [
2398 ("1 2", "0 0", Microseconds, 1),
2400 ];
2401 for test in test_cases.iter() {
2402 let mut pdt = ParsedDateTime::default();
2403 let mut actual = tokenize_time_str(test.0).unwrap();
2404 let expected = tokenize_time_str(test.1).unwrap();
2405
2406 if fill_pdt_from_tokens(&mut pdt, &mut actual, &expected, test.2, test.3).is_ok() {
2407 panic!(
2408 "test_fill_pdt_from_tokens_panic should have panicked. input {}\nformat {}\
2409 \nDateTimeField {}\nGenerated ParsedDateTime {:?}",
2410 test.0, test.1, test.2, pdt
2411 );
2412 };
2413 }
2414 }
2415
2416 #[mz_ore::test]
2417 fn test_fill_pdt_interval_pg() {
2418 use DateTimeField::*;
2419 let test_cases = [
2420 (
2421 ParsedDateTime {
2422 year: Some(DateTimeFieldValue::new(2, 0)),
2423 ..Default::default()
2424 },
2425 "2",
2426 Year,
2427 ),
2428 (
2429 ParsedDateTime {
2430 month: Some(DateTimeFieldValue::new(2, 300_000_000)),
2431 ..Default::default()
2432 },
2433 "2.3",
2434 Month,
2435 ),
2436 (
2437 ParsedDateTime {
2438 day: Some(DateTimeFieldValue::new(-2, -300_000_000)),
2439 ..Default::default()
2440 },
2441 "-2.3",
2442 Day,
2443 ),
2444 (
2445 ParsedDateTime {
2446 hour: Some(DateTimeFieldValue::new(2, 0)),
2447 ..Default::default()
2448 },
2449 "2",
2450 Hour,
2451 ),
2452 (
2453 ParsedDateTime {
2454 minute: Some(DateTimeFieldValue::new(2, 300_000_000)),
2455 ..Default::default()
2456 },
2457 "2.3",
2458 Minute,
2459 ),
2460 (
2461 ParsedDateTime {
2462 second: Some(DateTimeFieldValue::new(-2, -300_000_000)),
2463 ..Default::default()
2464 },
2465 "-2.3",
2466 Second,
2467 ),
2468 (
2469 ParsedDateTime {
2470 year: Some(DateTimeFieldValue::new(2, 0)),
2471 ..Default::default()
2472 },
2473 "2year",
2474 Year,
2475 ),
2476 (
2477 ParsedDateTime {
2478 month: Some(DateTimeFieldValue::new(2, 300_000_000)),
2479 ..Default::default()
2480 },
2481 "2.3month",
2482 Month,
2483 ),
2484 (
2485 ParsedDateTime {
2486 day: Some(DateTimeFieldValue::new(-2, -300_000_000)),
2487 ..Default::default()
2488 },
2489 "-2.3day",
2490 Day,
2491 ),
2492 (
2493 ParsedDateTime {
2494 hour: Some(DateTimeFieldValue::new(2, 0)),
2495 ..Default::default()
2496 },
2497 "2hour",
2498 Hour,
2499 ),
2500 (
2501 ParsedDateTime {
2502 minute: Some(DateTimeFieldValue::new(2, 300_000_000)),
2503 ..Default::default()
2504 },
2505 "2.3minute",
2506 Minute,
2507 ),
2508 (
2509 ParsedDateTime {
2510 second: Some(DateTimeFieldValue::new(-2, -300_000_000)),
2511 ..Default::default()
2512 },
2513 "-2.3second",
2514 Second,
2515 ),
2516 (
2517 ParsedDateTime {
2518 second: Some(DateTimeFieldValue::new(-2, -300_000_000)),
2519 ..Default::default()
2520 },
2521 ":::::::::-2.3second",
2522 Second,
2523 ),
2524 (
2525 ParsedDateTime {
2526 second: Some(DateTimeFieldValue::new(2, 300_000_000)),
2527 ..Default::default()
2528 },
2529 ":::::::::+2.3second",
2530 Second,
2531 ),
2532 (
2533 ParsedDateTime {
2534 millisecond: Some(DateTimeFieldValue::new(1, 200_000_000)),
2535 ..Default::default()
2536 },
2537 "1.2milliseconds",
2538 Milliseconds,
2539 ),
2540 (
2541 ParsedDateTime {
2542 microsecond: Some(DateTimeFieldValue::new(2, 300_000_000)),
2543 ..Default::default()
2544 },
2545 "2.3microseconds",
2546 Microseconds,
2547 ),
2548 (
2549 ParsedDateTime {
2550 millennium: Some(DateTimeFieldValue::new(4, 500_000_000)),
2551 ..Default::default()
2552 },
2553 "4.5millennium",
2554 Millennium,
2555 ),
2556 (
2557 ParsedDateTime {
2558 century: Some(DateTimeFieldValue::new(6, 700_000_000)),
2559 ..Default::default()
2560 },
2561 "6.7century",
2562 Century,
2563 ),
2564 (
2565 ParsedDateTime {
2566 decade: Some(DateTimeFieldValue::new(8, 900_000_000)),
2567 ..Default::default()
2568 },
2569 "8.9decade",
2570 Decade,
2571 ),
2572 ];
2573 for test in test_cases.iter() {
2574 let mut pdt = ParsedDateTime::default();
2575 let mut actual = tokenize_time_str(test.1).unwrap();
2576 fill_pdt_interval_pg(&mut actual, test.2, &mut pdt).unwrap();
2577
2578 assert_eq!(pdt, test.0);
2579 }
2580 }
2581
2582 #[mz_ore::test]
2583 fn fill_pdt_interval_pg_errors() {
2584 use DateTimeField::*;
2585 let test_cases = [
2586 (
2588 "1.2.",
2589 Month,
2590 "Invalid syntax at offset 3: provided Dot but expected TimeUnit(Year)",
2591 ),
2592 (
2595 "1YEAR",
2596 Month,
2597 "Invalid syntax at offset 1: provided TimeUnit(YEAR) but expected TimeUnit(MONTH)",
2598 ),
2599 ];
2600 for test in test_cases.iter() {
2601 let mut pdt = ParsedDateTime::default();
2602 let mut actual = tokenize_time_str(test.0).unwrap();
2603 match fill_pdt_interval_pg(&mut actual, test.1, &mut pdt) {
2604 Err(e) => assert_eq!(e.to_string(), test.2),
2605 Ok(_) => panic!(
2606 "Test passed when expected to fail, generated {:?}, expected error {}",
2607 pdt, test.2,
2608 ),
2609 };
2610 }
2611 }
2612
2613 #[mz_ore::test]
2614 fn test_fill_pdt_interval_sql() {
2615 use DateTimeField::*;
2616 let test_cases = [
2617 (
2618 ParsedDateTime {
2619 year: Some(DateTimeFieldValue::new(1, 0)),
2620 month: Some(DateTimeFieldValue::new(2, 0)),
2621 ..Default::default()
2622 },
2623 "1-2",
2624 Year,
2625 ),
2626 (
2627 ParsedDateTime {
2628 hour: Some(DateTimeFieldValue::new(1, 0)),
2629 minute: Some(DateTimeFieldValue::new(2, 0)),
2630 second: Some(DateTimeFieldValue::new(3, 400_000_000)),
2631 ..Default::default()
2632 },
2633 "1:2:3.4",
2634 Hour,
2635 ),
2636 (
2637 ParsedDateTime {
2638 hour: Some(DateTimeFieldValue::new(1, 0)),
2639 minute: Some(DateTimeFieldValue::new(0, 0)),
2640 second: Some(DateTimeFieldValue::new(3, 400_000_000)),
2641 ..Default::default()
2642 },
2643 "1::3.4",
2644 Hour,
2645 ),
2646 (
2647 ParsedDateTime {
2648 hour: Some(DateTimeFieldValue::new(1, 0)),
2649 minute: Some(DateTimeFieldValue::new(0, 0)),
2650 second: Some(DateTimeFieldValue::new(0, 400_000_000)),
2651 ..Default::default()
2652 },
2653 "1::.4",
2654 Hour,
2655 ),
2656 (
2657 ParsedDateTime {
2658 hour: Some(DateTimeFieldValue::new(0, 0)),
2659 minute: Some(DateTimeFieldValue::new(0, 0)),
2660 second: Some(DateTimeFieldValue::new(0, 400_000_000)),
2661 ..Default::default()
2662 },
2663 ".4",
2664 Second,
2665 ),
2666 (
2667 ParsedDateTime {
2668 hour: Some(DateTimeFieldValue::new(0, 0)),
2669 minute: Some(DateTimeFieldValue::new(1, 0)),
2670 second: Some(DateTimeFieldValue::new(2, 300_000_000)),
2671 ..Default::default()
2672 },
2673 "1:2.3",
2674 Minute,
2675 ),
2676 (
2677 ParsedDateTime {
2678 year: Some(DateTimeFieldValue::new(-1, 0)),
2679 month: Some(DateTimeFieldValue::new(-2, 0)),
2680 ..Default::default()
2681 },
2682 "-1-2",
2683 Year,
2684 ),
2685 (
2686 ParsedDateTime {
2687 hour: Some(DateTimeFieldValue::new(-1, 0)),
2688 minute: Some(DateTimeFieldValue::new(-2, 0)),
2689 second: Some(DateTimeFieldValue::new(-3, -400_000_000)),
2690 ..Default::default()
2691 },
2692 "-1:2:3.4",
2693 Hour,
2694 ),
2695 (
2696 ParsedDateTime {
2697 year: Some(DateTimeFieldValue::new(1, 0)),
2698 month: Some(DateTimeFieldValue::new(2, 0)),
2699 ..Default::default()
2700 },
2701 "+1-2",
2702 Year,
2703 ),
2704 (
2705 ParsedDateTime {
2706 hour: Some(DateTimeFieldValue::new(1, 0)),
2707 minute: Some(DateTimeFieldValue::new(2, 0)),
2708 second: Some(DateTimeFieldValue::new(3, 400_000_000)),
2709 ..Default::default()
2710 },
2711 "+1:2:3.4",
2712 Hour,
2713 ),
2714 (
2715 ParsedDateTime {
2716 year: Some(DateTimeFieldValue::new(-1, 0)),
2717 month: Some(DateTimeFieldValue::new(-2, 0)),
2718 ..Default::default()
2719 },
2720 "::::::-1-2",
2721 Year,
2722 ),
2723 (
2724 ParsedDateTime {
2725 hour: Some(DateTimeFieldValue::new(-1, 0)),
2726 minute: Some(DateTimeFieldValue::new(-2, 0)),
2727 second: Some(DateTimeFieldValue::new(-3, -400_000_000)),
2728 ..Default::default()
2729 },
2730 ":::::::-1:2:3.4",
2731 Hour,
2732 ),
2733 ];
2734 for test in test_cases.iter() {
2735 let mut pdt = ParsedDateTime::default();
2736 let mut actual = tokenize_time_str(test.1).unwrap();
2737 fill_pdt_interval_sql(&mut actual, test.2, &mut pdt).unwrap();
2738
2739 assert_eq!(pdt, test.0);
2740 }
2741 }
2742
2743 #[mz_ore::test]
2744 fn test_fill_pdt_interval_sql_errors() {
2745 use DateTimeField::*;
2746 let test_cases = [
2747 (
2749 "1.2",
2750 Year,
2751 "Invalid syntax at offset 1: provided Dot but expected Dash",
2752 ),
2753 (
2754 "1-2:3.4",
2755 Minute,
2756 "Invalid syntax at offset 1: provided Dash but expected Colon",
2757 ),
2758 (
2759 "1YEAR",
2760 Year,
2761 "Invalid syntax at offset 1: provided TimeUnit(Year) but expected Dash",
2762 ),
2763 ];
2764 for test in test_cases.iter() {
2765 let mut pdt = ParsedDateTime::default();
2766 let mut actual = tokenize_time_str(test.0).unwrap();
2767 match fill_pdt_interval_sql(&mut actual, test.1, &mut pdt) {
2768 Err(e) => assert_eq!(e.to_string(), test.2),
2769 Ok(_) => panic!("Test passed when expected to fail, generated {:?}", pdt),
2770 };
2771 }
2772 }
2773
2774 #[mz_ore::test]
2775 fn test_build_parsed_datetime_time() {
2776 run_test_build_parsed_datetime_time(
2777 "3:4:5.6",
2778 ParsedDateTime {
2779 hour: Some(DateTimeFieldValue::new(3, 0)),
2780 minute: Some(DateTimeFieldValue::new(4, 0)),
2781 second: Some(DateTimeFieldValue::new(5, 600_000_000)),
2782 ..Default::default()
2783 },
2784 );
2785 run_test_build_parsed_datetime_time(
2786 "3:4",
2787 ParsedDateTime {
2788 hour: Some(DateTimeFieldValue::new(3, 0)),
2789 minute: Some(DateTimeFieldValue::new(4, 0)),
2790 ..Default::default()
2791 },
2792 );
2793 run_test_build_parsed_datetime_time(
2794 "3:4.5",
2795 ParsedDateTime {
2796 minute: Some(DateTimeFieldValue::new(3, 0)),
2797 second: Some(DateTimeFieldValue::new(4, 500_000_000)),
2798 ..Default::default()
2799 },
2800 );
2801 run_test_build_parsed_datetime_time(
2802 "0::4.5",
2803 ParsedDateTime {
2804 hour: Some(DateTimeFieldValue::new(0, 0)),
2805 second: Some(DateTimeFieldValue::new(4, 500_000_000)),
2806 ..Default::default()
2807 },
2808 );
2809 run_test_build_parsed_datetime_time(
2810 "0::.5",
2811 ParsedDateTime {
2812 hour: Some(DateTimeFieldValue::new(0, 0)),
2813 second: Some(DateTimeFieldValue::new(0, 500_000_000)),
2814 ..Default::default()
2815 },
2816 );
2817
2818 fn run_test_build_parsed_datetime_time(test: &str, res: ParsedDateTime) {
2819 assert_eq!(
2820 ParsedDateTime::build_parsed_datetime_time(test).unwrap(),
2821 res
2822 );
2823 }
2824 }
2825
2826 #[mz_ore::test]
2827 fn test_build_parsed_datetime_timestamp() {
2828 run_test_build_parsed_datetime_timestamp(
2829 "2000-01-02",
2830 ParsedDateTime {
2831 year: Some(DateTimeFieldValue::new(2000, 0)),
2832 month: Some(DateTimeFieldValue::new(1, 0)),
2833 day: Some(DateTimeFieldValue::new(2, 0)),
2834 ..Default::default()
2835 },
2836 );
2837 run_test_build_parsed_datetime_timestamp(
2838 "2000",
2839 ParsedDateTime {
2840 year: Some(DateTimeFieldValue::new(2000, 0)),
2841 ..Default::default()
2842 },
2843 );
2844 run_test_build_parsed_datetime_timestamp(
2845 "2000-1-",
2846 ParsedDateTime {
2847 year: Some(DateTimeFieldValue::new(2000, 0)),
2848 month: Some(DateTimeFieldValue::new(1, 0)),
2849 ..Default::default()
2850 },
2851 );
2852 run_test_build_parsed_datetime_timestamp(
2853 "2000-01-02 3:4:5.6",
2854 ParsedDateTime {
2855 year: Some(DateTimeFieldValue::new(2000, 0)),
2856 month: Some(DateTimeFieldValue::new(1, 0)),
2857 day: Some(DateTimeFieldValue::new(2, 0)),
2858 hour: Some(DateTimeFieldValue::new(3, 0)),
2859 minute: Some(DateTimeFieldValue::new(4, 0)),
2860 second: Some(DateTimeFieldValue::new(5, 600_000_000)),
2861 ..Default::default()
2862 },
2863 );
2864 run_test_build_parsed_datetime_timestamp(
2865 "2000-01-02T3:4:5.6",
2866 ParsedDateTime {
2867 year: Some(DateTimeFieldValue::new(2000, 0)),
2868 month: Some(DateTimeFieldValue::new(1, 0)),
2869 day: Some(DateTimeFieldValue::new(2, 0)),
2870 hour: Some(DateTimeFieldValue::new(3, 0)),
2871 minute: Some(DateTimeFieldValue::new(4, 0)),
2872 second: Some(DateTimeFieldValue::new(5, 600_000_000)),
2873 ..Default::default()
2874 },
2875 );
2876
2877 fn run_test_build_parsed_datetime_timestamp(test: &str, res: ParsedDateTime) {
2878 assert_eq!(
2879 ParsedDateTime::build_parsed_datetime_timestamp(test, CalendarEra::AD).unwrap(),
2880 res
2881 );
2882 }
2883 }
2884
2885 #[mz_ore::test]
2886 fn test_build_parsed_datetime_interval() {
2887 use DateTimeField::*;
2888 let test_cases = [
2889 (
2890 ParsedDateTime {
2891 year: Some(DateTimeFieldValue::new(1, 0)),
2892 month: Some(DateTimeFieldValue::new(2, 0)),
2893 day: Some(DateTimeFieldValue::new(3, 0)),
2894 hour: Some(DateTimeFieldValue::new(4, 0)),
2895 minute: Some(DateTimeFieldValue::new(5, 0)),
2896 second: Some(DateTimeFieldValue::new(6, 700_000_000)),
2897 ..Default::default()
2898 },
2899 "1-2 3 4:5:6.7",
2900 Second,
2901 ),
2902 (
2903 ParsedDateTime {
2904 year: Some(DateTimeFieldValue::new(1, 0)),
2905 month: Some(DateTimeFieldValue::new(2, 0)),
2906 day: Some(DateTimeFieldValue::new(3, 0)),
2907 hour: Some(DateTimeFieldValue::new(4, 0)),
2908 minute: Some(DateTimeFieldValue::new(5, 0)),
2909 second: Some(DateTimeFieldValue::new(6, 700_000_000)),
2910 ..Default::default()
2911 },
2912 "1 year 2 months 3 days 4 hours 5 minutes 6.7 seconds",
2913 Second,
2914 ),
2915 (
2916 ParsedDateTime {
2917 second: Some(DateTimeFieldValue::new(1, 0)),
2918 ..Default::default()
2919 },
2920 "1",
2921 Second,
2922 ),
2923 (
2924 ParsedDateTime {
2925 day: Some(DateTimeFieldValue::new(1, 0)),
2926 ..Default::default()
2927 },
2928 "1",
2929 Day,
2930 ),
2931 (
2932 ParsedDateTime {
2933 month: Some(DateTimeFieldValue::new(1, 0)),
2934 ..Default::default()
2935 },
2936 "1",
2937 Month,
2938 ),
2939 (
2940 ParsedDateTime {
2941 hour: Some(DateTimeFieldValue::new(1, 0)),
2942 minute: Some(DateTimeFieldValue::new(0, 0)),
2943 second: Some(DateTimeFieldValue::new(0, 0)),
2944 ..Default::default()
2945 },
2946 "1:",
2947 Second,
2948 ),
2949 (
2950 ParsedDateTime {
2951 year: Some(DateTimeFieldValue::new(1, 0)),
2952 month: Some(DateTimeFieldValue::new(0, 0)),
2953 ..Default::default()
2954 },
2955 "1-",
2956 Second,
2957 ),
2958 (
2959 ParsedDateTime {
2960 day: Some(DateTimeFieldValue::new(1, 0)),
2961 hour: Some(DateTimeFieldValue::new(2, 0)),
2962 minute: Some(DateTimeFieldValue::new(0, 0)),
2963 second: Some(DateTimeFieldValue::new(0, 0)),
2964 ..Default::default()
2965 },
2966 "1 2:",
2967 Second,
2968 ),
2969 (
2970 ParsedDateTime {
2971 year: Some(DateTimeFieldValue::new(1, 0)),
2972 month: Some(DateTimeFieldValue::new(2, 0)),
2973 hour: Some(DateTimeFieldValue::new(3, 0)),
2974 minute: Some(DateTimeFieldValue::new(4, 0)),
2975 second: Some(DateTimeFieldValue::new(0, 0)),
2976 ..Default::default()
2977 },
2978 "1-2 3:4",
2979 Second,
2980 ),
2981 (
2982 ParsedDateTime {
2983 year: Some(DateTimeFieldValue::new(1, 0)),
2984 month: Some(DateTimeFieldValue::new(0, 0)),
2985 day: Some(DateTimeFieldValue::new(2, 0)),
2986 hour: Some(DateTimeFieldValue::new(3, 0)),
2987 minute: Some(DateTimeFieldValue::new(0, 0)),
2988 second: Some(DateTimeFieldValue::new(0, 0)),
2989 ..Default::default()
2990 },
2991 "1- 2 3:",
2992 Second,
2993 ),
2994 (
2995 ParsedDateTime {
2996 year: Some(DateTimeFieldValue::new(5, 0)),
2997 month: Some(DateTimeFieldValue::new(6, 0)),
2998 hour: Some(DateTimeFieldValue::new(1, 0)),
2999 minute: Some(DateTimeFieldValue::new(2, 0)),
3000 second: Some(DateTimeFieldValue::new(3, 400_000_000)),
3001 ..Default::default()
3002 },
3003 "1:2:3.4 5-6",
3004 Second,
3005 ),
3006 (
3007 ParsedDateTime {
3008 year: Some(DateTimeFieldValue::new(1, 0)),
3009 month: Some(DateTimeFieldValue::new(2, 0)),
3010 hour: Some(DateTimeFieldValue::new(3, 0)),
3011 ..Default::default()
3012 },
3013 "1-2 3",
3014 Hour,
3015 ),
3016 (
3017 ParsedDateTime {
3018 year: Some(DateTimeFieldValue::new(-1, 0)),
3019 month: Some(DateTimeFieldValue::new(-2, 0)),
3020 day: Some(DateTimeFieldValue::new(-3, 0)),
3021 hour: Some(DateTimeFieldValue::new(-4, 0)),
3022 minute: Some(DateTimeFieldValue::new(-5, 0)),
3023 second: Some(DateTimeFieldValue::new(-6, -700_000_000)),
3024 ..Default::default()
3025 },
3026 "-1-2 -3 -4:5:6.7",
3027 Second,
3028 ),
3029 (
3030 ParsedDateTime {
3031 year: Some(DateTimeFieldValue::new(-1, 0)),
3032 month: Some(DateTimeFieldValue::new(-2, 0)),
3033 day: Some(DateTimeFieldValue::new(3, 0)),
3034 hour: Some(DateTimeFieldValue::new(-4, 0)),
3035 minute: Some(DateTimeFieldValue::new(-5, 0)),
3036 second: Some(DateTimeFieldValue::new(-6, -700_000_000)),
3037 ..Default::default()
3038 },
3039 "-1-2 3 -4:5:6.7",
3040 Second,
3041 ),
3042 (
3043 ParsedDateTime {
3044 year: Some(DateTimeFieldValue::new(-1, 0)),
3045 month: Some(DateTimeFieldValue::new(-2, 0)),
3046 day: Some(DateTimeFieldValue::new(-3, 0)),
3047 hour: Some(DateTimeFieldValue::new(4, 0)),
3048 minute: Some(DateTimeFieldValue::new(0, 0)),
3049 second: Some(DateTimeFieldValue::new(0, 500_000_000)),
3050 ..Default::default()
3051 },
3052 "-1-2 -3 4::.5",
3053 Second,
3054 ),
3055 (
3056 ParsedDateTime {
3057 hour: Some(DateTimeFieldValue::new(0, 0)),
3058 minute: Some(DateTimeFieldValue::new(0, 0)),
3059 second: Some(DateTimeFieldValue::new(-1, -270_000_000)),
3060 ..Default::default()
3061 },
3062 "-::1.27",
3063 Second,
3064 ),
3065 (
3066 ParsedDateTime {
3067 second: Some(DateTimeFieldValue::new(1, 270_000_000)),
3068 ..Default::default()
3069 },
3070 ":::::1.27",
3071 Second,
3072 ),
3073 (
3074 ParsedDateTime {
3075 year: Some(DateTimeFieldValue::new(1, 0)),
3076 month: Some(DateTimeFieldValue::new(0, 0)),
3077 day: Some(DateTimeFieldValue::new(2, 0)),
3078 hour: Some(DateTimeFieldValue::new(3, 0)),
3079 minute: Some(DateTimeFieldValue::new(0, 0)),
3080 second: Some(DateTimeFieldValue::new(0, 0)),
3081 ..Default::default()
3082 },
3083 ":::1- ::2 ::::3:",
3084 Second,
3085 ),
3086 (
3087 ParsedDateTime {
3088 year: Some(DateTimeFieldValue::new(1, 0)),
3089 month: Some(DateTimeFieldValue::new(2, 0)),
3090 day: Some(DateTimeFieldValue::new(3, 0)),
3091 hour: Some(DateTimeFieldValue::new(4, 0)),
3092 minute: Some(DateTimeFieldValue::new(5, 0)),
3093 second: Some(DateTimeFieldValue::new(6, 700_000_000)),
3094 ..Default::default()
3095 },
3096 "1 years 2 months 3 days 4 hours 5 minutes 6.7 seconds",
3097 Second,
3098 ),
3099 (
3100 ParsedDateTime {
3101 year: Some(DateTimeFieldValue::new(1, 0)),
3102 month: Some(DateTimeFieldValue::new(2, 0)),
3103 day: Some(DateTimeFieldValue::new(3, 0)),
3104 hour: Some(DateTimeFieldValue::new(4, 0)),
3105 minute: Some(DateTimeFieldValue::new(5, 0)),
3106 second: Some(DateTimeFieldValue::new(6, 700_000_000)),
3107 ..Default::default()
3108 },
3109 "1y 2mon 3d 4h 5m 6.7s",
3110 Second,
3111 ),
3112 (
3113 ParsedDateTime {
3114 year: Some(DateTimeFieldValue::new(1, 0)),
3115 month: Some(DateTimeFieldValue::new(2, 0)),
3116 day: Some(DateTimeFieldValue::new(3, 0)),
3117 hour: Some(DateTimeFieldValue::new(4, 0)),
3118 minute: Some(DateTimeFieldValue::new(5, 0)),
3119 second: Some(DateTimeFieldValue::new(6, 700_000_000)),
3120 ..Default::default()
3121 },
3122 "6.7 seconds 5 minutes 3 days 4 hours 1 year 2 month",
3123 Second,
3124 ),
3125 (
3126 ParsedDateTime {
3127 year: Some(DateTimeFieldValue::new(-1, 0)),
3128 month: Some(DateTimeFieldValue::new(2, 0)),
3129 day: Some(DateTimeFieldValue::new(-3, 0)),
3130 hour: Some(DateTimeFieldValue::new(4, 0)),
3131 minute: Some(DateTimeFieldValue::new(5, 0)),
3132 second: Some(DateTimeFieldValue::new(-6, -700_000_000)),
3133 ..Default::default()
3134 },
3135 "-6.7 seconds 5 minutes -3 days 4 hours -1 year 2 month",
3136 Second,
3137 ),
3138 (
3139 ParsedDateTime {
3140 year: Some(DateTimeFieldValue::new(1, 0)),
3141 month: Some(DateTimeFieldValue::new(2, 300_000_000)),
3142 day: Some(DateTimeFieldValue::new(4, 500_000_000)),
3143 ..Default::default()
3144 },
3145 "1y 2.3mon 4.5d",
3146 Second,
3147 ),
3148 (
3149 ParsedDateTime {
3150 year: Some(DateTimeFieldValue::new(-1, -200_000_000)),
3151 month: Some(DateTimeFieldValue::new(2, 300_000_000)),
3152 day: Some(DateTimeFieldValue::new(-3, -400_000_000)),
3153 hour: Some(DateTimeFieldValue::new(4, 500_000_000)),
3154 minute: Some(DateTimeFieldValue::new(5, 600_000_000)),
3155 second: Some(DateTimeFieldValue::new(-6, -700_000_000)),
3156 ..Default::default()
3157 },
3158 "-6.7 seconds 5.6 minutes -3.4 days 4.5 hours -1.2 year 2.3 month",
3159 Second,
3160 ),
3161 (
3162 ParsedDateTime {
3163 day: Some(DateTimeFieldValue::new(1, 0)),
3164 second: Some(DateTimeFieldValue::new(0, -270_000_000)),
3165 ..Default::default()
3166 },
3167 "1 day -0.27 seconds",
3168 Second,
3169 ),
3170 (
3171 ParsedDateTime {
3172 day: Some(DateTimeFieldValue::new(-1, 0)),
3173 second: Some(DateTimeFieldValue::new(0, 270_000_000)),
3174 ..Default::default()
3175 },
3176 "-1 day 0.27 seconds",
3177 Second,
3178 ),
3179 (
3180 ParsedDateTime {
3181 year: Some(DateTimeFieldValue::new(10, 333_000_000)),
3182 ..Default::default()
3183 },
3184 "10.333 years",
3185 Second,
3186 ),
3187 (
3188 ParsedDateTime {
3189 year: Some(DateTimeFieldValue::new(10, 333_000_000)),
3190 ..Default::default()
3191 },
3192 "10.333",
3193 Year,
3194 ),
3195 (
3196 ParsedDateTime {
3197 year: Some(DateTimeFieldValue::new(1, 0)),
3198 month: Some(DateTimeFieldValue::new(2, 0)),
3199 day: Some(DateTimeFieldValue::new(5, 0)),
3200 hour: Some(DateTimeFieldValue::new(3, 0)),
3201 minute: Some(DateTimeFieldValue::new(4, 0)),
3202 second: Some(DateTimeFieldValue::new(0, 0)),
3203 ..Default::default()
3204 },
3205 "1-2 3:4 5 day",
3206 Second,
3207 ),
3208 (
3209 ParsedDateTime {
3210 year: Some(DateTimeFieldValue::new(1, 0)),
3211 month: Some(DateTimeFieldValue::new(2, 0)),
3212 day: Some(DateTimeFieldValue::new(5, 0)),
3213 hour: Some(DateTimeFieldValue::new(3, 0)),
3214 minute: Some(DateTimeFieldValue::new(4, 0)),
3215 second: Some(DateTimeFieldValue::new(0, 0)),
3216 ..Default::default()
3217 },
3218 "5 day 3:4 1-2",
3219 Second,
3220 ),
3221 (
3222 ParsedDateTime {
3223 year: Some(DateTimeFieldValue::new(1, 0)),
3224 month: Some(DateTimeFieldValue::new(2, 0)),
3225 day: Some(DateTimeFieldValue::new(5, 0)),
3226 hour: Some(DateTimeFieldValue::new(3, 0)),
3227 minute: Some(DateTimeFieldValue::new(4, 0)),
3228 second: Some(DateTimeFieldValue::new(0, 0)),
3229 ..Default::default()
3230 },
3231 "1-2 5 day 3:4",
3232 Second,
3233 ),
3234 (
3235 ParsedDateTime {
3236 year: Some(DateTimeFieldValue::new(1, 0)),
3237 day: Some(DateTimeFieldValue::new(2, 0)),
3238 hour: Some(DateTimeFieldValue::new(3, 0)),
3239 minute: Some(DateTimeFieldValue::new(4, 0)),
3240 second: Some(DateTimeFieldValue::new(5, 600_000_000)),
3241 ..Default::default()
3242 },
3243 "+1 year +2 days +3:4:5.6",
3244 Second,
3245 ),
3246 (
3247 ParsedDateTime {
3248 year: Some(DateTimeFieldValue::new(1, 0)),
3249 month: Some(DateTimeFieldValue::new(2, 0)),
3250 ..Default::default()
3251 },
3252 "1-2",
3253 Month,
3254 ),
3255 (
3256 ParsedDateTime {
3257 year: Some(DateTimeFieldValue::new(1, 0)),
3258 month: Some(DateTimeFieldValue::new(2, 0)),
3259 ..Default::default()
3260 },
3261 "1-2",
3262 Minute,
3263 ),
3264 (
3265 ParsedDateTime {
3266 day: Some(DateTimeFieldValue::new(1, 999_999_999)),
3267 ..Default::default()
3268 },
3269 "1.999999999999999999 days",
3270 Second,
3271 ),
3272 (
3273 ParsedDateTime {
3274 millisecond: Some(DateTimeFieldValue::new(1, 200_000_000)),
3275 ..Default::default()
3276 },
3277 "1.2ms",
3278 Second,
3279 ),
3280 (
3281 ParsedDateTime {
3282 millisecond: Some(DateTimeFieldValue::new(1, 0)),
3283 ..Default::default()
3284 },
3285 "1ms",
3286 Second,
3287 ),
3288 (
3289 ParsedDateTime {
3290 millisecond: Some(DateTimeFieldValue::new(2100, 0)),
3291 ..Default::default()
3292 },
3293 "2100ms",
3294 Second,
3295 ),
3296 (
3297 ParsedDateTime {
3298 hour: Some(DateTimeFieldValue::new(1, 0)),
3299 millisecond: Some(DateTimeFieldValue::new(2, 0)),
3300 ..Default::default()
3301 },
3302 "1h 2ms",
3303 Second,
3304 ),
3305 (
3306 ParsedDateTime {
3307 millisecond: Some(DateTimeFieldValue::new(42, 900_000_000)),
3308 ..Default::default()
3309 },
3310 "42.9 milliseconds",
3311 Second,
3312 ),
3313 (
3314 ParsedDateTime {
3315 second: Some(DateTimeFieldValue::new(5, 0)),
3316 millisecond: Some(DateTimeFieldValue::new(37, 660_000_000)),
3317 ..Default::default()
3318 },
3319 "5.0 seconds 37.66 milliseconds",
3320 Second,
3321 ),
3322 (
3323 ParsedDateTime {
3324 day: Some(DateTimeFieldValue::new(14, 0)),
3325 millisecond: Some(DateTimeFieldValue::new(60, 0)),
3326 ..Default::default()
3327 },
3328 "14 days 60 ms",
3329 Second,
3330 ),
3331 (
3332 ParsedDateTime {
3333 microsecond: Some(DateTimeFieldValue::new(42, 900_000_000)),
3334 ..Default::default()
3335 },
3336 "42.9 microseconds",
3337 Second,
3338 ),
3339 (
3340 ParsedDateTime {
3341 second: Some(DateTimeFieldValue::new(5, 0)),
3342 microsecond: Some(DateTimeFieldValue::new(37, 660_000_000)),
3343 ..Default::default()
3344 },
3345 "5.0 seconds 37.66 microseconds",
3346 Second,
3347 ),
3348 (
3349 ParsedDateTime {
3350 millennium: Some(DateTimeFieldValue::new(9, 800_000_000)),
3351 ..Default::default()
3352 },
3353 "9.8 millenniums",
3354 Second,
3355 ),
3356 (
3357 ParsedDateTime {
3358 century: Some(DateTimeFieldValue::new(7, 600_000_000)),
3359 ..Default::default()
3360 },
3361 "7.6 centuries",
3362 Second,
3363 ),
3364 (
3365 ParsedDateTime {
3366 decade: Some(DateTimeFieldValue::new(5, 400_000_000)),
3367 ..Default::default()
3368 },
3369 "5.4 decades",
3370 Second,
3371 ),
3372 (
3373 ParsedDateTime {
3374 year: Some(DateTimeFieldValue::new(1, 200_000_000)),
3375 decade: Some(DateTimeFieldValue::new(4, 300_000_000)),
3376 century: Some(DateTimeFieldValue::new(5, 600_000_000)),
3377 millennium: Some(DateTimeFieldValue::new(8, 700_000_000)),
3378 ..Default::default()
3379 },
3380 "8.7 mils 5.6 cent 4.3 decs 1.2 y",
3381 Second,
3382 ),
3383 ];
3384
3385 for test in test_cases.iter() {
3386 let actual =
3387 ParsedDateTime::build_parsed_datetime_interval(test.1, None, test.2).unwrap();
3388 if actual != test.0 {
3389 panic!(
3390 "In test INTERVAL '{}' {}\n actual: {:?} \n expected: {:?}",
3391 test.1, test.2, actual, test.0
3392 );
3393 }
3394 }
3395 }
3396
3397 #[mz_ore::test]
3398 fn test_build_parsed_datetime_interval_errors() {
3399 use DateTimeField::*;
3400 let test_cases = [
3401 ("1 year 2 years", Second, "YEAR field set twice"),
3402 ("1-2 3-4", Second, "YEAR or MONTH field set twice"),
3403 ("1-2 3 year", Second, "YEAR field set twice"),
3404 ("1-2 3", Month, "MONTH field set twice"),
3405 ("1-2 3:4 5", Second, "SECOND field set twice"),
3406 ("1:2:3.4 5-6 7", Year, "YEAR field set twice"),
3407 ("-:::::1.27", Second, "have unprocessed tokens 1.270000000"),
3408 (
3409 "-1 ::.27",
3410 Second,
3411 "Cannot determine format of all parts. Add explicit time components, e.g. \
3412 INTERVAL '1 day' or INTERVAL '1' DAY",
3413 ),
3414 ("1:2:3.4.5", Second, "have unprocessed tokens .500000000"),
3415 ("1+2:3.4", Second, "Cannot determine format of all parts"),
3416 ("1x2:3.4", Second, "unknown units x"),
3417 ("0 foo", Second, "unknown units foo"),
3418 ("1-2 3:4 5 second", Second, "SECOND field set twice"),
3419 (
3420 "1-2 5 second 3:4",
3421 Second,
3422 "HOUR, MINUTE, SECOND field set twice",
3423 ),
3424 (
3425 "1 2-3 4:5",
3426 Day,
3427 "Cannot determine format of all parts. Add explicit time components, e.g. \
3428 INTERVAL '1 day' or INTERVAL '1' DAY",
3429 ),
3430 (
3431 "9223372036854775808 months",
3432 Day,
3433 "Unable to parse value 9223372036854775808 as a number: number too large to fit in target type",
3434 ),
3435 (
3436 "-9223372036854775809 months",
3437 Day,
3438 "Unable to parse value 9223372036854775809 as a number: number too large to fit in target type",
3439 ),
3440 (
3441 "9223372036854775808 seconds",
3442 Day,
3443 "Unable to parse value 9223372036854775808 as a number: number too large to fit in target type",
3444 ),
3445 (
3446 "-9223372036854775809 seconds",
3447 Day,
3448 "Unable to parse value 9223372036854775809 as a number: number too large to fit in target type",
3449 ),
3450 (
3451 "1.234 second 5 ms",
3452 Second,
3453 "Cannot set MILLISECONDS or MICROSECONDS field if SECOND field has a fraction component",
3454 ),
3455 (
3456 "1.234 second 5 us",
3457 Second,
3458 "Cannot set MILLISECONDS or MICROSECONDS field if SECOND field has a fraction component",
3459 ),
3460 (
3461 "7 ms 4.321 second",
3462 Second,
3463 "Cannot set MILLISECONDS or MICROSECONDS field if SECOND field has a fraction component",
3464 ),
3465 (
3466 "7 us 4.321 second",
3467 Second,
3468 "Cannot set MILLISECONDS or MICROSECONDS field if SECOND field has a fraction component",
3469 ),
3470 ];
3471 for test in test_cases.iter() {
3472 match ParsedDateTime::build_parsed_datetime_interval(test.0, None, test.1) {
3473 Err(e) => assert_eq!(e.to_string(), test.2),
3474 Ok(pdt) => panic!(
3475 "Test INTERVAL '{}' {} passed when expected to fail with {}, generated ParsedDateTime {:?}",
3476 test.0, test.1, test.2, pdt,
3477 ),
3478 }
3479 }
3480 }
3481
3482 #[mz_ore::test]
3483 fn test_split_timestamp_string() {
3484 let test_cases = [
3485 (
3486 "1969-06-01 10:10:10.410 UTC",
3487 "1969-06-01 10:10:10.410",
3488 "UTC",
3489 ),
3490 (
3491 "1969-06-01 10:10:10.410+4:00",
3492 "1969-06-01 10:10:10.410",
3493 "+4:00",
3494 ),
3495 (
3496 "1969-06-01 10:10:10.410-4:00",
3497 "1969-06-01 10:10:10.410",
3498 "-4:00",
3499 ),
3500 ("1969-06-01 10:10:10.410", "1969-06-01 10:10:10.410", ""),
3501 ("1969-06-01 10:10:10.410+4", "1969-06-01 10:10:10.410", "+4"),
3502 ("1969-06-01 10:10:10.410-4", "1969-06-01 10:10:10.410", "-4"),
3503 ("1969-06-01 10:10:10+4:00", "1969-06-01 10:10:10", "+4:00"),
3504 ("1969-06-01 10:10:10-4:00", "1969-06-01 10:10:10", "-4:00"),
3505 ("1969-06-01 10:10:10 UTC", "1969-06-01 10:10:10", "UTC"),
3506 ("1969-06-01 10:10:10", "1969-06-01 10:10:10", ""),
3507 ("1969-06-01 10:10+4:00", "1969-06-01 10:10", "+4:00"),
3508 ("1969-06-01 10:10-4:00", "1969-06-01 10:10", "-4:00"),
3509 ("1969-06-01 10:10 UTC", "1969-06-01 10:10", "UTC"),
3510 ("1969-06-01 10:10", "1969-06-01 10:10", ""),
3511 ("1969-06-01 UTC", "1969-06-01", "UTC"),
3512 ("1969-06-01 +4:00", "1969-06-01", "+4:00"),
3513 ("1969-06-01 -4:00", "1969-06-01", "-4:00"),
3514 ("1969-06-01 +4", "1969-06-01", "+4"),
3515 ("1969-06-01 -4", "1969-06-01", "-4"),
3516 ("1969-06-01", "1969-06-01", ""),
3517 ("1969-06-01 10:10:10.410Z", "1969-06-01 10:10:10.410", "Z"),
3518 ("1969-06-01 10:10:10.410z", "1969-06-01 10:10:10.410", "z"),
3519 ("1969-06-01Z", "1969-06-01", "Z"),
3520 ("1969-06-01z", "1969-06-01", "z"),
3521 ("1969-06-01 10:10:10.410 ", "1969-06-01 10:10:10.410", ""),
3522 (
3523 "1969-06-01 10:10:10.410 ",
3524 "1969-06-01 10:10:10.410",
3525 "",
3526 ),
3527 (" 1969-06-01 10:10:10.412", "1969-06-01 10:10:10.412", ""),
3528 (
3529 " 1969-06-01 10:10:10.413 ",
3530 "1969-06-01 10:10:10.413",
3531 "",
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+4 :00",
3540 "1969-06-01 10:10:10.410",
3541 "+4 :00",
3542 ),
3543 (
3544 "1969-06-01 10:10:10.410 +4:00",
3545 "1969-06-01 10:10:10.410",
3546 "+4:00",
3547 ),
3548 (
3549 "1969-06-01 10:10:10.410+4:00 ",
3550 "1969-06-01 10:10:10.410",
3551 "+4:00",
3552 ),
3553 (
3554 "1969-06-01 10:10:10.410 Z ",
3555 "1969-06-01 10:10:10.410",
3556 "Z",
3557 ),
3558 ("1969-06-01 +4 ", "1969-06-01", "+4"),
3559 ("1969-06-01 Z ", "1969-06-01", "Z"),
3560 ];
3561
3562 for test in test_cases.iter() {
3563 let (ts, tz, era) = split_timestamp_string(test.0);
3564
3565 assert_eq!(ts, test.1);
3566 assert_eq!(tz, test.2);
3567 assert_eq!(era, CalendarEra::AD);
3568 }
3569 }
3570
3571 proptest! {
3572 #[mz_ore::test]
3573 #[cfg_attr(miri, ignore)] fn datetimeunits_serialization_roundtrip(expect in any::<DateTimeUnits>() ) {
3575 let actual = protobuf_roundtrip::<_, ProtoDateTimeUnits>(&expect);
3576 assert_ok!(actual);
3577 assert_eq!(actual.unwrap(), expect);
3578 }
3579 }
3580
3581 #[mz_ore::test]
3582 fn proptest_packed_naive_time_roundtrips() {
3583 let strat = add_arb_duration(NaiveTime::from_hms_opt(0, 0, 0).unwrap());
3584 proptest!(|(time in strat)| {
3585 let packed = PackedNaiveTime::from_value(time);
3586 let rnd = packed.into_value();
3587 prop_assert_eq!(time, rnd);
3588 });
3589 }
3590
3591 #[mz_ore::test]
3592 fn proptest_packed_naive_time_sort_order() {
3593 let time = add_arb_duration(NaiveTime::from_hms_opt(0, 0, 0).unwrap());
3594 let strat = proptest::collection::vec(time, 0..128);
3595 proptest!(|(mut times in strat)| {
3596 let mut packed: Vec<_> = times.iter().copied().map(PackedNaiveTime::from_value).collect();
3597
3598 times.sort();
3599 packed.sort();
3600
3601 for (time, packed) in times.into_iter().zip(packed.into_iter()) {
3602 let rnd = packed.into_value();
3603 prop_assert_eq!(time, rnd);
3604 }
3605 });
3606 }
3607}
3608
3609#[mz_ore::test]
3610fn test_parseddatetime_add_field() {
3611 use DateTimeField::*;
3612 let pdt_unit = ParsedDateTime {
3613 millennium: Some(DateTimeFieldValue::new(8, 0)),
3614 century: Some(DateTimeFieldValue::new(9, 0)),
3615 decade: Some(DateTimeFieldValue::new(10, 0)),
3616 year: Some(DateTimeFieldValue::new(1, 0)),
3617 month: Some(DateTimeFieldValue::new(2, 0)),
3618 day: Some(DateTimeFieldValue::new(2, 0)),
3619 hour: Some(DateTimeFieldValue::new(3, 0)),
3620 minute: Some(DateTimeFieldValue::new(4, 0)),
3621 second: Some(DateTimeFieldValue::new(5, 0)),
3622 millisecond: Some(DateTimeFieldValue::new(6, 0)),
3623 microsecond: Some(DateTimeFieldValue::new(7, 0)),
3624 ..Default::default()
3625 };
3626
3627 let pdt_frac = 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_frac_neg = ParsedDateTime {
3643 millennium: Some(DateTimeFieldValue::new(-8, -555_555_555)),
3644 century: Some(DateTimeFieldValue::new(-9, -555_555_555)),
3645 decade: Some(DateTimeFieldValue::new(-10, -555_555_555)),
3646 year: Some(DateTimeFieldValue::new(-1, -555_555_555)),
3647 month: Some(DateTimeFieldValue::new(-2, -555_555_555)),
3648 day: Some(DateTimeFieldValue::new(-2, -555_555_555)),
3649 hour: Some(DateTimeFieldValue::new(-3, -555_555_555)),
3650 minute: Some(DateTimeFieldValue::new(-4, -555_555_555)),
3651 second: Some(DateTimeFieldValue::new(-5, -555_555_555)),
3652 millisecond: Some(DateTimeFieldValue::new(-6, -555_555_555)),
3653 microsecond: Some(DateTimeFieldValue::new(-7, -555_555_555)),
3654 ..Default::default()
3655 };
3656
3657 let pdt_s_rollover = ParsedDateTime {
3658 millisecond: Some(DateTimeFieldValue::new(1002, 666_666_666)),
3659 microsecond: Some(DateTimeFieldValue::new(1000003, 777_777_777)),
3660 ..Default::default()
3661 };
3662
3663 run_test_parseddatetime_add_field(pdt_unit.clone(), Millennium, (8 * 12 * 1_000, 0, 0));
3664 run_test_parseddatetime_add_field(pdt_unit.clone(), Century, (9 * 12 * 100, 0, 0));
3665 run_test_parseddatetime_add_field(pdt_unit.clone(), Decade, (10 * 12 * 10, 0, 0));
3666 run_test_parseddatetime_add_field(pdt_unit.clone(), Year, (12, 0, 0));
3667 run_test_parseddatetime_add_field(pdt_unit.clone(), Month, (2, 0, 0));
3668 run_test_parseddatetime_add_field(pdt_unit.clone(), Day, (0, 2, 0));
3669 run_test_parseddatetime_add_field(pdt_unit.clone(), Hour, (0, 0, 3 * 60 * 60 * 1_000_000));
3670 run_test_parseddatetime_add_field(pdt_unit.clone(), Minute, (0, 0, 4 * 60 * 1_000_000));
3671 run_test_parseddatetime_add_field(pdt_unit.clone(), Second, (0, 0, 5 * 1_000_000));
3672 run_test_parseddatetime_add_field(pdt_unit.clone(), Milliseconds, (0, 0, 6 * 1_000));
3673 run_test_parseddatetime_add_field(pdt_unit, Microseconds, (0, 0, 7));
3674 run_test_parseddatetime_add_field(pdt_frac.clone(), Millennium, (102_666, 0, 0));
3675 run_test_parseddatetime_add_field(pdt_frac.clone(), Century, (11466, 0, 0));
3676 run_test_parseddatetime_add_field(pdt_frac.clone(), Decade, (1266, 0, 0));
3677 run_test_parseddatetime_add_field(pdt_frac.clone(), Year, (18, 0, 0));
3678 run_test_parseddatetime_add_field(
3679 pdt_frac.clone(),
3680 Month,
3681 (
3682 2,
3683 16,
3684 (15 * 60 * 60 * 1_000_000) + (59 * 60 * 1_000_000) + (59 * 1_000_000) + 998_560,
3686 ),
3687 );
3688 run_test_parseddatetime_add_field(
3689 pdt_frac.clone(),
3690 Day,
3691 (
3692 0,
3693 2,
3694 (13 * 60 * 60 * 1_000_000) + (19 * 60 * 1_000_000) + (59 * 1_000_000) + 999_952,
3696 ),
3697 );
3698 run_test_parseddatetime_add_field(
3699 pdt_frac.clone(),
3700 Hour,
3701 (
3702 0,
3703 0,
3704 (3 * 60 * 60 * 1_000_000) + (33 * 60 * 1_000_000) + (19 * 1_000_000) + 999_998,
3706 ),
3707 );
3708 run_test_parseddatetime_add_field(
3709 pdt_frac.clone(),
3710 Minute,
3711 (
3712 0,
3713 0,
3714 (4 * 60 * 1_000_000) + (33 * 1_000_000) + 333_333,
3716 ),
3717 );
3718 run_test_parseddatetime_add_field(
3719 pdt_frac.clone(),
3720 Second,
3721 (
3722 0,
3723 0,
3724 (5 * 1_000_000) + 555_556,
3726 ),
3727 );
3728 run_test_parseddatetime_add_field(
3729 pdt_frac.clone(),
3730 Milliseconds,
3731 (
3732 0, 0, 6_556,
3734 ),
3735 );
3736 run_test_parseddatetime_add_field(
3737 pdt_frac,
3738 Microseconds,
3739 (
3740 0, 0, 8,
3742 ),
3743 );
3744 run_test_parseddatetime_add_field(pdt_frac_neg.clone(), Year, (-18, 0, 0));
3745 run_test_parseddatetime_add_field(
3746 pdt_frac_neg.clone(),
3747 Month,
3748 (
3749 -2,
3750 -16,
3751 (-15 * 60 * 60 * 1_000_000) + (-59 * 60 * 1_000_000) + (-59 * 1_000_000) + -998_560,
3753 ),
3754 );
3755 run_test_parseddatetime_add_field(
3756 pdt_frac_neg.clone(),
3757 Day,
3758 (
3759 0,
3760 -2,
3761 (-13 * 60 * 60 * 1_000_000) + (-19 * 60 * 1_000_000) + (-59 * 1_000_000) + -999_952,
3763 ),
3764 );
3765 run_test_parseddatetime_add_field(
3766 pdt_frac_neg.clone(),
3767 Hour,
3768 (
3769 0,
3770 0,
3771 (-3 * 60 * 60 * 1_000_000) + (-33 * 60 * 1_000_000) + (-19 * 1_000_000) + -999_998,
3773 ),
3774 );
3775 run_test_parseddatetime_add_field(
3776 pdt_frac_neg.clone(),
3777 Minute,
3778 (
3779 0,
3780 0,
3781 (-4 * 60 * 1_000_000) + (-33 * 1_000_000) + -333_333,
3783 ),
3784 );
3785 run_test_parseddatetime_add_field(
3786 pdt_frac_neg.clone(),
3787 Second,
3788 (
3789 0,
3790 0,
3791 (-5 * 1_000_000) + -555_556,
3793 ),
3794 );
3795 run_test_parseddatetime_add_field(
3796 pdt_frac_neg.clone(),
3797 Milliseconds,
3798 (
3799 0, 0, -6_556,
3801 ),
3802 );
3803 run_test_parseddatetime_add_field(
3804 pdt_frac_neg,
3805 Microseconds,
3806 (
3807 0, 0, -8,
3809 ),
3810 );
3811 run_test_parseddatetime_add_field(
3812 pdt_s_rollover.clone(),
3813 Milliseconds,
3814 (
3815 0,
3816 0, (1 * 1_000_000) + 2_667,
3818 ),
3819 );
3820 run_test_parseddatetime_add_field(
3821 pdt_s_rollover,
3822 Microseconds,
3823 (
3824 0,
3825 0, (1 * 1_000_000) + 4,
3827 ),
3828 );
3829
3830 fn run_test_parseddatetime_add_field(
3831 pdt: ParsedDateTime,
3832 f: DateTimeField,
3833 expected: (i32, i32, i64),
3834 ) {
3835 let mut res = (0, 0, 0);
3836
3837 pdt.add_field(f, &mut res.0, &mut res.1, &mut res.2)
3838 .unwrap();
3839
3840 if res.0 != expected.0 || res.1 != expected.1 || res.2 != expected.2 {
3841 panic!(
3842 "test_parseddatetime_add_field failed \n actual: {:?} \n expected: {:?}",
3843 res, expected
3844 );
3845 }
3846 }
3847}
3848
3849#[mz_ore::test]
3850fn test_parseddatetime_compute_interval() {
3851 run_test_parseddatetime_compute_interval(
3852 ParsedDateTime {
3853 year: Some(DateTimeFieldValue::new(1, 0)),
3854 month: Some(DateTimeFieldValue::new(1, 0)),
3855 ..Default::default()
3856 },
3857 Interval {
3858 months: 13,
3859 ..Default::default()
3860 },
3861 );
3862 run_test_parseddatetime_compute_interval(
3863 ParsedDateTime {
3864 year: Some(DateTimeFieldValue::new(1, 0)),
3865 month: Some(DateTimeFieldValue::new(-1, 0)),
3866 ..Default::default()
3867 },
3868 Interval {
3869 months: 11,
3870 ..Default::default()
3871 },
3872 );
3873 run_test_parseddatetime_compute_interval(
3874 ParsedDateTime {
3875 year: Some(DateTimeFieldValue::new(-1, 0)),
3876 month: Some(DateTimeFieldValue::new(1, 0)),
3877 ..Default::default()
3878 },
3879 Interval {
3880 months: -11,
3881 ..Default::default()
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 hour: Some(DateTimeFieldValue::new(2, 0)),
3903 minute: Some(DateTimeFieldValue::new(3, 0)),
3904 second: Some(DateTimeFieldValue::new(4, 500_000_000)),
3905 ..Default::default()
3906 },
3907 Interval::new(
3909 0,
3910 -1,
3911 (2 * 60 * 60 * 1_000_000) + (3 * 60 * 1_000_000) + (4 * 1_000_000) + 500_000,
3912 ),
3913 );
3914 run_test_parseddatetime_compute_interval(
3915 ParsedDateTime {
3916 day: Some(DateTimeFieldValue::new(1, 0)),
3917 second: Some(DateTimeFieldValue::new(0, -270_000_000)),
3918 ..Default::default()
3919 },
3920 Interval::new(0, 1, -270_000),
3922 );
3923 run_test_parseddatetime_compute_interval(
3924 ParsedDateTime {
3925 day: Some(DateTimeFieldValue::new(-1, 0)),
3926 second: Some(DateTimeFieldValue::new(0, 270_000_000)),
3927 ..Default::default()
3928 },
3929 Interval::new(0, -1, 270_000),
3931 );
3932 run_test_parseddatetime_compute_interval(
3933 ParsedDateTime {
3934 year: Some(DateTimeFieldValue::new(-1, -555_555_555)),
3935 month: Some(DateTimeFieldValue::new(2, 555_555_555)),
3936 day: Some(DateTimeFieldValue::new(-3, -555_555_555)),
3937 hour: Some(DateTimeFieldValue::new(4, 555_555_555)),
3938 minute: Some(DateTimeFieldValue::new(-5, -555_555_555)),
3939 second: Some(DateTimeFieldValue::new(6, 555_555_555)),
3940 ..Default::default()
3941 },
3942 Interval::new(
3944 -16,
3945 13,
3946 (7 * 60 * 60 * 1_000_000) + (7 * 60 * 1_000_000) + (53 * 1_000_000) + 220_829,
3947 ),
3948 );
3949 run_test_parseddatetime_compute_interval(
3950 ParsedDateTime {
3951 second: Some(DateTimeFieldValue::new(1, 0)),
3952 millisecond: Some(DateTimeFieldValue::new(2_003, 0)),
3953 ..Default::default()
3954 },
3955 Interval::new(0, 0, (3 * 1_000_000) + 3_000),
3957 );
3958 run_test_parseddatetime_compute_interval(
3959 ParsedDateTime {
3960 second: Some(DateTimeFieldValue::new(1, 0)),
3961 microsecond: Some(DateTimeFieldValue::new(2_000_003, 0)),
3962 ..Default::default()
3963 },
3964 Interval::new(0, 0, (3 * 1_000_000) + 3),
3966 );
3967 run_test_parseddatetime_compute_interval(
3968 ParsedDateTime {
3969 millisecond: Some(DateTimeFieldValue::new(1, 200_000_000)),
3970 microsecond: Some(DateTimeFieldValue::new(3, 400_000_000)),
3971 ..Default::default()
3972 },
3973 Interval::new(0, 0, 1_203),
3975 );
3976 run_test_parseddatetime_compute_interval(
3977 ParsedDateTime {
3978 millennium: Some(DateTimeFieldValue::new(1, 0)),
3979 century: Some(DateTimeFieldValue::new(2, 0)),
3980 decade: Some(DateTimeFieldValue::new(3, 0)),
3981 year: Some(DateTimeFieldValue::new(4, 0)),
3982 ..Default::default()
3983 },
3984 Interval::new(1234 * 12, 0, 0),
3986 );
3987
3988 fn run_test_parseddatetime_compute_interval(pdt: ParsedDateTime, expected: Interval) {
3989 let actual = pdt.compute_interval().unwrap();
3990
3991 if actual != expected {
3992 panic!(
3993 "test_interval_compute_interval failed\n input {:?}\nactual {:?}\nexpected {:?}",
3994 pdt, actual, expected
3995 )
3996 }
3997 }
3998}