1use crate::common::{
4 HOURS_PER_DAY, MINUTES_PER_HOUR, MONTHS_PER_YEAR, SECONDS_PER_MINUTE, USECONDS_MAX,
5 USECONDS_PER_DAY, USECONDS_PER_HOUR, USECONDS_PER_MINUTE, USECONDS_PER_SECOND,
6};
7use crate::error::{Error, Result};
8use crate::format::{LazyFormat, NaiveDateTime};
9use crate::interval::Sign::{Negative, Positive};
10use crate::{Date, Time};
11use crate::{DateTime, Formatter};
12use std::cmp::Ordering;
13use std::convert::TryFrom;
14use std::fmt::Display;
15use std::ops::Neg;
16
17const INTERVAL_MAX_YEAR: i32 = 178_000_000;
18const INTERVAL_MAX_DAY: i32 = 100_000_000;
19
20pub(crate) const INTERVAL_MAX_MONTH: i32 = INTERVAL_MAX_YEAR * (MONTHS_PER_YEAR as i32);
21pub(crate) const INTERVAL_MAX_USECONDS: i64 = INTERVAL_MAX_DAY as i64 * USECONDS_PER_DAY;
22
23#[derive(Debug, PartialEq, Eq, Copy, Clone)]
24pub enum Sign {
25 Positive = 1,
26 Negative = -1,
27}
28
29#[allow(clippy::upper_case_acronyms)]
32#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
33#[repr(transparent)]
34pub struct IntervalYM(i32);
35
36impl IntervalYM {
37 pub const MIN: Self = unsafe { IntervalYM::from_ym_unchecked(178000000, 0).negate() };
39
40 pub const MAX: Self = unsafe { IntervalYM::from_ym_unchecked(178000000, 0) };
42
43 pub const ZERO: Self = IntervalYM(0);
45
46 #[inline]
52 pub const unsafe fn from_ym_unchecked(year: u32, month: u32) -> Self {
53 IntervalYM((year * MONTHS_PER_YEAR + month) as i32)
54 }
55
56 #[inline(always)]
62 pub const unsafe fn from_months_unchecked(months: i32) -> Self {
63 IntervalYM(months)
64 }
65
66 #[inline]
68 pub const fn try_from_ym(year: u32, month: u32) -> Result<Self> {
69 if year >= INTERVAL_MAX_YEAR as u32 && (year != INTERVAL_MAX_YEAR as u32 || month != 0) {
70 return Err(Error::IntervalOutOfRange);
71 }
72
73 if month >= MONTHS_PER_YEAR {
74 return Err(Error::InvalidMonth);
75 }
76
77 Ok(unsafe { IntervalYM::from_ym_unchecked(year, month) })
78 }
79
80 #[inline]
82 pub const fn try_from_months(months: i32) -> Result<Self> {
83 if IntervalYM::is_valid_months(months) {
84 Ok(unsafe { IntervalYM::from_months_unchecked(months) })
85 } else {
86 Err(Error::IntervalOutOfRange)
87 }
88 }
89
90 #[inline]
92 pub const fn is_valid_ym(year: u32, month: u32) -> bool {
93 if year >= INTERVAL_MAX_YEAR as u32 && (year != INTERVAL_MAX_YEAR as u32 || month != 0) {
94 return false;
95 }
96
97 if month >= MONTHS_PER_YEAR {
98 return false;
99 }
100
101 true
102 }
103
104 #[inline]
106 pub(crate) const fn is_valid_months(months: i32) -> bool {
107 months <= INTERVAL_MAX_MONTH && months >= -INTERVAL_MAX_MONTH
108 }
109
110 #[inline(always)]
112 pub const fn months(self) -> i32 {
113 self.0
114 }
115
116 #[inline]
118 pub const fn extract(self) -> (Sign, u32, u32) {
119 if self.0.is_negative() {
120 let year = -self.0 as u32 / MONTHS_PER_YEAR;
121 (Negative, year, -self.0 as u32 - year * MONTHS_PER_YEAR)
122 } else {
123 let year = self.0 as u32 / MONTHS_PER_YEAR;
124 (Positive, year, self.0 as u32 - year * MONTHS_PER_YEAR)
125 }
126 }
127
128 #[inline]
130 pub fn format<S: AsRef<str>>(self, fmt: S) -> Result<impl Display> {
131 let fmt = Formatter::try_new(fmt)?;
132 Ok(LazyFormat::new(fmt, self))
133 }
134
135 #[inline]
137 pub fn parse<S1: AsRef<str>, S2: AsRef<str>>(input: S1, fmt: S2) -> Result<Self> {
138 let fmt = Formatter::try_new(fmt)?;
139 fmt.parse(input)
140 }
141
142 #[inline]
143 pub(crate) const fn negate(self) -> IntervalYM {
144 unsafe { IntervalYM::from_months_unchecked(-self.months()) }
145 }
146
147 #[inline]
149 pub const fn add_interval_ym(self, interval: IntervalYM) -> Result<IntervalYM> {
150 let result = self.months().checked_add(interval.months());
151 match result {
152 Some(i) => IntervalYM::try_from_months(i),
153 None => Err(Error::IntervalOutOfRange),
154 }
155 }
156
157 #[inline]
159 pub const fn sub_interval_ym(self, interval: IntervalYM) -> Result<IntervalYM> {
160 self.add_interval_ym(interval.negate())
161 }
162
163 #[inline]
165 pub fn mul_f64(self, number: f64) -> Result<IntervalYM> {
166 let months = self.months() as f64;
167 let result = months * number;
168
169 if result.is_infinite() {
170 Err(Error::NumericOverflow)
171 } else if result.is_nan() {
172 Err(Error::InvalidNumber)
173 } else {
174 IntervalYM::try_from_months(result as i32)
175 }
176 }
177
178 #[inline]
180 pub fn div_f64(self, number: f64) -> Result<IntervalYM> {
181 if number == 0.0 {
182 return Err(Error::DivideByZero);
183 }
184 let months = self.months() as f64;
185 let result = months / number;
186
187 if result.is_infinite() {
188 Err(Error::NumericOverflow)
189 } else if result.is_nan() {
190 Err(Error::InvalidNumber)
191 } else {
192 IntervalYM::try_from_months(result as i32)
193 }
194 }
195}
196
197impl From<IntervalYM> for NaiveDateTime {
198 #[inline]
199 fn from(interval: IntervalYM) -> Self {
200 let (sign, year, month) = interval.extract();
201 let negative = sign == Negative;
202 NaiveDateTime {
203 year: year as i32,
204 month,
205 negative,
206 ..NaiveDateTime::new()
207 }
208 }
209}
210
211impl TryFrom<NaiveDateTime> for IntervalYM {
212 type Error = Error;
213
214 #[inline]
215 fn try_from(dt: NaiveDateTime) -> Result<Self> {
216 if dt.negative {
217 Ok(-IntervalYM::try_from_ym(-dt.year as u32, dt.month)?)
218 } else {
219 IntervalYM::try_from_ym(dt.year as u32, dt.month)
220 }
221 }
222}
223
224impl Neg for IntervalYM {
225 type Output = IntervalYM;
226
227 #[inline]
228 fn neg(self) -> Self::Output {
229 self.negate()
230 }
231}
232
233impl DateTime for IntervalYM {
234 #[inline(always)]
235 fn year(&self) -> Option<i32> {
236 Some(self.months() / MONTHS_PER_YEAR as i32)
237 }
238
239 #[inline(always)]
240 fn month(&self) -> Option<i32> {
241 Some(self.months() % MONTHS_PER_YEAR as i32)
242 }
243
244 #[inline(always)]
245 fn day(&self) -> Option<i32> {
246 None
247 }
248
249 #[inline(always)]
250 fn hour(&self) -> Option<i32> {
251 None
252 }
253
254 #[inline(always)]
255 fn minute(&self) -> Option<i32> {
256 None
257 }
258
259 #[inline(always)]
260 fn second(&self) -> Option<f64> {
261 None
262 }
263
264 #[inline(always)]
265 fn date(&self) -> Option<Date> {
266 None
267 }
268}
269
270#[allow(clippy::upper_case_acronyms)]
273#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
274#[repr(transparent)]
275pub struct IntervalDT(i64);
276
277impl IntervalDT {
278 pub const MIN: Self =
280 unsafe { IntervalDT::from_dhms_unchecked(100000000, 0, 0, 0, 0).negate() };
281
282 pub const MAX: Self = unsafe { IntervalDT::from_dhms_unchecked(100000000, 0, 0, 0, 0) };
284
285 pub const ZERO: Self = IntervalDT(0);
287
288 #[inline]
294 pub const unsafe fn from_dhms_unchecked(
295 day: u32,
296 hour: u32,
297 minute: u32,
298 sec: u32,
299 usec: u32,
300 ) -> Self {
301 let time = hour as i64 * USECONDS_PER_HOUR
302 + minute as i64 * USECONDS_PER_MINUTE
303 + sec as i64 * USECONDS_PER_SECOND
304 + usec as i64;
305 let us = day as i64 * USECONDS_PER_DAY + time;
306 IntervalDT(us)
307 }
308
309 #[inline]
311 pub const fn try_from_dhms(
312 day: u32,
313 hour: u32,
314 minute: u32,
315 sec: u32,
316 usec: u32,
317 ) -> Result<Self> {
318 if day >= INTERVAL_MAX_DAY as u32
319 && (day != INTERVAL_MAX_DAY as u32 || hour != 0 || minute != 0 || sec != 0 || usec != 0)
320 {
321 return Err(Error::IntervalOutOfRange);
322 }
323
324 if hour >= HOURS_PER_DAY {
325 return Err(Error::TimeOutOfRange);
326 }
327
328 if minute >= MINUTES_PER_HOUR {
329 return Err(Error::InvalidMinute);
330 }
331
332 if sec >= SECONDS_PER_MINUTE {
333 return Err(Error::InvalidSecond);
334 }
335
336 if usec > USECONDS_MAX {
337 return Err(Error::InvalidFraction);
338 }
339
340 Ok(unsafe { IntervalDT::from_dhms_unchecked(day, hour, minute, sec, usec) })
341 }
342
343 #[inline(always)]
349 pub const unsafe fn from_usecs_unchecked(usecs: i64) -> Self {
350 IntervalDT(usecs)
351 }
352
353 #[inline]
355 pub const fn try_from_usecs(usecs: i64) -> Result<Self> {
356 if IntervalDT::is_valid_usecs(usecs) {
357 Ok(unsafe { IntervalDT::from_usecs_unchecked(usecs) })
358 } else {
359 Err(Error::IntervalOutOfRange)
360 }
361 }
362
363 #[inline]
365 pub const fn is_valid(day: u32, hour: u32, minute: u32, sec: u32, usec: u32) -> bool {
366 if day >= INTERVAL_MAX_DAY as u32
367 && (day != INTERVAL_MAX_DAY as u32 || hour != 0 || minute != 0 || sec != 0 || usec != 0)
368 {
369 return false;
370 }
371
372 if hour >= HOURS_PER_DAY {
373 return false;
374 }
375
376 if minute >= MINUTES_PER_HOUR {
377 return false;
378 }
379
380 if sec >= SECONDS_PER_MINUTE {
381 return false;
382 }
383
384 if usec > USECONDS_MAX {
385 return false;
386 }
387
388 true
389 }
390
391 #[inline]
392 pub(crate) const fn is_valid_usecs(usecs: i64) -> bool {
393 usecs <= INTERVAL_MAX_USECONDS && usecs >= -INTERVAL_MAX_USECONDS
394 }
395
396 #[inline(always)]
398 pub const fn usecs(self) -> i64 {
399 self.0
400 }
401
402 #[inline]
404 pub const fn extract(self) -> (Sign, u32, u32, u32, u32, u32) {
405 let (sign, day, mut time) = if self.0.is_negative() {
406 let day = -self.0 / USECONDS_PER_DAY;
407 (Negative, day, -self.0 - day * USECONDS_PER_DAY)
408 } else {
409 let day = self.0 / USECONDS_PER_DAY;
410 (Positive, day, self.0 - day * USECONDS_PER_DAY)
411 };
412
413 let hour = time / USECONDS_PER_HOUR;
414 time -= hour * USECONDS_PER_HOUR;
415
416 let minute = time / USECONDS_PER_MINUTE;
417 time -= minute * USECONDS_PER_MINUTE;
418
419 let sec = time / USECONDS_PER_SECOND;
420 let usec = time - sec * USECONDS_PER_SECOND;
421
422 (
423 sign,
424 day as u32,
425 hour as u32,
426 minute as u32,
427 sec as u32,
428 usec as u32,
429 )
430 }
431
432 #[inline]
434 pub fn format<S: AsRef<str>>(self, fmt: S) -> Result<impl Display> {
435 let fmt = Formatter::try_new(fmt)?;
436 Ok(LazyFormat::new(fmt, self))
437 }
438
439 #[inline]
441 pub fn parse<S1: AsRef<str>, S2: AsRef<str>>(input: S1, fmt: S2) -> Result<Self> {
442 let fmt = Formatter::try_new(fmt)?;
443 fmt.parse(input)
444 }
445
446 #[inline]
447 pub(crate) const fn negate(self) -> IntervalDT {
448 unsafe { IntervalDT::from_usecs_unchecked(-self.usecs()) }
449 }
450
451 #[inline]
453 pub const fn add_interval_dt(self, interval: IntervalDT) -> Result<IntervalDT> {
454 let result = self.usecs().checked_add(interval.usecs());
455 match result {
456 Some(i) => IntervalDT::try_from_usecs(i),
457 None => Err(Error::IntervalOutOfRange),
458 }
459 }
460
461 #[inline]
463 pub const fn sub_interval_dt(self, interval: IntervalDT) -> Result<IntervalDT> {
464 self.add_interval_dt(interval.negate())
465 }
466
467 #[inline]
469 pub fn mul_f64(self, number: f64) -> Result<IntervalDT> {
470 let usecs = self.usecs() as f64;
471 let result = usecs * number;
472
473 if result.is_infinite() {
474 Err(Error::NumericOverflow)
475 } else if result.is_nan() {
476 Err(Error::InvalidNumber)
477 } else {
478 IntervalDT::try_from_usecs(result as i64)
479 }
480 }
481
482 #[inline]
484 pub fn div_f64(self, number: f64) -> Result<IntervalDT> {
485 if number == 0.0 {
486 return Err(Error::DivideByZero);
487 }
488 let usecs = self.usecs() as f64;
489 let result = usecs / number;
490
491 if result.is_infinite() {
492 Err(Error::NumericOverflow)
493 } else if result.is_nan() {
494 Err(Error::InvalidNumber)
495 } else {
496 IntervalDT::try_from_usecs(result as i64)
497 }
498 }
499
500 #[inline]
502 pub const fn sub_time(self, time: Time) -> Result<IntervalDT> {
503 IntervalDT::try_from_usecs(self.usecs() - time.usecs())
504 }
505}
506
507impl From<IntervalDT> for NaiveDateTime {
508 #[inline]
509 fn from(interval: IntervalDT) -> Self {
510 let (sign, day, hour, minute, sec, usec) = interval.extract();
511 let negative = sign == Sign::Negative;
512 NaiveDateTime {
513 day,
514 hour,
515 minute,
516 sec,
517 usec,
518 negative,
519 ..NaiveDateTime::new()
520 }
521 }
522}
523
524impl TryFrom<NaiveDateTime> for IntervalDT {
525 type Error = Error;
526
527 #[inline]
528 fn try_from(dt: NaiveDateTime) -> Result<Self> {
529 if dt.negative {
530 Ok(IntervalDT::try_from_dhms(dt.day, dt.hour, dt.minute, dt.sec, dt.usec)?.negate())
531 } else {
532 IntervalDT::try_from_dhms(dt.day, dt.hour, dt.minute, dt.sec, dt.usec)
533 }
534 }
535}
536
537impl From<Time> for IntervalDT {
538 #[inline]
539 fn from(time: Time) -> Self {
540 unsafe { IntervalDT::from_usecs_unchecked(time.usecs()) }
541 }
542}
543
544impl PartialEq<Time> for IntervalDT {
545 #[inline]
546 fn eq(&self, other: &Time) -> bool {
547 self.usecs() == other.usecs()
548 }
549}
550
551impl PartialOrd<Time> for IntervalDT {
552 #[inline]
553 fn partial_cmp(&self, other: &Time) -> Option<Ordering> {
554 Some(self.usecs().cmp(&other.usecs()))
555 }
556}
557
558impl Neg for IntervalDT {
559 type Output = IntervalDT;
560
561 #[inline]
562 fn neg(self) -> Self::Output {
563 self.negate()
564 }
565}
566
567impl DateTime for IntervalDT {
568 #[inline(always)]
569 fn year(&self) -> Option<i32> {
570 None
571 }
572
573 #[inline(always)]
574 fn month(&self) -> Option<i32> {
575 None
576 }
577
578 #[inline(always)]
579 fn day(&self) -> Option<i32> {
580 Some((self.usecs() / USECONDS_PER_DAY) as i32)
581 }
582
583 #[inline(always)]
584 fn hour(&self) -> Option<i32> {
585 let remain_time = self.usecs() % USECONDS_PER_DAY;
586 Some((remain_time / USECONDS_PER_HOUR) as i32)
587 }
588
589 #[inline(always)]
590 fn minute(&self) -> Option<i32> {
591 let remain_time = self.usecs() % USECONDS_PER_HOUR;
592 Some((remain_time / USECONDS_PER_MINUTE) as i32)
593 }
594
595 #[inline]
596 fn second(&self) -> Option<f64> {
597 let remain_time = self.usecs() % USECONDS_PER_MINUTE;
598 Some(remain_time as f64 / USECONDS_PER_SECOND as f64)
599 }
600
601 #[inline(always)]
602 fn date(&self) -> Option<Date> {
603 None
604 }
605}
606
607#[cfg(test)]
608mod tests {
609 use super::*;
610
611 #[test]
612 fn test_interval_ym() {
613 assert_eq!(IntervalYM::ZERO, IntervalYM::try_from_ym(0, 0).unwrap());
614 assert_eq!(
615 IntervalYM::MIN,
616 -IntervalYM::try_from_ym(178000000, 0).unwrap()
617 );
618 assert_eq!(
619 IntervalYM::MAX,
620 IntervalYM::try_from_ym(178000000, 0).unwrap()
621 );
622
623 let interval = IntervalYM::try_from_ym(0, 0).unwrap();
624 assert_eq!(interval.months(), 0);
625 assert_eq!(interval.extract(), (Positive, 0, 0));
626
627 let interval = IntervalYM::try_from_ym(178000000, 0).unwrap();
628 assert_eq!(interval.extract(), (Positive, 178000000, 0));
629 let fmt = format!("{}", interval.format("yyyy-mm").unwrap());
630 assert_eq!(fmt, "+178000000-00");
631 let interval2 = IntervalYM::parse("178000000-00", "yyyy-mm").unwrap();
632 assert_eq!(interval2, interval);
633
634 let interval = -IntervalYM::try_from_ym(1, 0).unwrap();
635 let fmt = format!("{}", interval.format("yy-mm").unwrap());
636 assert_eq!(fmt, "-01-00");
637
638 let interval = IntervalYM::try_from_ym(123, 2).unwrap();
639 let fmt = format!("{}", interval.format("yy-mm").unwrap());
640 assert_eq!(fmt, "+123-02");
641
642 let interval = -IntervalYM::try_from_ym(178000000, 0).unwrap();
643 assert_eq!(interval.extract(), (Negative, 178000000, 0));
644 let interval = IntervalYM::try_from_ym(178000000, 0).unwrap().negate();
645 assert_eq!(interval.extract(), (Negative, 178000000, 0));
646 let fmt = format!("{}", interval.format("yyyy-mm").unwrap());
647 assert_eq!(fmt, "-178000000-00");
648
649 let fmt = format!("{}", interval.format("yy-mm").unwrap());
650 assert_eq!(fmt, "-178000000-00");
651
652 let interval2 = IntervalYM::parse("-178000000-00", "yyyy-mm").unwrap();
653 assert_eq!(interval2, interval);
654
655 let interval2 = IntervalYM::parse("+178000000-00", "yyyy-mm").unwrap();
656 assert_eq!(interval2, -interval);
657
658 let interval = IntervalYM::try_from_ym(177999999, 11).unwrap();
659 assert_eq!(interval.extract(), (Positive, 177999999, 11));
660
661 let interval = -IntervalYM::try_from_ym(177999999, 11).unwrap();
662 assert_eq!(interval.extract(), (Negative, 177999999, 11));
663
664 let interval = IntervalYM::try_from_months(0).unwrap();
665 assert_eq!(interval.extract(), (Positive, 0, 0));
666
667 let interval = IntervalYM::try_from_months(-11).unwrap();
668 assert_eq!(interval.extract(), (Negative, 0, 11));
669 let fmt = format!("{}", interval.format("yyyy-mm").unwrap());
670 assert_eq!(fmt, "-0000-11");
671
672 let interval2 = IntervalYM::parse("-0000-11", "yyyy-mm").unwrap();
673 assert_eq!(interval, interval2);
674 let interval2 = IntervalYM::parse("-0000 - 11", "yyyy - mm").unwrap();
675 assert_eq!(interval, interval2);
676 let interval2 = IntervalYM::parse(" -0000 - 11 ", "yyyy - mm").unwrap();
677 assert_eq!(interval, interval2);
678 let interval2 = IntervalYM::parse(" -0000 - 11 ", " yyyy - mm ").unwrap();
679 assert_eq!(interval, interval2);
680 let interval2 = IntervalYM::parse("-0000-11", "yyyy - mm").unwrap();
681 assert_eq!(interval, interval2);
682
683 let interval = IntervalYM::try_from_months(11).unwrap();
684 let interval2 = IntervalYM::parse("0000-11", "yyyy-mm").unwrap();
685 assert_eq!(interval, interval2);
686
687 let interval = IntervalYM::try_from_ym(12345, 1).unwrap();
688 let interval2 = IntervalYM::parse("12345-1", "yyyy-mm").unwrap();
689 assert_eq!(interval, interval2);
690
691 let interval = IntervalYM::try_from_ym(12345, 1).unwrap();
692 let interval2 = IntervalYM::parse("12345-1", "yy-mm").unwrap();
693 assert_eq!(interval, interval2);
694
695 let interval = IntervalYM::try_from_ym(1, 1).unwrap();
696 let interval2 = IntervalYM::parse("1-1", "yy-mm").unwrap();
697 assert_eq!(interval, interval2);
698
699 let res = IntervalYM::parse("2022", "YYYY").unwrap();
701 assert_eq!(res.month().unwrap(), 0);
702
703 assert!(IntervalYM::parse("178000000-1", "yyyy-mm").is_err());
705 assert!(IntervalYM::parse("178000001-0", "yyyy-mm").is_err());
706 assert!(IntervalYM::parse("-178000001-0", "yyyy-mm").is_err());
707 assert!(IntervalYM::parse("0-13", "yyyy-mm").is_err());
708 assert!(IntervalYM::parse("-178000000-1", "yyyy-mm").is_err());
709 assert!(IntervalYM::parse("-178000001-0", "yyyy-mm").is_err());
710 assert!(IntervalYM::parse("11", "dd").is_err());
711 assert!(IntervalYM::parse("11", "hh24").is_err());
712 assert!(IntervalYM::parse("11", "mi").is_err());
713 assert!(IntervalYM::parse("11", "ss").is_err());
714
715 assert_eq!(
716 IntervalYM::parse("xxxx", "yy-mm").err().unwrap(),
717 Error::ParseError("the interval is invalid".to_string())
718 )
719 }
721
722 #[test]
723 fn test_interval_dt() {
724 assert_eq!(
725 IntervalDT::ZERO,
726 IntervalDT::try_from_dhms(0, 0, 0, 0, 0).unwrap()
727 );
728 assert_eq!(
729 IntervalDT::MIN,
730 -IntervalDT::try_from_dhms(100_000_000, 0, 0, 0, 0).unwrap()
731 );
732 assert_eq!(
733 IntervalDT::MAX,
734 IntervalDT::try_from_dhms(100_000_000, 0, 0, 0, 0).unwrap()
735 );
736
737 let time = Time::try_from_hms(0, 0, 0, 0).unwrap();
738 let interval = IntervalDT::from(time);
739 assert_eq!(IntervalDT::ZERO, interval);
740
741 let time = Time::try_from_hms(1, 2, 3, 4).unwrap();
742 let interval = IntervalDT::from(time);
743 assert_eq!(IntervalDT::try_from_dhms(0, 1, 2, 3, 4).unwrap(), interval);
744
745 let time = Time::try_from_hms(23, 59, 59, 999999).unwrap();
746 let interval = IntervalDT::from(time);
747 assert_eq!(
748 IntervalDT::try_from_dhms(0, 23, 59, 59, 999999).unwrap(),
749 interval
750 );
751
752 let interval = IntervalDT::try_from_dhms(0, 0, 0, 0, 0).unwrap();
753 assert_eq!(interval.usecs(), 0);
754 assert_eq!(interval.extract(), (Positive, 0, 0, 0, 0, 0));
755 let fmt = format!("{}", interval.format("DD HH24:MI:SS").unwrap());
756 assert_eq!(fmt, "+00 00:00:00");
757
758 let interval = IntervalDT::try_from_dhms(100000000, 0, 0, 0, 0).unwrap();
759 assert_eq!(interval.extract(), (Positive, 100000000, 0, 0, 0, 0));
760 let fmt = format!("{}", interval.format("DD HH24:MI:SS").unwrap());
761 assert_eq!(fmt, "+100000000 00:00:00");
762 let interval2 = IntervalDT::parse("100000000 00:00:00", "DD HH24:MI:SS").unwrap();
763 assert_eq!(interval2, interval);
764
765 let interval2 = IntervalDT::parse("+100000000 00:00:00", "DD HH24:MI:SS").unwrap();
766 assert_eq!(interval2, interval);
767
768 let interval = -IntervalDT::try_from_dhms(100000000, 0, 0, 0, 0).unwrap();
769 assert_eq!(interval.extract(), (Negative, 100000000, 0, 0, 0, 0));
770
771 let interval = IntervalDT::try_from_dhms(100000000, 0, 0, 0, 0)
772 .unwrap()
773 .negate();
774 assert_eq!(interval.extract(), (Negative, 100000000, 0, 0, 0, 0));
775
776 let interval = IntervalDT::try_from_dhms(99999999, 23, 59, 59, 999999).unwrap();
777 assert_eq!(interval.extract(), (Positive, 99999999, 23, 59, 59, 999999));
778
779 let interval = -IntervalDT::try_from_dhms(99999999, 23, 59, 59, 999999).unwrap();
780 assert_eq!(interval.extract(), (Negative, 99999999, 23, 59, 59, 999999));
781 let fmt = format!("{}", interval.format("DD HH24:MI:SS.FF6").unwrap());
782 assert_eq!(fmt, "-99999999 23:59:59.999999");
783
784 let interval = IntervalDT::try_from_usecs(-11).unwrap();
785 let interval2 = IntervalDT::parse("-0 00:00:00.000011", "DD HH24:MI:SS.FF6").unwrap();
786 assert_eq!(interval, interval2);
787
788 let interval = IntervalDT::try_from_usecs(11).unwrap();
789 let interval2 = IntervalDT::parse("0 00:00:00.000011", "DD HH24:MI:SS.FF6").unwrap();
790 assert_eq!(interval, interval2);
791
792 let interval = IntervalDT::try_from_usecs(-11).unwrap();
793 let interval2 = IntervalDT::parse("-0 00:00:00.000011", "DD HH24:MI:SS.FF").unwrap();
794 assert_eq!(interval, interval2);
795
796 let interval = IntervalDT::try_from_usecs(-12).unwrap();
797 let interval2 = IntervalDT::parse("-0 00:00:00.000011567", "DD HH24:MI:SS.FF").unwrap();
798 assert_eq!(interval, interval2);
799
800 let interval = IntervalDT::try_from_dhms(12, 4, 5, 6, 0).unwrap().negate();
801 let interval2 = IntervalDT::parse("-12 4:5:6", "DD HH24:MI:SS").unwrap();
802 assert_eq!(interval, interval2);
803
804 assert!(IntervalDT::parse("100000000 02:00:00.0", "DD HH24:MI:SS.FF").is_err());
806 assert!(IntervalDT::parse("0 24:00:00:00.0", "DD HH24:MI:SS.FF").is_err());
807 assert!(IntervalDT::parse("100000001 00:00:00.0", "DD HH24:MI:SS.FF").is_err());
808 assert!(IntervalDT::parse("-100000001 00:00:00.0", "DD HH24:MI:SS.FF").is_err());
809 assert!(IntervalDT::parse("-100000000 02:00:00.0", "DD HH24:MI:SS.FF").is_err());
810
811 assert!(IntervalDT::parse("-100000 02:00", "DD HH24:MI:SS.FF").is_err());
812 assert!(IntervalDT::parse("-100000 02", "DD HH24:MI:SS.FF").is_err());
813 assert!(IntervalDT::parse("-100000 ", "DD HH24:MI:SS.FF").is_err());
814
815 assert!(IntervalDT::parse("1919", "yyyy").is_err());
816 assert!(IntervalDT::parse("19", "mm").is_err());
817 }
818
819 #[test]
820 fn test_interval_negate() {
821 assert_eq!(
822 -IntervalDT::try_from_dhms(1, 2, 3, 4, 5).unwrap(),
823 IntervalDT::try_from_usecs(-93784000005).unwrap()
824 );
825 assert_eq!(
826 IntervalDT::try_from_dhms(1, 2, 3, 4, 5).unwrap().negate(),
827 IntervalDT::try_from_usecs(-93784000005).unwrap()
828 );
829 assert_eq!(
830 -IntervalDT::try_from_dhms(0, 0, 0, 0, 0).unwrap(),
831 IntervalDT::try_from_dhms(0, 0, 0, 0, 0).unwrap()
832 );
833 assert_eq!(
834 IntervalDT::try_from_dhms(0, 0, 0, 0, 0).unwrap().negate(),
835 IntervalDT::try_from_dhms(0, 0, 0, 0, 0).unwrap()
836 );
837 assert_eq!(
838 -IntervalDT::try_from_dhms(1, 2, 3, 4, 5).unwrap().negate(),
839 IntervalDT::try_from_usecs(93784000005).unwrap()
840 );
841 assert_eq!(
842 IntervalDT::try_from_dhms(1, 2, 3, 4, 5)
843 .unwrap()
844 .negate()
845 .negate(),
846 IntervalDT::try_from_dhms(1, 2, 3, 4, 5).unwrap()
847 );
848 assert_eq!(
849 -IntervalDT::try_from_dhms(INTERVAL_MAX_DAY as u32, 0, 0, 0, 0).unwrap(),
850 IntervalDT::try_from_usecs(-8640000000000000000).unwrap()
851 );
852 assert_eq!(
853 IntervalDT::try_from_dhms(INTERVAL_MAX_DAY as u32, 0, 0, 0, 0)
854 .unwrap()
855 .negate(),
856 IntervalDT::try_from_usecs(-8640000000000000000).unwrap()
857 );
858 assert_eq!(
859 -IntervalDT::try_from_dhms(INTERVAL_MAX_DAY as u32, 0, 0, 0, 0).unwrap(),
860 IntervalDT::try_from_dhms(INTERVAL_MAX_DAY as u32, 0, 0, 0, 0)
861 .unwrap()
862 .negate()
863 );
864
865 assert_eq!(
866 -IntervalYM::try_from_ym(1, 2).unwrap(),
867 IntervalYM::try_from_months(-14).unwrap()
868 );
869 assert_eq!(
870 IntervalYM::try_from_ym(1, 2).unwrap().negate(),
871 IntervalYM::try_from_months(-14).unwrap()
872 );
873 assert_eq!(
874 -IntervalYM::try_from_ym(0, 0).unwrap(),
875 IntervalYM::try_from_ym(0, 0).unwrap()
876 );
877 assert_eq!(
878 IntervalYM::try_from_ym(0, 0).unwrap().negate(),
879 IntervalYM::try_from_ym(0, 0).unwrap()
880 );
881 assert_eq!(
882 -IntervalYM::try_from_ym(1, 2).unwrap().negate(),
883 IntervalYM::try_from_ym(1, 2).unwrap()
884 );
885 assert_eq!(
886 IntervalYM::try_from_ym(1, 2).unwrap().negate().negate(),
887 IntervalYM::try_from_ym(1, 2).unwrap()
888 );
889 assert_eq!(
890 -IntervalYM::try_from_ym(INTERVAL_MAX_YEAR as u32, 0).unwrap(),
891 IntervalYM::try_from_months(-2136000000).unwrap()
892 );
893 assert_eq!(
894 IntervalYM::try_from_ym(INTERVAL_MAX_YEAR as u32, 0)
895 .unwrap()
896 .negate(),
897 IntervalYM::try_from_months(-2136000000).unwrap()
898 );
899 assert_eq!(
900 -IntervalYM::try_from_ym(INTERVAL_MAX_YEAR as u32, 0)
901 .unwrap()
902 .negate(),
903 IntervalYM::try_from_months(2136000000).unwrap()
904 );
905 assert_eq!(
906 IntervalYM::try_from_ym(INTERVAL_MAX_YEAR as u32, 0)
907 .unwrap()
908 .negate()
909 .negate(),
910 IntervalYM::try_from_months(2136000000).unwrap()
911 );
912 }
913
914 #[test]
915 fn test_interval_ym_add_sub_interval_ym() {
916 assert!(IntervalYM::try_from_ym(178000000, 0)
917 .unwrap()
918 .add_interval_ym(IntervalYM::try_from_ym(0, 1).unwrap())
919 .is_err());
920
921 assert!(IntervalYM::try_from_ym(178000000, 0)
922 .unwrap()
923 .sub_interval_ym(-IntervalYM::try_from_ym(0, 1).unwrap())
924 .is_err());
925
926 assert!(IntervalYM::try_from_ym(178000000, 0)
927 .unwrap()
928 .negate()
929 .sub_interval_ym(IntervalYM::try_from_ym(0, 1).unwrap())
930 .is_err());
931
932 assert!((-IntervalYM::try_from_ym(178000000, 0).unwrap())
933 .add_interval_ym(-IntervalYM::try_from_ym(0, 1).unwrap())
934 .is_err());
935
936 assert_eq!(
937 IntervalYM::try_from_ym(123456, 5)
938 .unwrap()
939 .add_interval_ym(IntervalYM::try_from_ym(123, 7).unwrap())
940 .unwrap(),
941 IntervalYM::try_from_ym(123580, 0).unwrap()
942 );
943
944 assert_eq!(
945 IntervalYM::try_from_ym(123456, 5)
946 .unwrap()
947 .sub_interval_ym(IntervalYM::try_from_ym(123, 7).unwrap())
948 .unwrap(),
949 IntervalYM::try_from_ym(123332, 10).unwrap()
950 );
951 }
952
953 #[test]
954 fn test_interval_dt_add_sub_interval_dt() {
955 assert!(IntervalDT::try_from_dhms(100000000, 0, 0, 0, 0)
956 .unwrap()
957 .add_interval_dt(IntervalDT::try_from_dhms(0, 0, 0, 0, 1).unwrap())
958 .is_err());
959
960 assert!(IntervalDT::try_from_dhms(100000000, 0, 0, 0, 0)
961 .unwrap()
962 .sub_interval_dt(-IntervalDT::try_from_dhms(0, 0, 0, 0, 1).unwrap())
963 .is_err());
964
965 assert!(IntervalDT::try_from_dhms(100000000, 0, 0, 0, 0)
966 .unwrap()
967 .negate()
968 .sub_interval_dt(IntervalDT::try_from_dhms(0, 0, 0, 0, 1).unwrap())
969 .is_err());
970
971 assert!(IntervalDT::try_from_dhms(100000000, 0, 0, 0, 0)
972 .unwrap()
973 .negate()
974 .add_interval_dt(-IntervalDT::try_from_dhms(0, 0, 0, 0, 1).unwrap())
975 .is_err());
976
977 assert_eq!(
978 IntervalDT::try_from_dhms(23456789, 1, 2, 3, 4)
979 .unwrap()
980 .add_interval_dt(IntervalDT::try_from_dhms(123, 1, 2, 3, 4).unwrap())
981 .unwrap(),
982 IntervalDT::try_from_dhms(23456912, 2, 4, 6, 8).unwrap()
983 );
984
985 assert_eq!(
986 IntervalDT::try_from_dhms(23456789, 1, 2, 3, 4)
987 .unwrap()
988 .sub_interval_dt(IntervalDT::try_from_dhms(123, 1, 2, 3, 4).unwrap())
989 .unwrap(),
990 IntervalDT::try_from_dhms(23456666, 0, 0, 0, 0).unwrap()
991 );
992 }
993
994 #[test]
995 fn test_interval_mul_div() {
996 assert_eq!(
998 IntervalDT::try_from_dhms(1, 2, 3, 4, 5)
999 .unwrap()
1000 .mul_f64(5.0)
1001 .unwrap(),
1002 IntervalDT::try_from_dhms(5, 10, 15, 20, 25).unwrap()
1003 );
1004
1005 assert_eq!(
1006 IntervalDT::try_from_dhms(1, 2, 3, 4, 5)
1007 .unwrap()
1008 .mul_f64(-5.2)
1009 .unwrap(),
1010 -IntervalDT::try_from_dhms(5, 15, 27, 56, 800026).unwrap()
1011 );
1012
1013 assert_eq!(
1014 IntervalDT::try_from_dhms(1, 2, 3, 4, 5)
1015 .unwrap()
1016 .div_f64(-5.2)
1017 .unwrap(),
1018 -IntervalDT::try_from_dhms(0, 5, 0, 35, 384616).unwrap()
1019 );
1020
1021 assert_eq!(
1022 IntervalDT::try_from_dhms(1, 2, 3, 4, 5)
1023 .unwrap()
1024 .div_f64(-5.0)
1025 .unwrap(),
1026 -IntervalDT::try_from_dhms(0, 5, 12, 36, 800001).unwrap()
1027 );
1028
1029 assert_eq!(
1030 IntervalDT::try_from_dhms(99999, 2, 3, 4, 5)
1031 .unwrap()
1032 .div_f64(f64::INFINITY)
1033 .unwrap(),
1034 -IntervalDT::try_from_dhms(0, 0, 0, 0, 0).unwrap()
1035 );
1036
1037 assert_eq!(
1039 IntervalDT::try_from_dhms(1, 2, 3, 4, 5)
1040 .unwrap()
1041 .div_f64(-5.1)
1042 .unwrap(),
1043 -IntervalDT::try_from_dhms(0, 5, 6, 29, 19608).unwrap()
1044 );
1045
1046 assert_eq!(
1047 IntervalDT::try_from_dhms(1, 2, 3, 4, 5)
1048 .unwrap()
1049 .mul_f64(-5.57)
1050 .unwrap(),
1051 -IntervalDT::try_from_dhms(6, 1, 6, 16, 880027).unwrap()
1052 );
1053
1054 assert!(IntervalDT::try_from_dhms(99999, 2, 3, 4, 5)
1056 .unwrap()
1057 .mul_f64(-1234567890.6)
1058 .is_err());
1059
1060 assert!(IntervalDT::try_from_dhms(99999, 2, 3, 4, 5)
1061 .unwrap()
1062 .div_f64(-0.000000000001)
1063 .is_err());
1064
1065 assert!(IntervalDT::try_from_dhms(99999, 2, 3, 4, 5)
1066 .unwrap()
1067 .mul_f64(f64::NEG_INFINITY)
1068 .is_err());
1069
1070 assert!(IntervalDT::try_from_dhms(99999, 2, 3, 4, 5)
1071 .unwrap()
1072 .div_f64(f64::NAN)
1073 .is_err());
1074
1075 assert!(IntervalDT::try_from_dhms(99999, 2, 3, 4, 5)
1076 .unwrap()
1077 .mul_f64(f64::NAN)
1078 .is_err());
1079
1080 assert!(IntervalDT::try_from_dhms(99999, 2, 3, 4, 5)
1082 .unwrap()
1083 .div_f64(0.0)
1084 .is_err());
1085
1086 assert_eq!(
1088 IntervalYM::try_from_ym(1, 2).unwrap().mul_f64(5.0).unwrap(),
1089 IntervalYM::try_from_ym(5, 10).unwrap()
1090 );
1091
1092 assert_eq!(
1093 IntervalYM::try_from_ym(1, 2)
1094 .unwrap()
1095 .mul_f64(-5.3)
1096 .unwrap(),
1097 -IntervalYM::try_from_ym(6, 2).unwrap()
1098 );
1099
1100 assert_eq!(
1101 IntervalYM::try_from_ym(1, 2)
1102 .unwrap()
1103 .mul_f64(-5.2)
1104 .unwrap(),
1105 -IntervalYM::try_from_ym(6, 0).unwrap()
1106 );
1107
1108 assert_eq!(
1109 IntervalYM::try_from_ym(1, 2)
1110 .unwrap()
1111 .div_f64(-5.2)
1112 .unwrap(),
1113 -IntervalYM::try_from_ym(0, 2).unwrap()
1114 );
1115
1116 assert_eq!(
1117 IntervalYM::try_from_ym(1, 2)
1118 .unwrap()
1119 .div_f64(-4.7)
1120 .unwrap(),
1121 -IntervalYM::try_from_ym(0, 2).unwrap()
1122 );
1123
1124 assert_eq!(
1125 IntervalYM::try_from_ym(1, 2)
1126 .unwrap()
1127 .div_f64(f64::INFINITY)
1128 .unwrap(),
1129 -IntervalYM::try_from_ym(0, 0).unwrap()
1130 );
1131
1132 assert!(IntervalYM::try_from_ym(500000, 2)
1134 .unwrap()
1135 .mul_f64(123456789.123)
1136 .is_err());
1137
1138 assert!(IntervalYM::try_from_ym(500000, 2)
1139 .unwrap()
1140 .mul_f64(f64::INFINITY)
1141 .is_err());
1142
1143 assert!(IntervalYM::try_from_ym(500000, 2)
1144 .unwrap()
1145 .mul_f64(f64::NEG_INFINITY)
1146 .is_err());
1147
1148 assert!(IntervalYM::try_from_ym(500000, 2)
1149 .unwrap()
1150 .mul_f64(f64::NAN)
1151 .is_err());
1152
1153 assert!(IntervalYM::try_from_ym(500000, 2)
1154 .unwrap()
1155 .div_f64(f64::NAN)
1156 .is_err());
1157
1158 assert!(IntervalYM::try_from_ym(500000, 2)
1160 .unwrap()
1161 .div_f64(0.0)
1162 .is_err());
1163 }
1164
1165 #[test]
1166 fn test_interval_dt_sub_time() {
1167 assert!(
1169 IntervalDT::try_from_dhms(INTERVAL_MAX_DAY as u32, 0, 0, 0, 0)
1170 .unwrap()
1171 .negate()
1172 .sub_time(Time::try_from_hms(1, 2, 3, 4).unwrap())
1173 .is_err()
1174 );
1175
1176 assert_eq!(
1178 IntervalDT::try_from_dhms(0, 0, 0, 0, 0)
1179 .unwrap()
1180 .sub_time(Time::try_from_hms(1, 2, 3, 4).unwrap())
1181 .unwrap(),
1182 -IntervalDT::try_from_dhms(0, 1, 2, 3, 4).unwrap()
1183 );
1184 }
1185
1186 fn test_extract_ym(negate: bool, year: u32, month: u32) {
1187 let interval = if negate {
1188 IntervalYM::try_from_ym(year, month).unwrap().negate()
1189 } else {
1190 IntervalYM::try_from_ym(year, month).unwrap()
1191 };
1192
1193 let modifier = if negate { -1 } else { 1 };
1194
1195 assert_eq!(year as i32 * modifier, interval.year().unwrap());
1196 assert_eq!(month as i32 * modifier, interval.month().unwrap());
1197
1198 assert!(interval.hour().is_none());
1199 assert!(interval.day().is_none());
1200 assert!(interval.minute().is_none());
1201 assert!(interval.second().is_none());
1202 }
1203
1204 #[test]
1205 fn test_interval_ym_extract() {
1206 test_extract_ym(false, 0, 0);
1207 test_extract_ym(false, 0, 1);
1208 test_extract_ym(false, 1, 1);
1209 test_extract_ym(false, 1234, 11);
1210 test_extract_ym(false, 178000000, 0);
1211 test_extract_ym(true, 0, 1);
1212 test_extract_ym(true, 1, 1);
1213 test_extract_ym(true, 1234, 11);
1214 test_extract_ym(true, 178000000, 0);
1215 }
1216
1217 #[allow(clippy::float_cmp)]
1218 fn test_extract_dt(negate: bool, day: u32, hour: u32, min: u32, sec: u32, usec: u32) {
1219 let interval = if negate {
1220 IntervalDT::try_from_dhms(day, hour, min, sec, usec)
1221 .unwrap()
1222 .negate()
1223 } else {
1224 IntervalDT::try_from_dhms(day, hour, min, sec, usec).unwrap()
1225 };
1226
1227 let modifier = if negate { -1 } else { 1 };
1228
1229 assert_eq!(day as i32 * modifier, interval.day().unwrap());
1230 assert_eq!(hour as i32 * modifier, interval.hour().unwrap());
1231 assert_eq!(min as i32 * modifier, interval.minute().unwrap());
1232 assert_eq!(
1233 modifier as f64 * (sec as f64 + (usec as f64) / 1_000_000f64),
1234 interval.second().unwrap()
1235 );
1236 assert!(interval.year().is_none());
1237 assert!(interval.month().is_none());
1238 }
1239
1240 #[test]
1241 fn test_interval_dt_extract() {
1242 test_extract_dt(false, 0, 0, 0, 0, 0);
1243 test_extract_dt(false, 0, 0, 0, 0, 1);
1244 test_extract_dt(false, 1, 0, 0, 0, 1);
1245 test_extract_dt(false, 9999, 23, 59, 59, 999999);
1246 test_extract_dt(false, 100000000, 0, 0, 0, 0);
1247 test_extract_dt(true, 0, 0, 0, 0, 1);
1248 test_extract_dt(true, 1, 0, 0, 0, 1);
1249 test_extract_dt(true, 9999, 23, 59, 59, 999999);
1250 test_extract_dt(true, 9999, 23, 59, 59, 375473);
1251 test_extract_dt(true, 100000000, 0, 0, 0, 0);
1252 }
1253}