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