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, Offset, 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.is_multiple_of(1_000_000) {
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.is_multiple_of(1_000) {
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 utc = self.to_chrono_datetime()?;
403 match tz {
404 None => Some(utc),
405 Some(Timezone::Offset(offset)) => utc.checked_add_offset(*offset),
406 Some(Timezone::Named(tz)) => {
407 let offset = tz.offset_from_utc_datetime(&utc).fix();
408 utc.checked_add_offset(offset)
409 }
410 }
411 }
412
413 pub fn to_chrono_date(&self) -> Option<NaiveDate> {
415 self.to_chrono_datetime().map(|ndt| ndt.date())
416 }
417
418 pub fn to_chrono_time(&self) -> Option<NaiveTime> {
420 self.to_chrono_datetime().map(|ndt| ndt.time())
421 }
422
423 pub fn from_chrono_datetime(ndt: NaiveDateTime) -> Option<Self> {
424 let sec = ndt.and_utc().timestamp();
425 let nsec = ndt.and_utc().timestamp_subsec_nanos();
426 Timestamp::from_splits(sec, nsec)
427 }
428
429 pub fn from_chrono_date(date: NaiveDate) -> Option<Self> {
430 Timestamp::from_chrono_datetime(date.and_time(NaiveTime::default()))
431 }
432
433 pub fn from_str_utc(s: &str) -> Result<Self> {
436 Self::from_str(s, None)
437 }
438
439 #[allow(deprecated)]
451 pub fn from_str(s: &str, timezone: Option<&Timezone>) -> Result<Self> {
452 let s = s.trim();
454 if let Ok(ts) = DateTime::parse_from_rfc3339(s) {
455 return Timestamp::from_chrono_datetime(ts.naive_utc())
456 .context(ParseTimestampSnafu { raw: s });
457 }
458 if let Ok(ts) = DateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S%.f%:z") {
459 return Timestamp::from_chrono_datetime(ts.naive_utc())
460 .context(ParseTimestampSnafu { raw: s });
461 }
462 if let Ok(ts) = chrono::Utc.datetime_from_str(s, "%Y-%m-%d %H:%M:%S%.fZ") {
463 return Timestamp::from_chrono_datetime(ts.naive_utc())
464 .context(ParseTimestampSnafu { raw: s });
465 }
466
467 if let Ok(ts) = NaiveDateTime::parse_from_str(s, "%Y-%m-%dT%H:%M:%S") {
468 return naive_datetime_to_timestamp(s, ts, timezone);
469 }
470
471 if let Ok(ts) = NaiveDateTime::parse_from_str(s, "%Y-%m-%dT%H:%M:%S%.f") {
472 return naive_datetime_to_timestamp(s, ts, timezone);
473 }
474
475 if let Ok(ts) = NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S") {
476 return naive_datetime_to_timestamp(s, ts, timezone);
477 }
478
479 if let Ok(ts) = NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S%.f") {
480 return naive_datetime_to_timestamp(s, ts, timezone);
481 }
482
483 ParseTimestampSnafu { raw: s }.fail()
484 }
485
486 pub fn negative(mut self) -> Self {
487 self.value = -self.value;
488 self
489 }
490
491 pub fn checked_negative(mut self) -> Option<Self> {
492 self.value = self.value.checked_neg()?;
493 Some(self)
494 }
495}
496
497impl Timestamp {
498 pub const MIN_SECOND: Self = Self::new_second(-8_334_601_228_800);
499 pub const MAX_SECOND: Self = Self::new_second(8_210_266_876_799);
500
501 pub const MIN_MILLISECOND: Self = Self::new_millisecond(-8_334_601_228_800_000);
502 pub const MAX_MILLISECOND: Self = Self::new_millisecond(8_210_266_876_799_999);
503
504 pub const MIN_MICROSECOND: Self = Self::new_microsecond(-8_334_601_228_800_000_000);
505 pub const MAX_MICROSECOND: Self = Self::new_microsecond(8_210_266_876_799_999_999);
506
507 pub const MIN_NANOSECOND: Self = Self::new_nanosecond(i64::MIN);
508 pub const MAX_NANOSECOND: Self = Self::new_nanosecond(i64::MAX);
509
510 pub fn is_overflow(value: i64, unit: TimeUnit) -> bool {
512 let (min_val, max_val) = match unit {
513 TimeUnit::Second => (Self::MIN_SECOND.value(), Self::MAX_SECOND.value()),
514 TimeUnit::Millisecond => (Self::MIN_MILLISECOND.value(), Self::MAX_MILLISECOND.value()),
515 TimeUnit::Microsecond => (Self::MIN_MICROSECOND.value(), Self::MAX_MICROSECOND.value()),
516 TimeUnit::Nanosecond => (Self::MIN_NANOSECOND.value(), Self::MAX_NANOSECOND.value()),
517 };
518 value < min_val || value > max_val
519 }
520}
521
522fn naive_datetime_to_timestamp(
525 s: &str,
526 datetime: NaiveDateTime,
527 timezone: Option<&Timezone>,
528) -> crate::error::Result<Timestamp> {
529 let Some(timezone) = timezone else {
530 return Timestamp::from_chrono_datetime(Utc.from_utc_datetime(&datetime).naive_utc())
531 .context(ParseTimestampSnafu { raw: s });
532 };
533
534 match datetime_to_utc(&datetime, timezone) {
535 LocalResult::None => ParseTimestampSnafu { raw: s }.fail(),
536 LocalResult::Single(utc) | LocalResult::Ambiguous(utc, _) => {
537 Timestamp::from_chrono_datetime(utc).context(ParseTimestampSnafu { raw: s })
538 }
539 }
540}
541
542impl From<i64> for Timestamp {
543 fn from(v: i64) -> Self {
544 Self {
545 value: v,
546 unit: TimeUnit::Millisecond,
547 }
548 }
549}
550
551impl From<Timestamp> for i64 {
552 fn from(t: Timestamp) -> Self {
553 t.value
554 }
555}
556
557impl From<Timestamp> for serde_json::Value {
558 fn from(d: Timestamp) -> Self {
559 serde_json::Value::String(d.to_iso8601_string())
560 }
561}
562
563impl fmt::Debug for Timestamp {
564 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
565 write!(f, "{}::{}", self.value, self.unit)
566 }
567}
568
569#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
570pub enum TimeUnit {
571 Second,
572 #[default]
573 Millisecond,
574 Microsecond,
575 Nanosecond,
576}
577
578impl From<&ArrowTimeUnit> for TimeUnit {
579 fn from(unit: &ArrowTimeUnit) -> Self {
580 match unit {
581 ArrowTimeUnit::Second => Self::Second,
582 ArrowTimeUnit::Millisecond => Self::Millisecond,
583 ArrowTimeUnit::Microsecond => Self::Microsecond,
584 ArrowTimeUnit::Nanosecond => Self::Nanosecond,
585 }
586 }
587}
588
589impl From<ArrowTimeUnit> for TimeUnit {
590 fn from(unit: ArrowTimeUnit) -> Self {
591 (&unit).into()
592 }
593}
594
595impl Display for TimeUnit {
596 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
597 match self {
598 TimeUnit::Second => {
599 write!(f, "Second")
600 }
601 TimeUnit::Millisecond => {
602 write!(f, "Millisecond")
603 }
604 TimeUnit::Microsecond => {
605 write!(f, "Microsecond")
606 }
607 TimeUnit::Nanosecond => {
608 write!(f, "Nanosecond")
609 }
610 }
611 }
612}
613
614impl TimeUnit {
615 pub fn factor(&self) -> u32 {
616 match self {
617 TimeUnit::Second => 1_000_000_000,
618 TimeUnit::Millisecond => 1_000_000,
619 TimeUnit::Microsecond => 1_000,
620 TimeUnit::Nanosecond => 1,
621 }
622 }
623
624 pub(crate) fn short_name(&self) -> &'static str {
625 match self {
626 TimeUnit::Second => "s",
627 TimeUnit::Millisecond => "ms",
628 TimeUnit::Microsecond => "us",
629 TimeUnit::Nanosecond => "ns",
630 }
631 }
632
633 pub fn as_arrow_time_unit(&self) -> ArrowTimeUnit {
634 match self {
635 Self::Second => ArrowTimeUnit::Second,
636 Self::Millisecond => ArrowTimeUnit::Millisecond,
637 Self::Microsecond => ArrowTimeUnit::Microsecond,
638 Self::Nanosecond => ArrowTimeUnit::Nanosecond,
639 }
640 }
641}
642
643impl PartialOrd for Timestamp {
644 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
645 Some(self.cmp(other))
646 }
647}
648
649impl Ord for Timestamp {
653 fn cmp(&self, other: &Self) -> Ordering {
654 if self.unit == other.unit {
656 return self.value.cmp(&other.value);
657 }
658
659 let (s_sec, s_nsec) = self.split();
660 let (o_sec, o_nsec) = other.split();
661 match s_sec.cmp(&o_sec) {
662 Ordering::Less => Ordering::Less,
663 Ordering::Greater => Ordering::Greater,
664 Ordering::Equal => s_nsec.cmp(&o_nsec),
665 }
666 }
667}
668
669impl PartialEq for Timestamp {
670 fn eq(&self, other: &Self) -> bool {
671 self.cmp(other) == Ordering::Equal
672 }
673}
674
675impl Eq for Timestamp {}
676
677impl Hash for Timestamp {
678 fn hash<H: Hasher>(&self, state: &mut H) {
679 let (sec, nsec) = self.split();
680 state.write_i64(sec);
681 state.write_u32(nsec);
682 }
683}
684
685#[cfg(test)]
686mod tests {
687 use std::collections::hash_map::DefaultHasher;
688
689 use chrono_tz::Tz;
690 use rand::Rng;
691 use serde_json::Value;
692
693 use super::*;
694 use crate::timezone::set_default_timezone;
695
696 #[test]
697 pub fn test_time_unit() {
698 assert_eq!(
699 TimeUnit::Millisecond.factor() * 1000,
700 TimeUnit::Second.factor()
701 );
702 assert_eq!(
703 TimeUnit::Microsecond.factor() * 1000000,
704 TimeUnit::Second.factor()
705 );
706 assert_eq!(
707 TimeUnit::Nanosecond.factor() * 1000000000,
708 TimeUnit::Second.factor()
709 );
710 }
711
712 #[test]
713 pub fn test_timestamp() {
714 let t = Timestamp::new(1, TimeUnit::Millisecond);
715 assert_eq!(TimeUnit::Millisecond, t.unit());
716 assert_eq!(1, t.value());
717 assert_eq!(Timestamp::new(1000, TimeUnit::Microsecond), t);
718 assert!(t > Timestamp::new(999, TimeUnit::Microsecond));
719 }
720
721 #[test]
722 fn test_timestamp_antisymmetry() {
723 let t1 = Timestamp::new(1, TimeUnit::Second);
724 let t2 = Timestamp::new(1000, TimeUnit::Millisecond);
725 assert!(t1 >= t2);
726 assert!(t2 >= t1);
727 assert_eq!(Ordering::Equal, t1.cmp(&t2));
728 }
729
730 fn gen_random_ts() -> Timestamp {
731 let units = [
732 TimeUnit::Second,
733 TimeUnit::Millisecond,
734 TimeUnit::Microsecond,
735 TimeUnit::Nanosecond,
736 ];
737 let mut rng = rand::rng();
738 let unit_idx: usize = rng.random_range(0..4);
739 let unit = units[unit_idx];
740 let value: i64 = rng.random();
741 Timestamp::new(value, unit)
742 }
743
744 #[test]
745 fn test_add_sub_interval() {
746 let ts = Timestamp::new(1000, TimeUnit::Millisecond);
747
748 let interval = IntervalDayTime::new(1, 200);
749
750 let new_ts = ts.add_day_time(interval).unwrap();
751 assert_eq!(new_ts.unit(), TimeUnit::Millisecond);
752 assert_eq!(new_ts.value(), 1000 + 3600 * 24 * 1000 + 200);
753
754 assert_eq!(ts, new_ts.sub_day_time(interval).unwrap());
755 }
756
757 #[test]
758 fn test_timestamp_reflexivity() {
759 for _ in 0..1000 {
760 let ts = gen_random_ts();
761 assert!(ts >= ts, "ts: {ts:?}");
762 }
763 }
764
765 fn gen_ts_le(threshold: &Timestamp) -> Timestamp {
767 let mut rng = rand::rng();
768 let timestamp = rng.random_range(i64::MIN..=threshold.value);
769 Timestamp::new(timestamp, threshold.unit)
770 }
771
772 #[test]
773 fn test_timestamp_transitivity() {
774 let t0 = Timestamp::new_millisecond(100);
775 let t1 = gen_ts_le(&t0);
776 let t2 = gen_ts_le(&t1);
777 assert!(t0 >= t1, "t0: {t0:?}, t1: {t1:?}");
778 assert!(t1 >= t2, "t1: {t1:?}, t2: {t2:?}");
779 assert!(t0 >= t2, "t0: {t0:?}, t2: {t2:?}");
780
781 let t0 = Timestamp::new_millisecond(-100);
782 let t1 = gen_ts_le(&t0); let t2 = gen_ts_le(&t1); assert!(t0 >= t1, "t0: {t0:?}, t1: {t1:?}");
785 assert!(t1 >= t2, "t1: {t1:?}, t2: {t2:?}");
786 assert!(t0 >= t2, "t0: {t0:?}, t2: {t2:?}"); }
788
789 #[test]
790 fn test_antisymmetry() {
791 let t0 = Timestamp::new(1, TimeUnit::Second);
792 let t1 = Timestamp::new(1000, TimeUnit::Millisecond);
793 assert!(t0 >= t1, "t0: {t0:?}, t1: {t1:?}");
794 assert!(t1 >= t0, "t0: {t0:?}, t1: {t1:?}");
795 assert_eq!(t1, t0, "t0: {t0:?}, t1: {t1:?}");
796 }
797
798 #[test]
799 fn test_strong_connectivity() {
800 let mut values = Vec::with_capacity(1000);
801 for _ in 0..1000 {
802 values.push(gen_random_ts());
803 }
804
805 for l in &values {
806 for r in &values {
807 assert!(l >= r || l <= r, "l: {l:?}, r: {r:?}");
808 }
809 }
810 }
811
812 #[test]
813 fn test_cmp_timestamp() {
814 let t1 = Timestamp::new(0, TimeUnit::Millisecond);
815 let t2 = Timestamp::new(0, TimeUnit::Second);
816 assert_eq!(t2, t1);
817
818 let t1 = Timestamp::new(1, TimeUnit::Millisecond);
819 let t2 = Timestamp::new(-1, TimeUnit::Second);
820 assert!(t1 > t2);
821
822 let t1 = Timestamp::new(i64::MAX / 1000 * 1000, TimeUnit::Millisecond);
823 let t2 = Timestamp::new(i64::MAX / 1000, TimeUnit::Second);
824 assert_eq!(t2, t1);
825
826 let t1 = Timestamp::new(i64::MAX, TimeUnit::Millisecond);
827 let t2 = Timestamp::new(i64::MAX / 1000 + 1, TimeUnit::Second);
828 assert!(t2 > t1);
829
830 let t1 = Timestamp::new(i64::MAX, TimeUnit::Millisecond);
831 let t2 = Timestamp::new(i64::MAX / 1000, TimeUnit::Second);
832 assert!(t2 < t1);
833
834 let t1 = Timestamp::new(10_010_001, TimeUnit::Millisecond);
835 let t2 = Timestamp::new(100, TimeUnit::Second);
836 assert!(t1 > t2);
837
838 let t1 = Timestamp::new(-100 * 10_001, TimeUnit::Millisecond);
839 let t2 = Timestamp::new(-100, TimeUnit::Second);
840 assert!(t2 > t1);
841
842 let t1 = Timestamp::new(i64::MIN, TimeUnit::Millisecond);
843 let t2 = Timestamp::new(i64::MIN / 1000 - 1, TimeUnit::Second);
844 assert!(t1 > t2);
845
846 let t1 = Timestamp::new(i64::MIN, TimeUnit::Millisecond);
847 let t2 = Timestamp::new(i64::MIN + 1, TimeUnit::Millisecond);
848 assert!(t2 > t1);
849
850 let t1 = Timestamp::new(i64::MAX, TimeUnit::Millisecond);
851 let t2 = Timestamp::new(i64::MIN, TimeUnit::Second);
852 assert!(t1 > t2);
853
854 let t1 = Timestamp::new(0, TimeUnit::Nanosecond);
855 let t2 = Timestamp::new(i64::MIN, TimeUnit::Second);
856 assert!(t1 > t2);
857 }
858
859 fn check_hash_eq(t1: Timestamp, t2: Timestamp) {
860 let mut hasher = DefaultHasher::new();
861 t1.hash(&mut hasher);
862 let t1_hash = hasher.finish();
863
864 let mut hasher = DefaultHasher::new();
865 t2.hash(&mut hasher);
866 let t2_hash = hasher.finish();
867 assert_eq!(t2_hash, t1_hash);
868 }
869
870 #[test]
871 fn test_hash() {
872 check_hash_eq(
873 Timestamp::new(0, TimeUnit::Millisecond),
874 Timestamp::new(0, TimeUnit::Second),
875 );
876 check_hash_eq(
877 Timestamp::new(1000, TimeUnit::Millisecond),
878 Timestamp::new(1, TimeUnit::Second),
879 );
880 check_hash_eq(
881 Timestamp::new(1_000_000, TimeUnit::Microsecond),
882 Timestamp::new(1, TimeUnit::Second),
883 );
884 check_hash_eq(
885 Timestamp::new(1_000_000_000, TimeUnit::Nanosecond),
886 Timestamp::new(1, TimeUnit::Second),
887 );
888 }
889
890 #[test]
891 pub fn test_from_i64() {
892 let t: Timestamp = 42.into();
893 assert_eq!(42, t.value());
894 assert_eq!(TimeUnit::Millisecond, t.unit());
895 }
896
897 fn check_from_str(s: &str, expect: &str) {
900 let ts = Timestamp::from_str_utc(s).unwrap();
901 let time = ts.to_chrono_datetime().unwrap();
902 assert_eq!(expect, time.to_string());
903 }
904
905 #[test]
906 fn test_from_str() {
907 check_from_str("2020-09-08 13:42:29Z", "2020-09-08 13:42:29");
909 check_from_str("2020-09-08T13:42:29+08:00", "2020-09-08 05:42:29");
910
911 check_from_str("2020-09-08 13:42:29", "2020-09-08 13:42:29");
912
913 check_from_str("2020-09-08 13:42:29.042Z", "2020-09-08 13:42:29.042");
914 check_from_str("2020-09-08 13:42:29.042+08:00", "2020-09-08 05:42:29.042");
915
916 check_from_str(
917 "2020-09-08T13:42:29.0042+08:00",
918 "2020-09-08 05:42:29.004200",
919 );
920 }
921
922 #[test]
923 fn test_to_iso8601_string() {
924 set_default_timezone(Some("Asia/Shanghai")).unwrap();
925 let datetime_str = "2020-09-08 13:42:29.042+0000";
926 let ts = Timestamp::from_str_utc(datetime_str).unwrap();
927 assert_eq!("2020-09-08 21:42:29.042+0800", ts.to_iso8601_string());
928
929 let ts_millis = 1668070237000;
930 let ts = Timestamp::new_millisecond(ts_millis);
931 assert_eq!("2022-11-10 16:50:37+0800", ts.to_iso8601_string());
932
933 let ts_millis = -1000;
934 let ts = Timestamp::new_millisecond(ts_millis);
935 assert_eq!("1970-01-01 07:59:59+0800", ts.to_iso8601_string());
936
937 let ts_millis = -1;
938 let ts = Timestamp::new_millisecond(ts_millis);
939 assert_eq!("1970-01-01 07:59:59.999+0800", ts.to_iso8601_string());
940
941 let ts_millis = -1001;
942 let ts = Timestamp::new_millisecond(ts_millis);
943 assert_eq!("1970-01-01 07:59:58.999+0800", ts.to_iso8601_string());
944 }
945
946 #[test]
947 fn test_serialize_to_json_value() {
948 set_default_timezone(Some("Asia/Shanghai")).unwrap();
949 assert_eq!(
950 "1970-01-01 08:00:01+0800",
951 match serde_json::Value::from(Timestamp::new(1, TimeUnit::Second)) {
952 Value::String(s) => s,
953 _ => unreachable!(),
954 }
955 );
956
957 assert_eq!(
958 "1970-01-01 08:00:00.001+0800",
959 match serde_json::Value::from(Timestamp::new(1, TimeUnit::Millisecond)) {
960 Value::String(s) => s,
961 _ => unreachable!(),
962 }
963 );
964
965 assert_eq!(
966 "1970-01-01 08:00:00.000001+0800",
967 match serde_json::Value::from(Timestamp::new(1, TimeUnit::Microsecond)) {
968 Value::String(s) => s,
969 _ => unreachable!(),
970 }
971 );
972
973 assert_eq!(
974 "1970-01-01 08:00:00.000000001+0800",
975 match serde_json::Value::from(Timestamp::new(1, TimeUnit::Nanosecond)) {
976 Value::String(s) => s,
977 _ => unreachable!(),
978 }
979 );
980 }
981
982 #[test]
983 fn test_convert_timestamp() {
984 let ts = Timestamp::new(1, TimeUnit::Second);
985 assert_eq!(
986 Timestamp::new(1000, TimeUnit::Millisecond),
987 ts.convert_to(TimeUnit::Millisecond).unwrap()
988 );
989 assert_eq!(
990 Timestamp::new(1_000_000, TimeUnit::Microsecond),
991 ts.convert_to(TimeUnit::Microsecond).unwrap()
992 );
993 assert_eq!(
994 Timestamp::new(1_000_000_000, TimeUnit::Nanosecond),
995 ts.convert_to(TimeUnit::Nanosecond).unwrap()
996 );
997
998 let ts = Timestamp::new(1_000_100_100, TimeUnit::Nanosecond);
999 assert_eq!(
1000 Timestamp::new(1_000_100, TimeUnit::Microsecond),
1001 ts.convert_to(TimeUnit::Microsecond).unwrap()
1002 );
1003 assert_eq!(
1004 Timestamp::new(1000, TimeUnit::Millisecond),
1005 ts.convert_to(TimeUnit::Millisecond).unwrap()
1006 );
1007 assert_eq!(
1008 Timestamp::new(1, TimeUnit::Second),
1009 ts.convert_to(TimeUnit::Second).unwrap()
1010 );
1011
1012 let ts = Timestamp::new(1_000_100_100, TimeUnit::Nanosecond);
1013 assert_eq!(ts, ts.convert_to(TimeUnit::Nanosecond).unwrap());
1014 let ts = Timestamp::new(1_000_100_100, TimeUnit::Microsecond);
1015 assert_eq!(ts, ts.convert_to(TimeUnit::Microsecond).unwrap());
1016 let ts = Timestamp::new(1_000_100_100, TimeUnit::Millisecond);
1017 assert_eq!(ts, ts.convert_to(TimeUnit::Millisecond).unwrap());
1018 let ts = Timestamp::new(1_000_100_100, TimeUnit::Second);
1019 assert_eq!(ts, ts.convert_to(TimeUnit::Second).unwrap());
1020
1021 assert_eq!(
1023 Timestamp::new(-9223372036854776, TimeUnit::Second),
1024 Timestamp::new(i64::MIN, TimeUnit::Millisecond)
1025 .convert_to(TimeUnit::Second)
1026 .unwrap()
1027 );
1028
1029 assert!(
1030 Timestamp::new(i64::MAX, TimeUnit::Second)
1031 .convert_to(TimeUnit::Millisecond)
1032 .is_none()
1033 );
1034 }
1035
1036 #[test]
1037 fn test_split() {
1038 assert_eq!((0, 0), Timestamp::new(0, TimeUnit::Second).split());
1039 assert_eq!((1, 0), Timestamp::new(1, TimeUnit::Second).split());
1040 assert_eq!(
1041 (0, 1_000_000),
1042 Timestamp::new(1, TimeUnit::Millisecond).split()
1043 );
1044
1045 assert_eq!((0, 1_000), Timestamp::new(1, TimeUnit::Microsecond).split());
1046 assert_eq!((0, 1), Timestamp::new(1, TimeUnit::Nanosecond).split());
1047
1048 assert_eq!(
1049 (1, 1_000_000),
1050 Timestamp::new(1001, TimeUnit::Millisecond).split()
1051 );
1052
1053 assert_eq!(
1054 (-2, 999_000_000),
1055 Timestamp::new(-1001, TimeUnit::Millisecond).split()
1056 );
1057
1058 let (sec, nsec) = Timestamp::new(i64::MIN, TimeUnit::Nanosecond).split();
1060 assert_eq!(
1061 i64::MIN as i128,
1062 sec as i128 * (TimeUnit::Second.factor() / TimeUnit::Nanosecond.factor()) as i128
1063 + nsec as i128
1064 );
1065
1066 assert_eq!(
1067 (i64::MAX, 0),
1068 Timestamp::new(i64::MAX, TimeUnit::Second).split()
1069 );
1070 }
1071
1072 #[test]
1073 fn test_convert_to_ceil() {
1074 assert_eq!(
1075 Timestamp::new(1, TimeUnit::Second),
1076 Timestamp::new(1000, TimeUnit::Millisecond)
1077 .convert_to_ceil(TimeUnit::Second)
1078 .unwrap()
1079 );
1080
1081 assert_eq!(
1084 Timestamp::new(1, TimeUnit::Second),
1085 Timestamp::new(1001, TimeUnit::Millisecond)
1086 .convert_to(TimeUnit::Second)
1087 .unwrap()
1088 );
1089 assert_eq!(
1090 Timestamp::new(2, TimeUnit::Second),
1091 Timestamp::new(1001, TimeUnit::Millisecond)
1092 .convert_to_ceil(TimeUnit::Second)
1093 .unwrap()
1094 );
1095
1096 assert_eq!(
1097 Timestamp::new(-1, TimeUnit::Second),
1098 Timestamp::new(-1, TimeUnit::Millisecond)
1099 .convert_to(TimeUnit::Second)
1100 .unwrap()
1101 );
1102 assert_eq!(
1103 Timestamp::new(0, TimeUnit::Second),
1104 Timestamp::new(-1, TimeUnit::Millisecond)
1105 .convert_to_ceil(TimeUnit::Second)
1106 .unwrap()
1107 );
1108
1109 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 assert_eq!(
1116 Timestamp::new(1000, TimeUnit::Second).convert_to(TimeUnit::Millisecond),
1117 Timestamp::new(1000, TimeUnit::Second).convert_to_ceil(TimeUnit::Millisecond)
1118 );
1119 assert_eq!(
1120 Timestamp::new(1, TimeUnit::Second).convert_to(TimeUnit::Millisecond),
1121 Timestamp::new(1, TimeUnit::Second).convert_to_ceil(TimeUnit::Millisecond)
1122 );
1123 }
1124
1125 #[test]
1126 fn test_split_overflow() {
1127 let _ = Timestamp::new(i64::MAX, TimeUnit::Second).split();
1128 let _ = Timestamp::new(i64::MIN, TimeUnit::Second).split();
1129 let _ = Timestamp::new(i64::MAX, TimeUnit::Millisecond).split();
1130 let _ = Timestamp::new(i64::MIN, TimeUnit::Millisecond).split();
1131 let _ = Timestamp::new(i64::MAX, TimeUnit::Microsecond).split();
1132 let _ = Timestamp::new(i64::MIN, TimeUnit::Microsecond).split();
1133 let _ = Timestamp::new(i64::MAX, TimeUnit::Nanosecond).split();
1134 let _ = Timestamp::new(i64::MIN, TimeUnit::Nanosecond).split();
1135 let (sec, nsec) = Timestamp::new(i64::MIN, TimeUnit::Nanosecond).split();
1136 let time = DateTime::from_timestamp(sec, nsec).unwrap().naive_utc();
1137 assert_eq!(sec, time.and_utc().timestamp());
1138 assert_eq!(nsec, time.and_utc().timestamp_subsec_nanos());
1139 }
1140
1141 #[test]
1142 fn test_timestamp_sub() {
1143 let res = Timestamp::new(1, TimeUnit::Second)
1144 .sub_duration(Duration::from_secs(1))
1145 .unwrap();
1146 assert_eq!(0, res.value);
1147 assert_eq!(TimeUnit::Second, res.unit);
1148
1149 let res = Timestamp::new(0, TimeUnit::Second)
1150 .sub_duration(Duration::from_secs(1))
1151 .unwrap();
1152 assert_eq!(-1, res.value);
1153 assert_eq!(TimeUnit::Second, res.unit);
1154
1155 let res = Timestamp::new(1, TimeUnit::Second)
1156 .sub_duration(Duration::from_millis(1))
1157 .unwrap();
1158 assert_eq!(1, res.value);
1159 assert_eq!(TimeUnit::Second, res.unit);
1160 }
1161
1162 #[test]
1163 fn test_timestamp_add() {
1164 let res = Timestamp::new(1, TimeUnit::Second)
1165 .add_duration(Duration::from_secs(1))
1166 .unwrap();
1167 assert_eq!(2, res.value);
1168 assert_eq!(TimeUnit::Second, res.unit);
1169
1170 let res = Timestamp::new(0, TimeUnit::Second)
1171 .add_duration(Duration::from_secs(1))
1172 .unwrap();
1173 assert_eq!(1, res.value);
1174 assert_eq!(TimeUnit::Second, res.unit);
1175
1176 let res = Timestamp::new(1, TimeUnit::Second)
1177 .add_duration(Duration::from_millis(1))
1178 .unwrap();
1179 assert_eq!(1, res.value);
1180 assert_eq!(TimeUnit::Second, res.unit);
1181
1182 let res = Timestamp::new(100, TimeUnit::Second)
1183 .add_duration(Duration::from_millis(1000))
1184 .unwrap();
1185 assert_eq!(101, res.value);
1186 assert_eq!(TimeUnit::Second, res.unit);
1187 }
1188
1189 #[test]
1191 fn test_parse_in_timezone() {
1192 unsafe {
1193 std::env::set_var("TZ", "Asia/Shanghai");
1194 }
1195 assert_eq!(
1196 Timestamp::new(28800, TimeUnit::Second),
1197 Timestamp::from_str_utc("1970-01-01 08:00:00.000").unwrap()
1198 );
1199
1200 assert_eq!(
1201 Timestamp::new(28800, TimeUnit::Second),
1202 Timestamp::from_str_utc("1970-01-01 08:00:00").unwrap()
1203 );
1204
1205 assert_eq!(
1206 Timestamp::new(28800, TimeUnit::Second),
1207 Timestamp::from_str_utc(" 1970-01-01 08:00:00 ").unwrap()
1208 );
1209 }
1210
1211 #[test]
1212 fn test_to_local_string() {
1213 set_default_timezone(Some("Asia/Shanghai")).unwrap();
1214
1215 assert_eq!(
1216 "1970-01-01 08:00:00.000000001",
1217 Timestamp::new(1, TimeUnit::Nanosecond).to_local_string()
1218 );
1219
1220 assert_eq!(
1221 "1970-01-01 08:00:00.001",
1222 Timestamp::new(1, TimeUnit::Millisecond).to_local_string()
1223 );
1224
1225 assert_eq!(
1226 "1970-01-01 08:00:01",
1227 Timestamp::new(1, TimeUnit::Second).to_local_string()
1228 );
1229 }
1230
1231 #[test]
1232 fn test_subtract_timestamp() {
1233 assert_eq!(
1234 chrono::Duration::try_milliseconds(42),
1235 Timestamp::new_millisecond(100).sub(&Timestamp::new_millisecond(58))
1236 );
1237
1238 assert_eq!(
1239 chrono::Duration::try_milliseconds(-42),
1240 Timestamp::new_millisecond(58).sub(&Timestamp::new_millisecond(100))
1241 );
1242 }
1243
1244 #[test]
1245 fn test_to_timezone_aware_string() {
1246 set_default_timezone(Some("Asia/Shanghai")).unwrap();
1247 unsafe {
1248 std::env::set_var("TZ", "Asia/Shanghai");
1249 }
1250 assert_eq!(
1251 "1970-01-01 08:00:00.001",
1252 Timestamp::new(1, TimeUnit::Millisecond)
1253 .to_timezone_aware_string(Some(&Timezone::from_tz_string("SYSTEM").unwrap()))
1254 );
1255 assert_eq!(
1256 "1970-01-01 08:00:00.001",
1257 Timestamp::new(1, TimeUnit::Millisecond)
1258 .to_timezone_aware_string(Some(&Timezone::from_tz_string("SYSTEM").unwrap()))
1259 );
1260 assert_eq!(
1261 "1970-01-01 08:00:00.001",
1262 Timestamp::new(1, TimeUnit::Millisecond)
1263 .to_timezone_aware_string(Some(&Timezone::from_tz_string("+08:00").unwrap()))
1264 );
1265 assert_eq!(
1266 "1970-01-01 07:00:00.001",
1267 Timestamp::new(1, TimeUnit::Millisecond)
1268 .to_timezone_aware_string(Some(&Timezone::from_tz_string("+07:00").unwrap()))
1269 );
1270 assert_eq!(
1271 "1969-12-31 23:00:00.001",
1272 Timestamp::new(1, TimeUnit::Millisecond)
1273 .to_timezone_aware_string(Some(&Timezone::from_tz_string("-01:00").unwrap()))
1274 );
1275 assert_eq!(
1276 "1970-01-01 08:00:00.001",
1277 Timestamp::new(1, TimeUnit::Millisecond).to_timezone_aware_string(Some(
1278 &Timezone::from_tz_string("Asia/Shanghai").unwrap()
1279 ))
1280 );
1281 assert_eq!(
1282 "1970-01-01 00:00:00.001",
1283 Timestamp::new(1, TimeUnit::Millisecond)
1284 .to_timezone_aware_string(Some(&Timezone::from_tz_string("UTC").unwrap()))
1285 );
1286 assert_eq!(
1287 "1970-01-01 01:00:00.001",
1288 Timestamp::new(1, TimeUnit::Millisecond).to_timezone_aware_string(Some(
1289 &Timezone::from_tz_string("Europe/Berlin").unwrap()
1290 ))
1291 );
1292 assert_eq!(
1293 "1970-01-01 03:00:00.001",
1294 Timestamp::new(1, TimeUnit::Millisecond).to_timezone_aware_string(Some(
1295 &Timezone::from_tz_string("Europe/Moscow").unwrap()
1296 ))
1297 );
1298 }
1299
1300 #[test]
1301 fn test_as_formatted_string() {
1302 let ts = Timestamp::new(1, TimeUnit::Millisecond);
1303
1304 assert_eq!(
1305 "1970-01-01",
1306 ts.as_formatted_string("%Y-%m-%d", None).unwrap()
1307 );
1308 assert_eq!(
1309 "1970-01-01 00:00:00",
1310 ts.as_formatted_string("%Y-%m-%d %H:%M:%S", None).unwrap()
1311 );
1312 assert_eq!(
1313 "1970-01-01T00:00:00:001",
1314 ts.as_formatted_string("%Y-%m-%dT%H:%M:%S:%3f", None)
1315 .unwrap()
1316 );
1317 assert_eq!(
1318 "1970-01-01T08:00:00:001",
1319 ts.as_formatted_string(
1320 "%Y-%m-%dT%H:%M:%S:%3f",
1321 Some(&Timezone::from_tz_string("Asia/Shanghai").unwrap())
1322 )
1323 .unwrap()
1324 );
1325 }
1326
1327 #[test]
1328 fn test_to_chrono_datetime_with_timezone_bounds() {
1329 let positive_offset = Timezone::from_tz_string("+08:00").unwrap();
1330 assert_eq!(
1331 None,
1332 Timestamp::MAX_SECOND.to_chrono_datetime_with_timezone(Some(&positive_offset))
1333 );
1334
1335 let negative_offset = Timezone::from_tz_string("-08:00").unwrap();
1336 assert_eq!(
1337 None,
1338 Timestamp::MIN_SECOND.to_chrono_datetime_with_timezone(Some(&negative_offset))
1339 );
1340 }
1341
1342 #[test]
1343 fn test_to_chrono_datetime_with_named_timezone_summer_offset() {
1344 let timestamp = Timestamp::from_str_utc("2024-07-01 12:00:00Z").unwrap();
1345 let berlin = Timezone::from_tz_string("Europe/Berlin").unwrap();
1346
1347 assert_eq!(
1348 Some(
1349 NaiveDate::from_ymd_opt(2024, 7, 1)
1350 .unwrap()
1351 .and_hms_opt(14, 0, 0)
1352 .unwrap()
1353 ),
1354 timestamp.to_chrono_datetime_with_timezone(Some(&berlin))
1355 );
1356 }
1357
1358 #[test]
1359 fn test_from_arrow_time_unit() {
1360 assert_eq!(TimeUnit::Second, TimeUnit::from(ArrowTimeUnit::Second));
1361 assert_eq!(
1362 TimeUnit::Millisecond,
1363 TimeUnit::from(ArrowTimeUnit::Millisecond)
1364 );
1365 assert_eq!(
1366 TimeUnit::Microsecond,
1367 TimeUnit::from(ArrowTimeUnit::Microsecond)
1368 );
1369 assert_eq!(
1370 TimeUnit::Nanosecond,
1371 TimeUnit::from(ArrowTimeUnit::Nanosecond)
1372 );
1373 }
1374
1375 fn check_conversion(ts: Timestamp, valid: bool) {
1376 let Some(t2) = ts.to_chrono_datetime() else {
1377 if valid {
1378 panic!("Cannot convert {:?} to Chrono NaiveDateTime", ts);
1379 }
1380 return;
1381 };
1382 let Some(t3) = Timestamp::from_chrono_datetime(t2) else {
1383 if valid {
1384 panic!("Cannot convert Chrono NaiveDateTime {:?} to Timestamp", t2);
1385 }
1386 return;
1387 };
1388
1389 assert_eq!(t3, ts);
1390 }
1391
1392 #[test]
1393 fn test_from_naive_date_time() {
1394 let naive_date_time_min = NaiveDateTime::MIN.and_utc();
1395 let naive_date_time_max = NaiveDateTime::MAX.and_utc();
1396
1397 let min_sec = Timestamp::new_second(naive_date_time_min.timestamp());
1398 let max_sec = Timestamp::new_second(naive_date_time_max.timestamp());
1399 check_conversion(min_sec, true);
1400 check_conversion(Timestamp::new_second(min_sec.value - 1), false);
1401 check_conversion(max_sec, true);
1402 check_conversion(Timestamp::new_second(max_sec.value + 1), false);
1403
1404 let min_millis = Timestamp::new_millisecond(naive_date_time_min.timestamp_millis());
1405 let max_millis = Timestamp::new_millisecond(naive_date_time_max.timestamp_millis());
1406 check_conversion(min_millis, true);
1407 check_conversion(Timestamp::new_millisecond(min_millis.value - 1), false);
1408 check_conversion(max_millis, true);
1409 check_conversion(Timestamp::new_millisecond(max_millis.value + 1), false);
1410
1411 let min_micros = Timestamp::new_microsecond(naive_date_time_min.timestamp_micros());
1412 let max_micros = Timestamp::new_microsecond(naive_date_time_max.timestamp_micros());
1413 check_conversion(min_micros, true);
1414 check_conversion(Timestamp::new_microsecond(min_micros.value - 1), false);
1415 check_conversion(max_micros, true);
1416 check_conversion(Timestamp::new_microsecond(max_micros.value + 1), false);
1417
1418 let min_nanos = Timestamp::new_nanosecond(-9223372036854775000);
1420 let max_nanos = Timestamp::new_nanosecond(i64::MAX);
1421 check_conversion(min_nanos, true);
1422 check_conversion(Timestamp::new_nanosecond(min_nanos.value - 1), false);
1423 check_conversion(max_nanos, true);
1424 }
1425
1426 #[test]
1427 fn test_parse_timestamp_range() {
1428 let datetime_min = NaiveDateTime::MIN.format("%Y-%m-%d %H:%M:%SZ").to_string();
1429 assert_eq!("-262143-01-01 00:00:00Z", datetime_min);
1430 let datetime_max = NaiveDateTime::MAX.format("%Y-%m-%d %H:%M:%SZ").to_string();
1431 assert_eq!("+262142-12-31 23:59:59Z", datetime_max);
1432
1433 let valid_strings = vec![
1434 "-262143-01-01 00:00:00Z",
1435 "+262142-12-31 23:59:59Z",
1436 "+262142-12-31 23:59:59.999Z",
1437 "+262142-12-31 23:59:59.999999Z",
1438 "1677-09-21 00:12:43.145224192Z",
1439 "2262-04-11 23:47:16.854775807Z",
1440 "+100000-01-01 00:00:01.5Z",
1441 ];
1442
1443 for s in valid_strings {
1444 Timestamp::from_str_utc(s).unwrap();
1445 }
1446 }
1447
1448 #[test]
1449 fn test_min_nanos_roundtrip() {
1450 let (sec, nsec) = Timestamp::MIN_NANOSECOND.split();
1451 let ts = Timestamp::from_splits(sec, nsec).unwrap();
1452 assert_eq!(Timestamp::MIN_NANOSECOND, ts);
1453 }
1454
1455 #[test]
1456 fn test_timestamp_bound_format() {
1457 assert_eq!(
1458 "1677-09-21 00:12:43.145224192",
1459 Timestamp::MIN_NANOSECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1460 );
1461 assert_eq!(
1462 "2262-04-11 23:47:16.854775807",
1463 Timestamp::MAX_NANOSECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1464 );
1465 assert_eq!(
1466 "-262143-01-01 00:00:00",
1467 Timestamp::MIN_MICROSECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1468 );
1469 assert_eq!(
1470 "+262142-12-31 23:59:59.999999",
1471 Timestamp::MAX_MICROSECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1472 );
1473 assert_eq!(
1474 "-262143-01-01 00:00:00",
1475 Timestamp::MIN_MILLISECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1476 );
1477 assert_eq!(
1478 "+262142-12-31 23:59:59.999",
1479 Timestamp::MAX_MILLISECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1480 );
1481 assert_eq!(
1482 "-262143-01-01 00:00:00",
1483 Timestamp::MIN_SECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1484 );
1485 assert_eq!(
1486 "+262142-12-31 23:59:59",
1487 Timestamp::MAX_SECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1488 );
1489 }
1490
1491 #[test]
1492 fn test_debug_timestamp() {
1493 assert_eq!(
1494 "1000::Second",
1495 format!("{:?}", Timestamp::new(1000, TimeUnit::Second))
1496 );
1497 assert_eq!(
1498 "1001::Millisecond",
1499 format!("{:?}", Timestamp::new(1001, TimeUnit::Millisecond))
1500 );
1501 assert_eq!(
1502 "1002::Microsecond",
1503 format!("{:?}", Timestamp::new(1002, TimeUnit::Microsecond))
1504 );
1505 assert_eq!(
1506 "1003::Nanosecond",
1507 format!("{:?}", Timestamp::new(1003, TimeUnit::Nanosecond))
1508 );
1509 }
1510}