1use core::default::Default;
16use std::cmp::Ordering;
17use std::fmt::{self, Display, Formatter, Write};
18use std::hash::{Hash, Hasher};
19use std::time::Duration;
20
21use arrow::datatypes::TimeUnit as ArrowTimeUnit;
22use chrono::{
23 DateTime, Days, LocalResult, Months, NaiveDate, NaiveDateTime, NaiveTime, TimeDelta,
24 TimeZone as ChronoTimeZone, Utc,
25};
26use serde::{Deserialize, Serialize};
27use snafu::{OptionExt, ResultExt};
28
29use crate::error;
30use crate::error::{ArithmeticOverflowSnafu, ParseTimestampSnafu, Result, TimestampOverflowSnafu};
31use crate::interval::{IntervalDayTime, IntervalMonthDayNano, IntervalYearMonth};
32use crate::timezone::{Timezone, get_timezone};
33use crate::util::{datetime_to_utc, div_ceil};
34
35#[derive(Clone, Default, Copy, Serialize, Deserialize)]
46pub struct Timestamp {
47 value: i64,
48 unit: TimeUnit,
49}
50
51impl Timestamp {
52 pub fn current_millis() -> Self {
54 Self {
55 value: crate::util::current_time_millis(),
56 unit: TimeUnit::Millisecond,
57 }
58 }
59
60 pub fn current_time(unit: TimeUnit) -> Timestamp {
62 let now = chrono::Utc::now();
63 let value = match unit {
64 TimeUnit::Second => now.timestamp(),
65 TimeUnit::Millisecond => now.timestamp_millis(),
66 TimeUnit::Microsecond => now.timestamp_micros(),
67 TimeUnit::Nanosecond => now.timestamp_nanos_opt().unwrap_or_default(),
68 };
69 Timestamp { value, unit }
70 }
71
72 pub fn sub_duration(&self, duration: Duration) -> error::Result<Self> {
78 let duration: i64 = match self.unit {
79 TimeUnit::Second => {
80 i64::try_from(duration.as_secs()).context(TimestampOverflowSnafu)?
81 }
82 TimeUnit::Millisecond => {
83 i64::try_from(duration.as_millis()).context(TimestampOverflowSnafu)?
84 }
85 TimeUnit::Microsecond => {
86 i64::try_from(duration.as_micros()).context(TimestampOverflowSnafu)?
87 }
88 TimeUnit::Nanosecond => {
89 i64::try_from(duration.as_nanos()).context(TimestampOverflowSnafu)?
90 }
91 };
92
93 let value = self
94 .value
95 .checked_sub(duration)
96 .with_context(|| ArithmeticOverflowSnafu {
97 msg: format!(
98 "Try to subtract timestamp: {:?} with duration: {:?}",
99 self, duration
100 ),
101 })?;
102 Ok(Timestamp {
103 value,
104 unit: self.unit,
105 })
106 }
107
108 pub fn add_duration(&self, duration: Duration) -> error::Result<Self> {
114 let duration: i64 = match self.unit {
115 TimeUnit::Second => {
116 i64::try_from(duration.as_secs()).context(TimestampOverflowSnafu)?
117 }
118 TimeUnit::Millisecond => {
119 i64::try_from(duration.as_millis()).context(TimestampOverflowSnafu)?
120 }
121 TimeUnit::Microsecond => {
122 i64::try_from(duration.as_micros()).context(TimestampOverflowSnafu)?
123 }
124 TimeUnit::Nanosecond => {
125 i64::try_from(duration.as_nanos()).context(TimestampOverflowSnafu)?
126 }
127 };
128
129 let value = self
130 .value
131 .checked_add(duration)
132 .with_context(|| ArithmeticOverflowSnafu {
133 msg: format!(
134 "Try to add timestamp: {:?} with duration: {:?}",
135 self, duration
136 ),
137 })?;
138 Ok(Timestamp {
139 value,
140 unit: self.unit,
141 })
142 }
143
144 pub fn add_year_month(&self, interval: IntervalYearMonth) -> Option<Timestamp> {
147 let naive_datetime = self.to_chrono_datetime()?;
148
149 let naive_datetime =
150 naive_datetime.checked_add_months(Months::new(interval.months as u32))?;
151
152 Timestamp::from_chrono_datetime(naive_datetime).and_then(|ts| ts.convert_to(self.unit))
154 }
155
156 pub fn add_day_time(&self, interval: IntervalDayTime) -> Option<Timestamp> {
158 let naive_datetime = self.to_chrono_datetime()?;
159
160 let naive_datetime = naive_datetime
161 .checked_add_days(Days::new(interval.days as u64))?
162 .checked_add_signed(TimeDelta::milliseconds(interval.milliseconds as i64))?;
163
164 Timestamp::from_chrono_datetime(naive_datetime).and_then(|ts| ts.convert_to(self.unit))
166 }
167
168 pub fn add_month_day_nano(&self, interval: IntervalMonthDayNano) -> Option<Timestamp> {
170 let naive_datetime = self.to_chrono_datetime()?;
171
172 let naive_datetime = naive_datetime
173 .checked_add_months(Months::new(interval.months as u32))?
174 .checked_add_days(Days::new(interval.days as u64))?
175 .checked_add_signed(TimeDelta::nanoseconds(interval.nanoseconds))?;
176
177 Timestamp::from_chrono_datetime(naive_datetime).and_then(|ts| ts.convert_to(self.unit))
179 }
180
181 pub fn sub_year_month(&self, interval: IntervalYearMonth) -> Option<Timestamp> {
183 let naive_datetime = self.to_chrono_datetime()?;
184
185 let naive_datetime =
186 naive_datetime.checked_sub_months(Months::new(interval.months as u32))?;
187
188 Timestamp::from_chrono_datetime(naive_datetime).and_then(|ts| ts.convert_to(self.unit))
190 }
191
192 pub fn sub_day_time(&self, interval: IntervalDayTime) -> Option<Timestamp> {
194 let naive_datetime = self.to_chrono_datetime()?;
195
196 let naive_datetime = naive_datetime
197 .checked_sub_days(Days::new(interval.days as u64))?
198 .checked_sub_signed(TimeDelta::milliseconds(interval.milliseconds as i64))?;
199
200 Timestamp::from_chrono_datetime(naive_datetime).and_then(|ts| ts.convert_to(self.unit))
202 }
203
204 pub fn sub_month_day_nano(&self, interval: IntervalMonthDayNano) -> Option<Timestamp> {
206 let naive_datetime = self.to_chrono_datetime()?;
207
208 let naive_datetime = naive_datetime
209 .checked_sub_months(Months::new(interval.months as u32))?
210 .checked_sub_days(Days::new(interval.days as u64))?
211 .checked_sub_signed(TimeDelta::nanoseconds(interval.nanoseconds))?;
212
213 Timestamp::from_chrono_datetime(naive_datetime).and_then(|ts| ts.convert_to(self.unit))
215 }
216
217 pub fn sub(&self, rhs: &Self) -> Option<chrono::Duration> {
219 let lhs = self.to_chrono_datetime()?;
220 let rhs = rhs.to_chrono_datetime()?;
221 Some(lhs - rhs)
222 }
223
224 pub fn new(value: i64, unit: TimeUnit) -> Self {
225 Self { unit, value }
226 }
227
228 pub const fn new_second(value: i64) -> Self {
229 Self {
230 value,
231 unit: TimeUnit::Second,
232 }
233 }
234
235 pub const fn new_millisecond(value: i64) -> Self {
236 Self {
237 value,
238 unit: TimeUnit::Millisecond,
239 }
240 }
241
242 pub const fn new_microsecond(value: i64) -> Self {
243 Self {
244 value,
245 unit: TimeUnit::Microsecond,
246 }
247 }
248
249 pub const fn new_nanosecond(value: i64) -> Self {
250 Self {
251 value,
252 unit: TimeUnit::Nanosecond,
253 }
254 }
255
256 pub fn unit(&self) -> TimeUnit {
257 self.unit
258 }
259
260 pub fn value(&self) -> i64 {
261 self.value
262 }
263
264 pub fn convert_to(&self, unit: TimeUnit) -> Option<Timestamp> {
268 if self.unit().factor() >= unit.factor() {
269 let mul = self.unit().factor() / unit.factor();
270 let value = self.value.checked_mul(mul as i64)?;
271 Some(Timestamp::new(value, unit))
272 } else {
273 let mul = unit.factor() / self.unit().factor();
274 Some(Timestamp::new(self.value.div_euclid(mul as i64), unit))
275 }
276 }
277
278 pub fn convert_to_ceil(&self, unit: TimeUnit) -> Option<Timestamp> {
283 if self.unit().factor() >= unit.factor() {
284 let mul = self.unit().factor() / unit.factor();
285 let value = self.value.checked_mul(mul as i64)?;
286 Some(Timestamp::new(value, unit))
287 } else {
288 let mul = unit.factor() / self.unit().factor();
289 Some(Timestamp::new(div_ceil(self.value, mul as i64), unit))
290 }
291 }
292
293 pub fn split(&self) -> (i64, u32) {
296 let sec_mul = (TimeUnit::Second.factor() / self.unit.factor()) as i64;
297 let nsec_mul = (self.unit.factor() / TimeUnit::Nanosecond.factor()) as i64;
298
299 let sec_div = self.value.div_euclid(sec_mul);
300 let sec_mod = self.value.rem_euclid(sec_mul);
301 let nsec = u32::try_from(sec_mod * nsec_mul).unwrap();
303 (sec_div, nsec)
304 }
305
306 fn from_splits(sec: i64, nsec: u32) -> Option<Self> {
309 if nsec == 0 {
310 Some(Timestamp::new_second(sec))
311 } else if nsec % 1_000_000 == 0 {
312 let millis = nsec / 1_000_000;
313 sec.checked_mul(1000)
314 .and_then(|v| v.checked_add(millis as i64))
315 .map(Timestamp::new_millisecond)
316 } else if nsec % 1000 == 0 {
317 let micros = nsec / 1000;
318 sec.checked_mul(1_000_000)
319 .and_then(|v| v.checked_add(micros as i64))
320 .map(Timestamp::new_microsecond)
321 } else {
322 let mut sec = sec;
334 let mut nsec = nsec as i64;
335 if sec < 0 && nsec > 0 {
336 nsec -= 1_000_000_000;
337 sec += 1;
338 }
339
340 sec.checked_mul(1_000_000_000)
341 .and_then(|v| v.checked_add(nsec))
342 .map(Timestamp::new_nanosecond)
343 }
344 }
345
346 pub fn to_iso8601_string(&self) -> String {
349 self.as_formatted_string("%Y-%m-%d %H:%M:%S%.f%z", None)
351 .unwrap()
352 }
353
354 pub fn to_local_string(&self) -> String {
356 self.as_formatted_string("%Y-%m-%d %H:%M:%S%.f", None)
358 .unwrap()
359 }
360
361 pub fn to_timezone_aware_string(&self, tz: Option<&Timezone>) -> String {
364 self.as_formatted_string("%Y-%m-%d %H:%M:%S%.f", tz)
366 .unwrap()
367 }
368
369 pub fn as_formatted_string(self, pattern: &str, timezone: Option<&Timezone>) -> Result<String> {
372 if let Some(v) = self.to_chrono_datetime() {
373 let mut formatted = String::new();
374
375 match get_timezone(timezone) {
376 Timezone::Offset(offset) => {
377 write!(
378 formatted,
379 "{}",
380 offset.from_utc_datetime(&v).format(pattern)
381 )
382 .context(crate::error::FormatSnafu { pattern })?;
383 }
384 Timezone::Named(tz) => {
385 write!(formatted, "{}", tz.from_utc_datetime(&v).format(pattern))
386 .context(crate::error::FormatSnafu { pattern })?;
387 }
388 }
389
390 Ok(formatted)
391 } else {
392 Ok(format!("[Timestamp{}: {}]", self.unit, self.value))
393 }
394 }
395
396 pub fn to_chrono_datetime(&self) -> Option<NaiveDateTime> {
397 let (sec, nsec) = self.split();
398 chrono::DateTime::from_timestamp(sec, nsec).map(|x| x.naive_utc())
399 }
400
401 pub fn to_chrono_datetime_with_timezone(&self, tz: Option<&Timezone>) -> Option<NaiveDateTime> {
402 let datetime = self.to_chrono_datetime();
403 datetime.map(|v| match tz {
404 Some(Timezone::Offset(offset)) => offset.from_utc_datetime(&v).naive_local(),
405 Some(Timezone::Named(tz)) => tz.from_utc_datetime(&v).naive_local(),
406 None => Utc.from_utc_datetime(&v).naive_local(),
407 })
408 }
409
410 pub fn to_chrono_date(&self) -> Option<NaiveDate> {
412 self.to_chrono_datetime().map(|ndt| ndt.date())
413 }
414
415 pub fn to_chrono_time(&self) -> Option<NaiveTime> {
417 self.to_chrono_datetime().map(|ndt| ndt.time())
418 }
419
420 pub fn from_chrono_datetime(ndt: NaiveDateTime) -> Option<Self> {
421 let sec = ndt.and_utc().timestamp();
422 let nsec = ndt.and_utc().timestamp_subsec_nanos();
423 Timestamp::from_splits(sec, nsec)
424 }
425
426 pub fn from_chrono_date(date: NaiveDate) -> Option<Self> {
427 Timestamp::from_chrono_datetime(date.and_time(NaiveTime::default()))
428 }
429
430 pub fn from_str_utc(s: &str) -> Result<Self> {
433 Self::from_str(s, None)
434 }
435
436 #[allow(deprecated)]
448 pub fn from_str(s: &str, timezone: Option<&Timezone>) -> Result<Self> {
449 let s = s.trim();
451 if let Ok(ts) = DateTime::parse_from_rfc3339(s) {
452 return Timestamp::from_chrono_datetime(ts.naive_utc())
453 .context(ParseTimestampSnafu { raw: s });
454 }
455 if let Ok(ts) = DateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S%.f%:z") {
456 return Timestamp::from_chrono_datetime(ts.naive_utc())
457 .context(ParseTimestampSnafu { raw: s });
458 }
459 if let Ok(ts) = chrono::Utc.datetime_from_str(s, "%Y-%m-%d %H:%M:%S%.fZ") {
460 return Timestamp::from_chrono_datetime(ts.naive_utc())
461 .context(ParseTimestampSnafu { raw: s });
462 }
463
464 if let Ok(ts) = NaiveDateTime::parse_from_str(s, "%Y-%m-%dT%H:%M:%S") {
465 return naive_datetime_to_timestamp(s, ts, timezone);
466 }
467
468 if let Ok(ts) = NaiveDateTime::parse_from_str(s, "%Y-%m-%dT%H:%M:%S%.f") {
469 return naive_datetime_to_timestamp(s, ts, timezone);
470 }
471
472 if let Ok(ts) = NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S") {
473 return naive_datetime_to_timestamp(s, ts, timezone);
474 }
475
476 if let Ok(ts) = NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S%.f") {
477 return naive_datetime_to_timestamp(s, ts, timezone);
478 }
479
480 ParseTimestampSnafu { raw: s }.fail()
481 }
482
483 pub fn negative(mut self) -> Self {
484 self.value = -self.value;
485 self
486 }
487}
488
489impl Timestamp {
490 pub const MIN_SECOND: Self = Self::new_second(-8_334_601_228_800);
491 pub const MAX_SECOND: Self = Self::new_second(8_210_266_876_799);
492
493 pub const MIN_MILLISECOND: Self = Self::new_millisecond(-8_334_601_228_800_000);
494 pub const MAX_MILLISECOND: Self = Self::new_millisecond(8_210_266_876_799_999);
495
496 pub const MIN_MICROSECOND: Self = Self::new_microsecond(-8_334_601_228_800_000_000);
497 pub const MAX_MICROSECOND: Self = Self::new_microsecond(8_210_266_876_799_999_999);
498
499 pub const MIN_NANOSECOND: Self = Self::new_nanosecond(i64::MIN);
500 pub const MAX_NANOSECOND: Self = Self::new_nanosecond(i64::MAX);
501
502 pub fn is_overflow(value: i64, unit: TimeUnit) -> bool {
504 let (min_val, max_val) = match unit {
505 TimeUnit::Second => (Self::MIN_SECOND.value(), Self::MAX_SECOND.value()),
506 TimeUnit::Millisecond => (Self::MIN_MILLISECOND.value(), Self::MAX_MILLISECOND.value()),
507 TimeUnit::Microsecond => (Self::MIN_MICROSECOND.value(), Self::MAX_MICROSECOND.value()),
508 TimeUnit::Nanosecond => (Self::MIN_NANOSECOND.value(), Self::MAX_NANOSECOND.value()),
509 };
510 value < min_val || value > max_val
511 }
512}
513
514fn naive_datetime_to_timestamp(
517 s: &str,
518 datetime: NaiveDateTime,
519 timezone: Option<&Timezone>,
520) -> crate::error::Result<Timestamp> {
521 let Some(timezone) = timezone else {
522 return Timestamp::from_chrono_datetime(Utc.from_utc_datetime(&datetime).naive_utc())
523 .context(ParseTimestampSnafu { raw: s });
524 };
525
526 match datetime_to_utc(&datetime, timezone) {
527 LocalResult::None => ParseTimestampSnafu { raw: s }.fail(),
528 LocalResult::Single(utc) | LocalResult::Ambiguous(utc, _) => {
529 Timestamp::from_chrono_datetime(utc).context(ParseTimestampSnafu { raw: s })
530 }
531 }
532}
533
534impl From<i64> for Timestamp {
535 fn from(v: i64) -> Self {
536 Self {
537 value: v,
538 unit: TimeUnit::Millisecond,
539 }
540 }
541}
542
543impl From<Timestamp> for i64 {
544 fn from(t: Timestamp) -> Self {
545 t.value
546 }
547}
548
549impl From<Timestamp> for serde_json::Value {
550 fn from(d: Timestamp) -> Self {
551 serde_json::Value::String(d.to_iso8601_string())
552 }
553}
554
555impl fmt::Debug for Timestamp {
556 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
557 write!(f, "{}::{}", self.value, self.unit)
558 }
559}
560
561#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
562pub enum TimeUnit {
563 Second,
564 #[default]
565 Millisecond,
566 Microsecond,
567 Nanosecond,
568}
569
570impl From<&ArrowTimeUnit> for TimeUnit {
571 fn from(unit: &ArrowTimeUnit) -> Self {
572 match unit {
573 ArrowTimeUnit::Second => Self::Second,
574 ArrowTimeUnit::Millisecond => Self::Millisecond,
575 ArrowTimeUnit::Microsecond => Self::Microsecond,
576 ArrowTimeUnit::Nanosecond => Self::Nanosecond,
577 }
578 }
579}
580
581impl From<ArrowTimeUnit> for TimeUnit {
582 fn from(unit: ArrowTimeUnit) -> Self {
583 (&unit).into()
584 }
585}
586
587impl Display for TimeUnit {
588 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
589 match self {
590 TimeUnit::Second => {
591 write!(f, "Second")
592 }
593 TimeUnit::Millisecond => {
594 write!(f, "Millisecond")
595 }
596 TimeUnit::Microsecond => {
597 write!(f, "Microsecond")
598 }
599 TimeUnit::Nanosecond => {
600 write!(f, "Nanosecond")
601 }
602 }
603 }
604}
605
606impl TimeUnit {
607 pub fn factor(&self) -> u32 {
608 match self {
609 TimeUnit::Second => 1_000_000_000,
610 TimeUnit::Millisecond => 1_000_000,
611 TimeUnit::Microsecond => 1_000,
612 TimeUnit::Nanosecond => 1,
613 }
614 }
615
616 pub(crate) fn short_name(&self) -> &'static str {
617 match self {
618 TimeUnit::Second => "s",
619 TimeUnit::Millisecond => "ms",
620 TimeUnit::Microsecond => "us",
621 TimeUnit::Nanosecond => "ns",
622 }
623 }
624
625 pub fn as_arrow_time_unit(&self) -> ArrowTimeUnit {
626 match self {
627 Self::Second => ArrowTimeUnit::Second,
628 Self::Millisecond => ArrowTimeUnit::Millisecond,
629 Self::Microsecond => ArrowTimeUnit::Microsecond,
630 Self::Nanosecond => ArrowTimeUnit::Nanosecond,
631 }
632 }
633}
634
635impl PartialOrd for Timestamp {
636 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
637 Some(self.cmp(other))
638 }
639}
640
641impl Ord for Timestamp {
645 fn cmp(&self, other: &Self) -> Ordering {
646 if self.unit == other.unit {
648 return self.value.cmp(&other.value);
649 }
650
651 let (s_sec, s_nsec) = self.split();
652 let (o_sec, o_nsec) = other.split();
653 match s_sec.cmp(&o_sec) {
654 Ordering::Less => Ordering::Less,
655 Ordering::Greater => Ordering::Greater,
656 Ordering::Equal => s_nsec.cmp(&o_nsec),
657 }
658 }
659}
660
661impl PartialEq for Timestamp {
662 fn eq(&self, other: &Self) -> bool {
663 self.cmp(other) == Ordering::Equal
664 }
665}
666
667impl Eq for Timestamp {}
668
669impl Hash for Timestamp {
670 fn hash<H: Hasher>(&self, state: &mut H) {
671 let (sec, nsec) = self.split();
672 state.write_i64(sec);
673 state.write_u32(nsec);
674 }
675}
676
677#[cfg(test)]
678mod tests {
679 use std::collections::hash_map::DefaultHasher;
680
681 use chrono_tz::Tz;
682 use rand::Rng;
683 use serde_json::Value;
684
685 use super::*;
686 use crate::timezone::set_default_timezone;
687
688 #[test]
689 pub fn test_time_unit() {
690 assert_eq!(
691 TimeUnit::Millisecond.factor() * 1000,
692 TimeUnit::Second.factor()
693 );
694 assert_eq!(
695 TimeUnit::Microsecond.factor() * 1000000,
696 TimeUnit::Second.factor()
697 );
698 assert_eq!(
699 TimeUnit::Nanosecond.factor() * 1000000000,
700 TimeUnit::Second.factor()
701 );
702 }
703
704 #[test]
705 pub fn test_timestamp() {
706 let t = Timestamp::new(1, TimeUnit::Millisecond);
707 assert_eq!(TimeUnit::Millisecond, t.unit());
708 assert_eq!(1, t.value());
709 assert_eq!(Timestamp::new(1000, TimeUnit::Microsecond), t);
710 assert!(t > Timestamp::new(999, TimeUnit::Microsecond));
711 }
712
713 #[test]
714 fn test_timestamp_antisymmetry() {
715 let t1 = Timestamp::new(1, TimeUnit::Second);
716 let t2 = Timestamp::new(1000, TimeUnit::Millisecond);
717 assert!(t1 >= t2);
718 assert!(t2 >= t1);
719 assert_eq!(Ordering::Equal, t1.cmp(&t2));
720 }
721
722 fn gen_random_ts() -> Timestamp {
723 let units = [
724 TimeUnit::Second,
725 TimeUnit::Millisecond,
726 TimeUnit::Microsecond,
727 TimeUnit::Nanosecond,
728 ];
729 let mut rng = rand::rng();
730 let unit_idx: usize = rng.random_range(0..4);
731 let unit = units[unit_idx];
732 let value: i64 = rng.random();
733 Timestamp::new(value, unit)
734 }
735
736 #[test]
737 fn test_add_sub_interval() {
738 let ts = Timestamp::new(1000, TimeUnit::Millisecond);
739
740 let interval = IntervalDayTime::new(1, 200);
741
742 let new_ts = ts.add_day_time(interval).unwrap();
743 assert_eq!(new_ts.unit(), TimeUnit::Millisecond);
744 assert_eq!(new_ts.value(), 1000 + 3600 * 24 * 1000 + 200);
745
746 assert_eq!(ts, new_ts.sub_day_time(interval).unwrap());
747 }
748
749 #[test]
750 fn test_timestamp_reflexivity() {
751 for _ in 0..1000 {
752 let ts = gen_random_ts();
753 assert!(ts >= ts, "ts: {ts:?}");
754 }
755 }
756
757 fn gen_ts_le(threshold: &Timestamp) -> Timestamp {
759 let mut rng = rand::rng();
760 let timestamp = rng.random_range(i64::MIN..=threshold.value);
761 Timestamp::new(timestamp, threshold.unit)
762 }
763
764 #[test]
765 fn test_timestamp_transitivity() {
766 let t0 = Timestamp::new_millisecond(100);
767 let t1 = gen_ts_le(&t0);
768 let t2 = gen_ts_le(&t1);
769 assert!(t0 >= t1, "t0: {t0:?}, t1: {t1:?}");
770 assert!(t1 >= t2, "t1: {t1:?}, t2: {t2:?}");
771 assert!(t0 >= t2, "t0: {t0:?}, t2: {t2:?}");
772
773 let t0 = Timestamp::new_millisecond(-100);
774 let t1 = gen_ts_le(&t0); let t2 = gen_ts_le(&t1); assert!(t0 >= t1, "t0: {t0:?}, t1: {t1:?}");
777 assert!(t1 >= t2, "t1: {t1:?}, t2: {t2:?}");
778 assert!(t0 >= t2, "t0: {t0:?}, t2: {t2:?}"); }
780
781 #[test]
782 fn test_antisymmetry() {
783 let t0 = Timestamp::new(1, TimeUnit::Second);
784 let t1 = Timestamp::new(1000, TimeUnit::Millisecond);
785 assert!(t0 >= t1, "t0: {t0:?}, t1: {t1:?}");
786 assert!(t1 >= t0, "t0: {t0:?}, t1: {t1:?}");
787 assert_eq!(t1, t0, "t0: {t0:?}, t1: {t1:?}");
788 }
789
790 #[test]
791 fn test_strong_connectivity() {
792 let mut values = Vec::with_capacity(1000);
793 for _ in 0..1000 {
794 values.push(gen_random_ts());
795 }
796
797 for l in &values {
798 for r in &values {
799 assert!(l >= r || l <= r, "l: {l:?}, r: {r:?}");
800 }
801 }
802 }
803
804 #[test]
805 fn test_cmp_timestamp() {
806 let t1 = Timestamp::new(0, TimeUnit::Millisecond);
807 let t2 = Timestamp::new(0, TimeUnit::Second);
808 assert_eq!(t2, t1);
809
810 let t1 = Timestamp::new(1, TimeUnit::Millisecond);
811 let t2 = Timestamp::new(-1, TimeUnit::Second);
812 assert!(t1 > t2);
813
814 let t1 = Timestamp::new(i64::MAX / 1000 * 1000, TimeUnit::Millisecond);
815 let t2 = Timestamp::new(i64::MAX / 1000, TimeUnit::Second);
816 assert_eq!(t2, t1);
817
818 let t1 = Timestamp::new(i64::MAX, TimeUnit::Millisecond);
819 let t2 = Timestamp::new(i64::MAX / 1000 + 1, TimeUnit::Second);
820 assert!(t2 > t1);
821
822 let t1 = Timestamp::new(i64::MAX, TimeUnit::Millisecond);
823 let t2 = Timestamp::new(i64::MAX / 1000, TimeUnit::Second);
824 assert!(t2 < t1);
825
826 let t1 = Timestamp::new(10_010_001, TimeUnit::Millisecond);
827 let t2 = Timestamp::new(100, TimeUnit::Second);
828 assert!(t1 > t2);
829
830 let t1 = Timestamp::new(-100 * 10_001, TimeUnit::Millisecond);
831 let t2 = Timestamp::new(-100, TimeUnit::Second);
832 assert!(t2 > t1);
833
834 let t1 = Timestamp::new(i64::MIN, TimeUnit::Millisecond);
835 let t2 = Timestamp::new(i64::MIN / 1000 - 1, TimeUnit::Second);
836 assert!(t1 > t2);
837
838 let t1 = Timestamp::new(i64::MIN, TimeUnit::Millisecond);
839 let t2 = Timestamp::new(i64::MIN + 1, TimeUnit::Millisecond);
840 assert!(t2 > t1);
841
842 let t1 = Timestamp::new(i64::MAX, TimeUnit::Millisecond);
843 let t2 = Timestamp::new(i64::MIN, TimeUnit::Second);
844 assert!(t1 > t2);
845
846 let t1 = Timestamp::new(0, TimeUnit::Nanosecond);
847 let t2 = Timestamp::new(i64::MIN, TimeUnit::Second);
848 assert!(t1 > t2);
849 }
850
851 fn check_hash_eq(t1: Timestamp, t2: Timestamp) {
852 let mut hasher = DefaultHasher::new();
853 t1.hash(&mut hasher);
854 let t1_hash = hasher.finish();
855
856 let mut hasher = DefaultHasher::new();
857 t2.hash(&mut hasher);
858 let t2_hash = hasher.finish();
859 assert_eq!(t2_hash, t1_hash);
860 }
861
862 #[test]
863 fn test_hash() {
864 check_hash_eq(
865 Timestamp::new(0, TimeUnit::Millisecond),
866 Timestamp::new(0, TimeUnit::Second),
867 );
868 check_hash_eq(
869 Timestamp::new(1000, TimeUnit::Millisecond),
870 Timestamp::new(1, TimeUnit::Second),
871 );
872 check_hash_eq(
873 Timestamp::new(1_000_000, TimeUnit::Microsecond),
874 Timestamp::new(1, TimeUnit::Second),
875 );
876 check_hash_eq(
877 Timestamp::new(1_000_000_000, TimeUnit::Nanosecond),
878 Timestamp::new(1, TimeUnit::Second),
879 );
880 }
881
882 #[test]
883 pub fn test_from_i64() {
884 let t: Timestamp = 42.into();
885 assert_eq!(42, t.value());
886 assert_eq!(TimeUnit::Millisecond, t.unit());
887 }
888
889 fn check_from_str(s: &str, expect: &str) {
892 let ts = Timestamp::from_str_utc(s).unwrap();
893 let time = ts.to_chrono_datetime().unwrap();
894 assert_eq!(expect, time.to_string());
895 }
896
897 #[test]
898 fn test_from_str() {
899 check_from_str("2020-09-08 13:42:29Z", "2020-09-08 13:42:29");
901 check_from_str("2020-09-08T13:42:29+08:00", "2020-09-08 05:42:29");
902
903 check_from_str("2020-09-08 13:42:29", "2020-09-08 13:42:29");
904
905 check_from_str("2020-09-08 13:42:29.042Z", "2020-09-08 13:42:29.042");
906 check_from_str("2020-09-08 13:42:29.042+08:00", "2020-09-08 05:42:29.042");
907
908 check_from_str(
909 "2020-09-08T13:42:29.0042+08:00",
910 "2020-09-08 05:42:29.004200",
911 );
912 }
913
914 #[test]
915 fn test_to_iso8601_string() {
916 set_default_timezone(Some("Asia/Shanghai")).unwrap();
917 let datetime_str = "2020-09-08 13:42:29.042+0000";
918 let ts = Timestamp::from_str_utc(datetime_str).unwrap();
919 assert_eq!("2020-09-08 21:42:29.042+0800", ts.to_iso8601_string());
920
921 let ts_millis = 1668070237000;
922 let ts = Timestamp::new_millisecond(ts_millis);
923 assert_eq!("2022-11-10 16:50:37+0800", ts.to_iso8601_string());
924
925 let ts_millis = -1000;
926 let ts = Timestamp::new_millisecond(ts_millis);
927 assert_eq!("1970-01-01 07:59:59+0800", ts.to_iso8601_string());
928
929 let ts_millis = -1;
930 let ts = Timestamp::new_millisecond(ts_millis);
931 assert_eq!("1970-01-01 07:59:59.999+0800", ts.to_iso8601_string());
932
933 let ts_millis = -1001;
934 let ts = Timestamp::new_millisecond(ts_millis);
935 assert_eq!("1970-01-01 07:59:58.999+0800", ts.to_iso8601_string());
936 }
937
938 #[test]
939 fn test_serialize_to_json_value() {
940 set_default_timezone(Some("Asia/Shanghai")).unwrap();
941 assert_eq!(
942 "1970-01-01 08:00:01+0800",
943 match serde_json::Value::from(Timestamp::new(1, TimeUnit::Second)) {
944 Value::String(s) => s,
945 _ => unreachable!(),
946 }
947 );
948
949 assert_eq!(
950 "1970-01-01 08:00:00.001+0800",
951 match serde_json::Value::from(Timestamp::new(1, TimeUnit::Millisecond)) {
952 Value::String(s) => s,
953 _ => unreachable!(),
954 }
955 );
956
957 assert_eq!(
958 "1970-01-01 08:00:00.000001+0800",
959 match serde_json::Value::from(Timestamp::new(1, TimeUnit::Microsecond)) {
960 Value::String(s) => s,
961 _ => unreachable!(),
962 }
963 );
964
965 assert_eq!(
966 "1970-01-01 08:00:00.000000001+0800",
967 match serde_json::Value::from(Timestamp::new(1, TimeUnit::Nanosecond)) {
968 Value::String(s) => s,
969 _ => unreachable!(),
970 }
971 );
972 }
973
974 #[test]
975 fn test_convert_timestamp() {
976 let ts = Timestamp::new(1, TimeUnit::Second);
977 assert_eq!(
978 Timestamp::new(1000, TimeUnit::Millisecond),
979 ts.convert_to(TimeUnit::Millisecond).unwrap()
980 );
981 assert_eq!(
982 Timestamp::new(1_000_000, TimeUnit::Microsecond),
983 ts.convert_to(TimeUnit::Microsecond).unwrap()
984 );
985 assert_eq!(
986 Timestamp::new(1_000_000_000, TimeUnit::Nanosecond),
987 ts.convert_to(TimeUnit::Nanosecond).unwrap()
988 );
989
990 let ts = Timestamp::new(1_000_100_100, TimeUnit::Nanosecond);
991 assert_eq!(
992 Timestamp::new(1_000_100, TimeUnit::Microsecond),
993 ts.convert_to(TimeUnit::Microsecond).unwrap()
994 );
995 assert_eq!(
996 Timestamp::new(1000, TimeUnit::Millisecond),
997 ts.convert_to(TimeUnit::Millisecond).unwrap()
998 );
999 assert_eq!(
1000 Timestamp::new(1, TimeUnit::Second),
1001 ts.convert_to(TimeUnit::Second).unwrap()
1002 );
1003
1004 let ts = Timestamp::new(1_000_100_100, TimeUnit::Nanosecond);
1005 assert_eq!(ts, ts.convert_to(TimeUnit::Nanosecond).unwrap());
1006 let ts = Timestamp::new(1_000_100_100, TimeUnit::Microsecond);
1007 assert_eq!(ts, ts.convert_to(TimeUnit::Microsecond).unwrap());
1008 let ts = Timestamp::new(1_000_100_100, TimeUnit::Millisecond);
1009 assert_eq!(ts, ts.convert_to(TimeUnit::Millisecond).unwrap());
1010 let ts = Timestamp::new(1_000_100_100, TimeUnit::Second);
1011 assert_eq!(ts, ts.convert_to(TimeUnit::Second).unwrap());
1012
1013 assert_eq!(
1015 Timestamp::new(-9223372036854776, TimeUnit::Second),
1016 Timestamp::new(i64::MIN, TimeUnit::Millisecond)
1017 .convert_to(TimeUnit::Second)
1018 .unwrap()
1019 );
1020
1021 assert!(
1022 Timestamp::new(i64::MAX, TimeUnit::Second)
1023 .convert_to(TimeUnit::Millisecond)
1024 .is_none()
1025 );
1026 }
1027
1028 #[test]
1029 fn test_split() {
1030 assert_eq!((0, 0), Timestamp::new(0, TimeUnit::Second).split());
1031 assert_eq!((1, 0), Timestamp::new(1, TimeUnit::Second).split());
1032 assert_eq!(
1033 (0, 1_000_000),
1034 Timestamp::new(1, TimeUnit::Millisecond).split()
1035 );
1036
1037 assert_eq!((0, 1_000), Timestamp::new(1, TimeUnit::Microsecond).split());
1038 assert_eq!((0, 1), Timestamp::new(1, TimeUnit::Nanosecond).split());
1039
1040 assert_eq!(
1041 (1, 1_000_000),
1042 Timestamp::new(1001, TimeUnit::Millisecond).split()
1043 );
1044
1045 assert_eq!(
1046 (-2, 999_000_000),
1047 Timestamp::new(-1001, TimeUnit::Millisecond).split()
1048 );
1049
1050 let (sec, nsec) = Timestamp::new(i64::MIN, TimeUnit::Nanosecond).split();
1052 assert_eq!(
1053 i64::MIN as i128,
1054 sec as i128 * (TimeUnit::Second.factor() / TimeUnit::Nanosecond.factor()) as i128
1055 + nsec as i128
1056 );
1057
1058 assert_eq!(
1059 (i64::MAX, 0),
1060 Timestamp::new(i64::MAX, TimeUnit::Second).split()
1061 );
1062 }
1063
1064 #[test]
1065 fn test_convert_to_ceil() {
1066 assert_eq!(
1067 Timestamp::new(1, TimeUnit::Second),
1068 Timestamp::new(1000, TimeUnit::Millisecond)
1069 .convert_to_ceil(TimeUnit::Second)
1070 .unwrap()
1071 );
1072
1073 assert_eq!(
1076 Timestamp::new(1, TimeUnit::Second),
1077 Timestamp::new(1001, TimeUnit::Millisecond)
1078 .convert_to(TimeUnit::Second)
1079 .unwrap()
1080 );
1081 assert_eq!(
1082 Timestamp::new(2, TimeUnit::Second),
1083 Timestamp::new(1001, TimeUnit::Millisecond)
1084 .convert_to_ceil(TimeUnit::Second)
1085 .unwrap()
1086 );
1087
1088 assert_eq!(
1089 Timestamp::new(-1, TimeUnit::Second),
1090 Timestamp::new(-1, TimeUnit::Millisecond)
1091 .convert_to(TimeUnit::Second)
1092 .unwrap()
1093 );
1094 assert_eq!(
1095 Timestamp::new(0, TimeUnit::Second),
1096 Timestamp::new(-1, TimeUnit::Millisecond)
1097 .convert_to_ceil(TimeUnit::Second)
1098 .unwrap()
1099 );
1100
1101 assert_eq!(
1104 Timestamp::new(-1, TimeUnit::Second).convert_to(TimeUnit::Millisecond),
1105 Timestamp::new(-1, TimeUnit::Second).convert_to_ceil(TimeUnit::Millisecond)
1106 );
1107 assert_eq!(
1108 Timestamp::new(1000, TimeUnit::Second).convert_to(TimeUnit::Millisecond),
1109 Timestamp::new(1000, TimeUnit::Second).convert_to_ceil(TimeUnit::Millisecond)
1110 );
1111 assert_eq!(
1112 Timestamp::new(1, TimeUnit::Second).convert_to(TimeUnit::Millisecond),
1113 Timestamp::new(1, TimeUnit::Second).convert_to_ceil(TimeUnit::Millisecond)
1114 );
1115 }
1116
1117 #[test]
1118 fn test_split_overflow() {
1119 let _ = Timestamp::new(i64::MAX, TimeUnit::Second).split();
1120 let _ = Timestamp::new(i64::MIN, TimeUnit::Second).split();
1121 let _ = Timestamp::new(i64::MAX, TimeUnit::Millisecond).split();
1122 let _ = Timestamp::new(i64::MIN, TimeUnit::Millisecond).split();
1123 let _ = Timestamp::new(i64::MAX, TimeUnit::Microsecond).split();
1124 let _ = Timestamp::new(i64::MIN, TimeUnit::Microsecond).split();
1125 let _ = Timestamp::new(i64::MAX, TimeUnit::Nanosecond).split();
1126 let _ = Timestamp::new(i64::MIN, TimeUnit::Nanosecond).split();
1127 let (sec, nsec) = Timestamp::new(i64::MIN, TimeUnit::Nanosecond).split();
1128 let time = DateTime::from_timestamp(sec, nsec).unwrap().naive_utc();
1129 assert_eq!(sec, time.and_utc().timestamp());
1130 assert_eq!(nsec, time.and_utc().timestamp_subsec_nanos());
1131 }
1132
1133 #[test]
1134 fn test_timestamp_sub() {
1135 let res = Timestamp::new(1, TimeUnit::Second)
1136 .sub_duration(Duration::from_secs(1))
1137 .unwrap();
1138 assert_eq!(0, res.value);
1139 assert_eq!(TimeUnit::Second, res.unit);
1140
1141 let res = Timestamp::new(0, TimeUnit::Second)
1142 .sub_duration(Duration::from_secs(1))
1143 .unwrap();
1144 assert_eq!(-1, res.value);
1145 assert_eq!(TimeUnit::Second, res.unit);
1146
1147 let res = Timestamp::new(1, TimeUnit::Second)
1148 .sub_duration(Duration::from_millis(1))
1149 .unwrap();
1150 assert_eq!(1, res.value);
1151 assert_eq!(TimeUnit::Second, res.unit);
1152 }
1153
1154 #[test]
1155 fn test_timestamp_add() {
1156 let res = Timestamp::new(1, TimeUnit::Second)
1157 .add_duration(Duration::from_secs(1))
1158 .unwrap();
1159 assert_eq!(2, res.value);
1160 assert_eq!(TimeUnit::Second, res.unit);
1161
1162 let res = Timestamp::new(0, TimeUnit::Second)
1163 .add_duration(Duration::from_secs(1))
1164 .unwrap();
1165 assert_eq!(1, res.value);
1166 assert_eq!(TimeUnit::Second, res.unit);
1167
1168 let res = Timestamp::new(1, TimeUnit::Second)
1169 .add_duration(Duration::from_millis(1))
1170 .unwrap();
1171 assert_eq!(1, res.value);
1172 assert_eq!(TimeUnit::Second, res.unit);
1173
1174 let res = Timestamp::new(100, TimeUnit::Second)
1175 .add_duration(Duration::from_millis(1000))
1176 .unwrap();
1177 assert_eq!(101, res.value);
1178 assert_eq!(TimeUnit::Second, res.unit);
1179 }
1180
1181 #[test]
1183 fn test_parse_in_timezone() {
1184 unsafe {
1185 std::env::set_var("TZ", "Asia/Shanghai");
1186 }
1187 assert_eq!(
1188 Timestamp::new(28800, TimeUnit::Second),
1189 Timestamp::from_str_utc("1970-01-01 08:00:00.000").unwrap()
1190 );
1191
1192 assert_eq!(
1193 Timestamp::new(28800, TimeUnit::Second),
1194 Timestamp::from_str_utc("1970-01-01 08:00:00").unwrap()
1195 );
1196
1197 assert_eq!(
1198 Timestamp::new(28800, TimeUnit::Second),
1199 Timestamp::from_str_utc(" 1970-01-01 08:00:00 ").unwrap()
1200 );
1201 }
1202
1203 #[test]
1204 fn test_to_local_string() {
1205 set_default_timezone(Some("Asia/Shanghai")).unwrap();
1206
1207 assert_eq!(
1208 "1970-01-01 08:00:00.000000001",
1209 Timestamp::new(1, TimeUnit::Nanosecond).to_local_string()
1210 );
1211
1212 assert_eq!(
1213 "1970-01-01 08:00:00.001",
1214 Timestamp::new(1, TimeUnit::Millisecond).to_local_string()
1215 );
1216
1217 assert_eq!(
1218 "1970-01-01 08:00:01",
1219 Timestamp::new(1, TimeUnit::Second).to_local_string()
1220 );
1221 }
1222
1223 #[test]
1224 fn test_subtract_timestamp() {
1225 assert_eq!(
1226 chrono::Duration::try_milliseconds(42),
1227 Timestamp::new_millisecond(100).sub(&Timestamp::new_millisecond(58))
1228 );
1229
1230 assert_eq!(
1231 chrono::Duration::try_milliseconds(-42),
1232 Timestamp::new_millisecond(58).sub(&Timestamp::new_millisecond(100))
1233 );
1234 }
1235
1236 #[test]
1237 fn test_to_timezone_aware_string() {
1238 set_default_timezone(Some("Asia/Shanghai")).unwrap();
1239 unsafe {
1240 std::env::set_var("TZ", "Asia/Shanghai");
1241 }
1242 assert_eq!(
1243 "1970-01-01 08:00:00.001",
1244 Timestamp::new(1, TimeUnit::Millisecond)
1245 .to_timezone_aware_string(Some(&Timezone::from_tz_string("SYSTEM").unwrap()))
1246 );
1247 assert_eq!(
1248 "1970-01-01 08:00:00.001",
1249 Timestamp::new(1, TimeUnit::Millisecond)
1250 .to_timezone_aware_string(Some(&Timezone::from_tz_string("SYSTEM").unwrap()))
1251 );
1252 assert_eq!(
1253 "1970-01-01 08:00:00.001",
1254 Timestamp::new(1, TimeUnit::Millisecond)
1255 .to_timezone_aware_string(Some(&Timezone::from_tz_string("+08:00").unwrap()))
1256 );
1257 assert_eq!(
1258 "1970-01-01 07:00:00.001",
1259 Timestamp::new(1, TimeUnit::Millisecond)
1260 .to_timezone_aware_string(Some(&Timezone::from_tz_string("+07:00").unwrap()))
1261 );
1262 assert_eq!(
1263 "1969-12-31 23:00:00.001",
1264 Timestamp::new(1, TimeUnit::Millisecond)
1265 .to_timezone_aware_string(Some(&Timezone::from_tz_string("-01:00").unwrap()))
1266 );
1267 assert_eq!(
1268 "1970-01-01 08:00:00.001",
1269 Timestamp::new(1, TimeUnit::Millisecond).to_timezone_aware_string(Some(
1270 &Timezone::from_tz_string("Asia/Shanghai").unwrap()
1271 ))
1272 );
1273 assert_eq!(
1274 "1970-01-01 00:00:00.001",
1275 Timestamp::new(1, TimeUnit::Millisecond)
1276 .to_timezone_aware_string(Some(&Timezone::from_tz_string("UTC").unwrap()))
1277 );
1278 assert_eq!(
1279 "1970-01-01 01:00:00.001",
1280 Timestamp::new(1, TimeUnit::Millisecond).to_timezone_aware_string(Some(
1281 &Timezone::from_tz_string("Europe/Berlin").unwrap()
1282 ))
1283 );
1284 assert_eq!(
1285 "1970-01-01 03:00:00.001",
1286 Timestamp::new(1, TimeUnit::Millisecond).to_timezone_aware_string(Some(
1287 &Timezone::from_tz_string("Europe/Moscow").unwrap()
1288 ))
1289 );
1290 }
1291
1292 #[test]
1293 fn test_as_formatted_string() {
1294 let ts = Timestamp::new(1, TimeUnit::Millisecond);
1295
1296 assert_eq!(
1297 "1970-01-01",
1298 ts.as_formatted_string("%Y-%m-%d", None).unwrap()
1299 );
1300 assert_eq!(
1301 "1970-01-01 00:00:00",
1302 ts.as_formatted_string("%Y-%m-%d %H:%M:%S", None).unwrap()
1303 );
1304 assert_eq!(
1305 "1970-01-01T00:00:00:001",
1306 ts.as_formatted_string("%Y-%m-%dT%H:%M:%S:%3f", None)
1307 .unwrap()
1308 );
1309 assert_eq!(
1310 "1970-01-01T08:00:00:001",
1311 ts.as_formatted_string(
1312 "%Y-%m-%dT%H:%M:%S:%3f",
1313 Some(&Timezone::from_tz_string("Asia/Shanghai").unwrap())
1314 )
1315 .unwrap()
1316 );
1317 }
1318
1319 #[test]
1320 fn test_from_arrow_time_unit() {
1321 assert_eq!(TimeUnit::Second, TimeUnit::from(ArrowTimeUnit::Second));
1322 assert_eq!(
1323 TimeUnit::Millisecond,
1324 TimeUnit::from(ArrowTimeUnit::Millisecond)
1325 );
1326 assert_eq!(
1327 TimeUnit::Microsecond,
1328 TimeUnit::from(ArrowTimeUnit::Microsecond)
1329 );
1330 assert_eq!(
1331 TimeUnit::Nanosecond,
1332 TimeUnit::from(ArrowTimeUnit::Nanosecond)
1333 );
1334 }
1335
1336 fn check_conversion(ts: Timestamp, valid: bool) {
1337 let Some(t2) = ts.to_chrono_datetime() else {
1338 if valid {
1339 panic!("Cannot convert {:?} to Chrono NaiveDateTime", ts);
1340 }
1341 return;
1342 };
1343 let Some(t3) = Timestamp::from_chrono_datetime(t2) else {
1344 if valid {
1345 panic!("Cannot convert Chrono NaiveDateTime {:?} to Timestamp", t2);
1346 }
1347 return;
1348 };
1349
1350 assert_eq!(t3, ts);
1351 }
1352
1353 #[test]
1354 fn test_from_naive_date_time() {
1355 let naive_date_time_min = NaiveDateTime::MIN.and_utc();
1356 let naive_date_time_max = NaiveDateTime::MAX.and_utc();
1357
1358 let min_sec = Timestamp::new_second(naive_date_time_min.timestamp());
1359 let max_sec = Timestamp::new_second(naive_date_time_max.timestamp());
1360 check_conversion(min_sec, true);
1361 check_conversion(Timestamp::new_second(min_sec.value - 1), false);
1362 check_conversion(max_sec, true);
1363 check_conversion(Timestamp::new_second(max_sec.value + 1), false);
1364
1365 let min_millis = Timestamp::new_millisecond(naive_date_time_min.timestamp_millis());
1366 let max_millis = Timestamp::new_millisecond(naive_date_time_max.timestamp_millis());
1367 check_conversion(min_millis, true);
1368 check_conversion(Timestamp::new_millisecond(min_millis.value - 1), false);
1369 check_conversion(max_millis, true);
1370 check_conversion(Timestamp::new_millisecond(max_millis.value + 1), false);
1371
1372 let min_micros = Timestamp::new_microsecond(naive_date_time_min.timestamp_micros());
1373 let max_micros = Timestamp::new_microsecond(naive_date_time_max.timestamp_micros());
1374 check_conversion(min_micros, true);
1375 check_conversion(Timestamp::new_microsecond(min_micros.value - 1), false);
1376 check_conversion(max_micros, true);
1377 check_conversion(Timestamp::new_microsecond(max_micros.value + 1), false);
1378
1379 let min_nanos = Timestamp::new_nanosecond(-9223372036854775000);
1381 let max_nanos = Timestamp::new_nanosecond(i64::MAX);
1382 check_conversion(min_nanos, true);
1383 check_conversion(Timestamp::new_nanosecond(min_nanos.value - 1), false);
1384 check_conversion(max_nanos, true);
1385 }
1386
1387 #[test]
1388 fn test_parse_timestamp_range() {
1389 let datetime_min = NaiveDateTime::MIN.format("%Y-%m-%d %H:%M:%SZ").to_string();
1390 assert_eq!("-262143-01-01 00:00:00Z", datetime_min);
1391 let datetime_max = NaiveDateTime::MAX.format("%Y-%m-%d %H:%M:%SZ").to_string();
1392 assert_eq!("+262142-12-31 23:59:59Z", datetime_max);
1393
1394 let valid_strings = vec![
1395 "-262143-01-01 00:00:00Z",
1396 "+262142-12-31 23:59:59Z",
1397 "+262142-12-31 23:59:59.999Z",
1398 "+262142-12-31 23:59:59.999999Z",
1399 "1677-09-21 00:12:43.145224192Z",
1400 "2262-04-11 23:47:16.854775807Z",
1401 "+100000-01-01 00:00:01.5Z",
1402 ];
1403
1404 for s in valid_strings {
1405 Timestamp::from_str_utc(s).unwrap();
1406 }
1407 }
1408
1409 #[test]
1410 fn test_min_nanos_roundtrip() {
1411 let (sec, nsec) = Timestamp::MIN_NANOSECOND.split();
1412 let ts = Timestamp::from_splits(sec, nsec).unwrap();
1413 assert_eq!(Timestamp::MIN_NANOSECOND, ts);
1414 }
1415
1416 #[test]
1417 fn test_timestamp_bound_format() {
1418 assert_eq!(
1419 "1677-09-21 00:12:43.145224192",
1420 Timestamp::MIN_NANOSECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1421 );
1422 assert_eq!(
1423 "2262-04-11 23:47:16.854775807",
1424 Timestamp::MAX_NANOSECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1425 );
1426 assert_eq!(
1427 "-262143-01-01 00:00:00",
1428 Timestamp::MIN_MICROSECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1429 );
1430 assert_eq!(
1431 "+262142-12-31 23:59:59.999999",
1432 Timestamp::MAX_MICROSECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1433 );
1434 assert_eq!(
1435 "-262143-01-01 00:00:00",
1436 Timestamp::MIN_MILLISECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1437 );
1438 assert_eq!(
1439 "+262142-12-31 23:59:59.999",
1440 Timestamp::MAX_MILLISECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1441 );
1442 assert_eq!(
1443 "-262143-01-01 00:00:00",
1444 Timestamp::MIN_SECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1445 );
1446 assert_eq!(
1447 "+262142-12-31 23:59:59",
1448 Timestamp::MAX_SECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1449 );
1450 }
1451
1452 #[test]
1453 fn test_debug_timestamp() {
1454 assert_eq!(
1455 "1000::Second",
1456 format!("{:?}", Timestamp::new(1000, TimeUnit::Second))
1457 );
1458 assert_eq!(
1459 "1001::Millisecond",
1460 format!("{:?}", Timestamp::new(1001, TimeUnit::Millisecond))
1461 );
1462 assert_eq!(
1463 "1002::Microsecond",
1464 format!("{:?}", Timestamp::new(1002, TimeUnit::Microsecond))
1465 );
1466 assert_eq!(
1467 "1003::Nanosecond",
1468 format!("{:?}", Timestamp::new(1003, TimeUnit::Nanosecond))
1469 );
1470 }
1471}