common_time/
timestamp.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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::{get_timezone, Timezone};
33use crate::util::{datetime_to_utc, div_ceil};
34
35/// Timestamp represents the value of units(seconds/milliseconds/microseconds/nanoseconds) elapsed
36/// since UNIX epoch. The valid value range of [Timestamp] depends on it's unit (all in UTC timezone):
37/// - for [TimeUnit::Second]: [-262144-01-01 00:00:00, +262143-12-31 23:59:59]
38/// - for [TimeUnit::Millisecond]: [-262144-01-01 00:00:00.000, +262143-12-31 23:59:59.999]
39/// - for [TimeUnit::Microsecond]: [-262144-01-01 00:00:00.000000, +262143-12-31 23:59:59.999999]
40/// - for [TimeUnit::Nanosecond]: [1677-09-21 00:12:43.145224192, 2262-04-11 23:47:16.854775807]
41///
42/// # Note:
43/// For values out of range, you can still store these timestamps, but while performing arithmetic
44/// or formatting operations, it will return an error or just overflow.
45#[derive(Clone, Default, Copy, Serialize, Deserialize)]
46pub struct Timestamp {
47    value: i64,
48    unit: TimeUnit,
49}
50
51impl Timestamp {
52    /// Creates current timestamp in millisecond.
53    pub fn current_millis() -> Self {
54        Self {
55            value: crate::util::current_time_millis(),
56            unit: TimeUnit::Millisecond,
57        }
58    }
59
60    /// Creates current timestamp in specific time `unit`.
61    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    /// Subtracts a duration from timestamp.
73    /// # Note
74    /// The result time unit remains unchanged even if `duration` has a different unit with `self`.
75    /// For example, a timestamp with value 1 and time unit second, subtracted by 1 millisecond
76    /// and the result is still 1 second.
77    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    /// Adds a duration to timestamp.
109    /// # Note
110    /// The result time unit remains unchanged even if `duration` has a different unit with `self`.
111    /// For example, a timestamp with value 1 and time unit second, subtracted by 1 millisecond
112    /// and the result is still 1 second.
113    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    // FIXME(yingwen): remove add/sub intervals later
145    /// Adds given [IntervalYearMonth] to the current timestamp.
146    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        // Have to convert the new timestamp by the current unit.
153        Timestamp::from_chrono_datetime(naive_datetime).and_then(|ts| ts.convert_to(self.unit))
154    }
155
156    /// Adds given [IntervalDayTime] to the current timestamp.
157    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        // Have to convert the new timestamp by the current unit.
165        Timestamp::from_chrono_datetime(naive_datetime).and_then(|ts| ts.convert_to(self.unit))
166    }
167
168    /// Adds given [IntervalMonthDayNano] to the current timestamp.
169    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        // Have to convert the new timestamp by the current unit.
178        Timestamp::from_chrono_datetime(naive_datetime).and_then(|ts| ts.convert_to(self.unit))
179    }
180
181    /// Subtracts given [IntervalYearMonth] to the current timestamp.
182    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        // Have to convert the new timestamp by the current unit.
189        Timestamp::from_chrono_datetime(naive_datetime).and_then(|ts| ts.convert_to(self.unit))
190    }
191
192    /// Subtracts given [IntervalDayTime] to the current timestamp.
193    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        // Have to convert the new timestamp by the current unit.
201        Timestamp::from_chrono_datetime(naive_datetime).and_then(|ts| ts.convert_to(self.unit))
202    }
203
204    /// Subtracts given [IntervalMonthDayNano] to the current timestamp.
205    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        // Have to convert the new timestamp by the current unit.
214        Timestamp::from_chrono_datetime(naive_datetime).and_then(|ts| ts.convert_to(self.unit))
215    }
216
217    /// Subtracts current timestamp with another timestamp, yielding a duration.
218    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    /// Convert a timestamp to given time unit.
265    /// Conversion from a timestamp with smaller unit to a larger unit may cause rounding error.
266    /// Return `None` if conversion causes overflow.
267    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    /// Convert a timestamp to given time unit.
279    /// Conversion from a timestamp with smaller unit to a larger unit will round the value
280    /// to ceil (positive infinity).
281    /// Return `None` if conversion causes overflow.
282    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    /// Split a [Timestamp] into seconds part and nanoseconds part.
294    /// Notice the seconds part of split result is always rounded down to floor.
295    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        // safety:  the max possible value of `sec_mod` is 999,999,999
302        let nsec = u32::try_from(sec_mod * nsec_mul).unwrap();
303        (sec_div, nsec)
304    }
305
306    /// Creates a new Timestamp instance from seconds and nanoseconds parts.
307    /// Returns None if overflow.
308    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            // Refer to <https://github.com/chronotope/chrono/issues/1289>
323            //
324            // subsec nanos are always non-negative, however the timestamp itself (both in seconds and in nanos) can be
325            // negative. Now i64::MIN is NOT dividable by 1_000_000_000, so
326            //
327            //   (sec * 1_000_000_000) + nsec
328            //
329            // may underflow (even when in theory we COULD represent the datetime as i64) because we add the non-negative
330            // nanos AFTER the multiplication. This is fixed by converting the negative case to
331            //
332            //   ((sec + 1) * 1_000_000_000) + (nsec - 1_000_000_000)
333            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    /// Format timestamp to ISO8601 string. If the timestamp exceeds what chrono timestamp can
347    /// represent, this function simply print the timestamp unit and value in plain string.
348    pub fn to_iso8601_string(&self) -> String {
349        // Safety: the format is valid
350        self.as_formatted_string("%Y-%m-%d %H:%M:%S%.f%z", None)
351            .unwrap()
352    }
353
354    /// Format timestamp use **system timezone**.
355    pub fn to_local_string(&self) -> String {
356        // Safety: the format is valid
357        self.as_formatted_string("%Y-%m-%d %H:%M:%S%.f", None)
358            .unwrap()
359    }
360
361    /// Format timestamp for given timezone.
362    /// If `tz==None`, the server default timezone will used.
363    pub fn to_timezone_aware_string(&self, tz: Option<&Timezone>) -> String {
364        // Safety: the format is valid
365        self.as_formatted_string("%Y-%m-%d %H:%M:%S%.f", tz)
366            .unwrap()
367    }
368
369    /// Format timestamp for given format and timezone.
370    /// If `tz==None`, the server default timezone will used.
371    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    /// Convert timestamp to chrono date.
411    pub fn to_chrono_date(&self) -> Option<NaiveDate> {
412        self.to_chrono_datetime().map(|ndt| ndt.date())
413    }
414
415    /// Convert timestamp to chrono time.
416    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    /// Accepts a string in RFC3339 / ISO8601 standard format and some variants and converts it to a nanosecond precision timestamp.
431    /// It no timezone specified in string, it cast to nanosecond epoch timestamp in UTC.
432    pub fn from_str_utc(s: &str) -> Result<Self> {
433        Self::from_str(s, None)
434    }
435
436    /// Accepts a string in RFC3339 / ISO8601 standard format and some variants and converts it to a nanosecond precision timestamp.
437    /// This code is copied from [arrow-datafusion](https://github.com/apache/arrow-datafusion/blob/arrow2/datafusion-physical-expr/src/arrow_temporal_util.rs#L71)
438    /// with some bugfixes.
439    /// Supported format:
440    /// - `2022-09-20T14:16:43.012345Z` (Zulu timezone)
441    /// - `2022-09-20T14:16:43.012345+08:00` (Explicit offset)
442    /// - `2022-09-20T14:16:43.012345` (The given timezone, with T)
443    /// - `2022-09-20T14:16:43` (Zulu timezone, no fractional seconds, with T)
444    /// - `2022-09-20 14:16:43.012345Z` (Zulu timezone, without T)
445    /// - `2022-09-20 14:16:43` (The given timezone, without T)
446    /// - `2022-09-20 14:16:43.012345` (The given timezone, without T)
447    #[allow(deprecated)]
448    pub fn from_str(s: &str, timezone: Option<&Timezone>) -> Result<Self> {
449        // RFC3339 timestamp (with a T)
450        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    /// Checks if a value would overflow for the given time unit.
503    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
514/// Converts the naive datetime (which has no specific timezone) to a
515/// nanosecond epoch timestamp in UTC.
516fn 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, 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
641/// A proper implementation of total order requires antisymmetry, reflexivity, transitivity and totality.
642/// In this comparison implementation, we map a timestamp uniquely to a `(i64, i64)` tuple which is respectively
643/// total order.
644impl Ord for Timestamp {
645    fn cmp(&self, other: &Self) -> Ordering {
646        // fast path: most comparisons use the same unit.
647        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    /// Generate timestamp less than or equal to `threshold`
758    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); // t0 >= t1
775        let t2 = gen_ts_le(&t1); // t1 >= t2
776        assert!(t0 >= t1, "t0: {t0:?}, t1: {t1:?}");
777        assert!(t1 >= t2, "t1: {t1:?}, t2: {t2:?}");
778        assert!(t0 >= t2, "t0: {t0:?}, t2: {t2:?}"); // check if t0 >= t2
779    }
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    // Input timestamp string is regarded as local timezone if no timezone is specified,
890    // but expected timestamp is in UTC timezone
891    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        // Explicit Z means timestamp in UTC
900        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        // -9223372036854775808 in milliseconds should be rounded up to -9223372036854776 in seconds
1014        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!(Timestamp::new(i64::MAX, TimeUnit::Second)
1022            .convert_to(TimeUnit::Millisecond)
1023            .is_none());
1024    }
1025
1026    #[test]
1027    fn test_split() {
1028        assert_eq!((0, 0), Timestamp::new(0, TimeUnit::Second).split());
1029        assert_eq!((1, 0), Timestamp::new(1, TimeUnit::Second).split());
1030        assert_eq!(
1031            (0, 1_000_000),
1032            Timestamp::new(1, TimeUnit::Millisecond).split()
1033        );
1034
1035        assert_eq!((0, 1_000), Timestamp::new(1, TimeUnit::Microsecond).split());
1036        assert_eq!((0, 1), Timestamp::new(1, TimeUnit::Nanosecond).split());
1037
1038        assert_eq!(
1039            (1, 1_000_000),
1040            Timestamp::new(1001, TimeUnit::Millisecond).split()
1041        );
1042
1043        assert_eq!(
1044            (-2, 999_000_000),
1045            Timestamp::new(-1001, TimeUnit::Millisecond).split()
1046        );
1047
1048        // check min value of nanos
1049        let (sec, nsec) = Timestamp::new(i64::MIN, TimeUnit::Nanosecond).split();
1050        assert_eq!(
1051            i64::MIN as i128,
1052            sec as i128 * (TimeUnit::Second.factor() / TimeUnit::Nanosecond.factor()) as i128
1053                + nsec as i128
1054        );
1055
1056        assert_eq!(
1057            (i64::MAX, 0),
1058            Timestamp::new(i64::MAX, TimeUnit::Second).split()
1059        );
1060    }
1061
1062    #[test]
1063    fn test_convert_to_ceil() {
1064        assert_eq!(
1065            Timestamp::new(1, TimeUnit::Second),
1066            Timestamp::new(1000, TimeUnit::Millisecond)
1067                .convert_to_ceil(TimeUnit::Second)
1068                .unwrap()
1069        );
1070
1071        // These two cases shows how `Timestamp::convert_to_ceil` behaves differently
1072        // from `Timestamp::convert_to` when converting larger unit to smaller unit.
1073        assert_eq!(
1074            Timestamp::new(1, TimeUnit::Second),
1075            Timestamp::new(1001, TimeUnit::Millisecond)
1076                .convert_to(TimeUnit::Second)
1077                .unwrap()
1078        );
1079        assert_eq!(
1080            Timestamp::new(2, TimeUnit::Second),
1081            Timestamp::new(1001, TimeUnit::Millisecond)
1082                .convert_to_ceil(TimeUnit::Second)
1083                .unwrap()
1084        );
1085
1086        assert_eq!(
1087            Timestamp::new(-1, TimeUnit::Second),
1088            Timestamp::new(-1, TimeUnit::Millisecond)
1089                .convert_to(TimeUnit::Second)
1090                .unwrap()
1091        );
1092        assert_eq!(
1093            Timestamp::new(0, TimeUnit::Second),
1094            Timestamp::new(-1, TimeUnit::Millisecond)
1095                .convert_to_ceil(TimeUnit::Second)
1096                .unwrap()
1097        );
1098
1099        // When converting large unit to smaller unit, there will be no rounding error,
1100        // so `Timestamp::convert_to_ceil` behaves just like `Timestamp::convert_to`
1101        assert_eq!(
1102            Timestamp::new(-1, TimeUnit::Second).convert_to(TimeUnit::Millisecond),
1103            Timestamp::new(-1, TimeUnit::Second).convert_to_ceil(TimeUnit::Millisecond)
1104        );
1105        assert_eq!(
1106            Timestamp::new(1000, TimeUnit::Second).convert_to(TimeUnit::Millisecond),
1107            Timestamp::new(1000, TimeUnit::Second).convert_to_ceil(TimeUnit::Millisecond)
1108        );
1109        assert_eq!(
1110            Timestamp::new(1, TimeUnit::Second).convert_to(TimeUnit::Millisecond),
1111            Timestamp::new(1, TimeUnit::Second).convert_to_ceil(TimeUnit::Millisecond)
1112        );
1113    }
1114
1115    #[test]
1116    fn test_split_overflow() {
1117        let _ = Timestamp::new(i64::MAX, TimeUnit::Second).split();
1118        let _ = Timestamp::new(i64::MIN, TimeUnit::Second).split();
1119        let _ = Timestamp::new(i64::MAX, TimeUnit::Millisecond).split();
1120        let _ = Timestamp::new(i64::MIN, TimeUnit::Millisecond).split();
1121        let _ = Timestamp::new(i64::MAX, TimeUnit::Microsecond).split();
1122        let _ = Timestamp::new(i64::MIN, TimeUnit::Microsecond).split();
1123        let _ = Timestamp::new(i64::MAX, TimeUnit::Nanosecond).split();
1124        let _ = Timestamp::new(i64::MIN, TimeUnit::Nanosecond).split();
1125        let (sec, nsec) = Timestamp::new(i64::MIN, TimeUnit::Nanosecond).split();
1126        let time = DateTime::from_timestamp(sec, nsec).unwrap().naive_utc();
1127        assert_eq!(sec, time.and_utc().timestamp());
1128        assert_eq!(nsec, time.and_utc().timestamp_subsec_nanos());
1129    }
1130
1131    #[test]
1132    fn test_timestamp_sub() {
1133        let res = Timestamp::new(1, TimeUnit::Second)
1134            .sub_duration(Duration::from_secs(1))
1135            .unwrap();
1136        assert_eq!(0, res.value);
1137        assert_eq!(TimeUnit::Second, res.unit);
1138
1139        let res = Timestamp::new(0, TimeUnit::Second)
1140            .sub_duration(Duration::from_secs(1))
1141            .unwrap();
1142        assert_eq!(-1, res.value);
1143        assert_eq!(TimeUnit::Second, res.unit);
1144
1145        let res = Timestamp::new(1, TimeUnit::Second)
1146            .sub_duration(Duration::from_millis(1))
1147            .unwrap();
1148        assert_eq!(1, res.value);
1149        assert_eq!(TimeUnit::Second, res.unit);
1150    }
1151
1152    #[test]
1153    fn test_timestamp_add() {
1154        let res = Timestamp::new(1, TimeUnit::Second)
1155            .add_duration(Duration::from_secs(1))
1156            .unwrap();
1157        assert_eq!(2, res.value);
1158        assert_eq!(TimeUnit::Second, res.unit);
1159
1160        let res = Timestamp::new(0, TimeUnit::Second)
1161            .add_duration(Duration::from_secs(1))
1162            .unwrap();
1163        assert_eq!(1, res.value);
1164        assert_eq!(TimeUnit::Second, res.unit);
1165
1166        let res = Timestamp::new(1, TimeUnit::Second)
1167            .add_duration(Duration::from_millis(1))
1168            .unwrap();
1169        assert_eq!(1, res.value);
1170        assert_eq!(TimeUnit::Second, res.unit);
1171
1172        let res = Timestamp::new(100, TimeUnit::Second)
1173            .add_duration(Duration::from_millis(1000))
1174            .unwrap();
1175        assert_eq!(101, res.value);
1176        assert_eq!(TimeUnit::Second, res.unit);
1177    }
1178
1179    // $TZ doesn't take effort.
1180    #[test]
1181    fn test_parse_in_timezone() {
1182        std::env::set_var("TZ", "Asia/Shanghai");
1183        assert_eq!(
1184            Timestamp::new(28800, TimeUnit::Second),
1185            Timestamp::from_str_utc("1970-01-01 08:00:00.000").unwrap()
1186        );
1187
1188        assert_eq!(
1189            Timestamp::new(28800, TimeUnit::Second),
1190            Timestamp::from_str_utc("1970-01-01 08:00:00").unwrap()
1191        );
1192
1193        assert_eq!(
1194            Timestamp::new(28800, TimeUnit::Second),
1195            Timestamp::from_str_utc("      1970-01-01        08:00:00    ").unwrap()
1196        );
1197    }
1198
1199    #[test]
1200    fn test_to_local_string() {
1201        set_default_timezone(Some("Asia/Shanghai")).unwrap();
1202
1203        assert_eq!(
1204            "1970-01-01 08:00:00.000000001",
1205            Timestamp::new(1, TimeUnit::Nanosecond).to_local_string()
1206        );
1207
1208        assert_eq!(
1209            "1970-01-01 08:00:00.001",
1210            Timestamp::new(1, TimeUnit::Millisecond).to_local_string()
1211        );
1212
1213        assert_eq!(
1214            "1970-01-01 08:00:01",
1215            Timestamp::new(1, TimeUnit::Second).to_local_string()
1216        );
1217    }
1218
1219    #[test]
1220    fn test_subtract_timestamp() {
1221        assert_eq!(
1222            chrono::Duration::try_milliseconds(42),
1223            Timestamp::new_millisecond(100).sub(&Timestamp::new_millisecond(58))
1224        );
1225
1226        assert_eq!(
1227            chrono::Duration::try_milliseconds(-42),
1228            Timestamp::new_millisecond(58).sub(&Timestamp::new_millisecond(100))
1229        );
1230    }
1231
1232    #[test]
1233    fn test_to_timezone_aware_string() {
1234        set_default_timezone(Some("Asia/Shanghai")).unwrap();
1235        std::env::set_var("TZ", "Asia/Shanghai");
1236        assert_eq!(
1237            "1970-01-01 08:00:00.001",
1238            Timestamp::new(1, TimeUnit::Millisecond)
1239                .to_timezone_aware_string(Some(&Timezone::from_tz_string("SYSTEM").unwrap()))
1240        );
1241        assert_eq!(
1242            "1970-01-01 08:00:00.001",
1243            Timestamp::new(1, TimeUnit::Millisecond)
1244                .to_timezone_aware_string(Some(&Timezone::from_tz_string("SYSTEM").unwrap()))
1245        );
1246        assert_eq!(
1247            "1970-01-01 08:00:00.001",
1248            Timestamp::new(1, TimeUnit::Millisecond)
1249                .to_timezone_aware_string(Some(&Timezone::from_tz_string("+08:00").unwrap()))
1250        );
1251        assert_eq!(
1252            "1970-01-01 07:00:00.001",
1253            Timestamp::new(1, TimeUnit::Millisecond)
1254                .to_timezone_aware_string(Some(&Timezone::from_tz_string("+07:00").unwrap()))
1255        );
1256        assert_eq!(
1257            "1969-12-31 23:00:00.001",
1258            Timestamp::new(1, TimeUnit::Millisecond)
1259                .to_timezone_aware_string(Some(&Timezone::from_tz_string("-01:00").unwrap()))
1260        );
1261        assert_eq!(
1262            "1970-01-01 08:00:00.001",
1263            Timestamp::new(1, TimeUnit::Millisecond).to_timezone_aware_string(Some(
1264                &Timezone::from_tz_string("Asia/Shanghai").unwrap()
1265            ))
1266        );
1267        assert_eq!(
1268            "1970-01-01 00:00:00.001",
1269            Timestamp::new(1, TimeUnit::Millisecond)
1270                .to_timezone_aware_string(Some(&Timezone::from_tz_string("UTC").unwrap()))
1271        );
1272        assert_eq!(
1273            "1970-01-01 01:00:00.001",
1274            Timestamp::new(1, TimeUnit::Millisecond).to_timezone_aware_string(Some(
1275                &Timezone::from_tz_string("Europe/Berlin").unwrap()
1276            ))
1277        );
1278        assert_eq!(
1279            "1970-01-01 03:00:00.001",
1280            Timestamp::new(1, TimeUnit::Millisecond).to_timezone_aware_string(Some(
1281                &Timezone::from_tz_string("Europe/Moscow").unwrap()
1282            ))
1283        );
1284    }
1285
1286    #[test]
1287    fn test_as_formatted_string() {
1288        let ts = Timestamp::new(1, TimeUnit::Millisecond);
1289
1290        assert_eq!(
1291            "1970-01-01",
1292            ts.as_formatted_string("%Y-%m-%d", None).unwrap()
1293        );
1294        assert_eq!(
1295            "1970-01-01 00:00:00",
1296            ts.as_formatted_string("%Y-%m-%d %H:%M:%S", None).unwrap()
1297        );
1298        assert_eq!(
1299            "1970-01-01T00:00:00:001",
1300            ts.as_formatted_string("%Y-%m-%dT%H:%M:%S:%3f", None)
1301                .unwrap()
1302        );
1303        assert_eq!(
1304            "1970-01-01T08:00:00:001",
1305            ts.as_formatted_string(
1306                "%Y-%m-%dT%H:%M:%S:%3f",
1307                Some(&Timezone::from_tz_string("Asia/Shanghai").unwrap())
1308            )
1309            .unwrap()
1310        );
1311    }
1312
1313    #[test]
1314    fn test_from_arrow_time_unit() {
1315        assert_eq!(TimeUnit::Second, TimeUnit::from(ArrowTimeUnit::Second));
1316        assert_eq!(
1317            TimeUnit::Millisecond,
1318            TimeUnit::from(ArrowTimeUnit::Millisecond)
1319        );
1320        assert_eq!(
1321            TimeUnit::Microsecond,
1322            TimeUnit::from(ArrowTimeUnit::Microsecond)
1323        );
1324        assert_eq!(
1325            TimeUnit::Nanosecond,
1326            TimeUnit::from(ArrowTimeUnit::Nanosecond)
1327        );
1328    }
1329
1330    fn check_conversion(ts: Timestamp, valid: bool) {
1331        let Some(t2) = ts.to_chrono_datetime() else {
1332            if valid {
1333                panic!("Cannot convert {:?} to Chrono NaiveDateTime", ts);
1334            }
1335            return;
1336        };
1337        let Some(t3) = Timestamp::from_chrono_datetime(t2) else {
1338            if valid {
1339                panic!("Cannot convert Chrono NaiveDateTime {:?} to Timestamp", t2);
1340            }
1341            return;
1342        };
1343
1344        assert_eq!(t3, ts);
1345    }
1346
1347    #[test]
1348    fn test_from_naive_date_time() {
1349        let naive_date_time_min = NaiveDateTime::MIN.and_utc();
1350        let naive_date_time_max = NaiveDateTime::MAX.and_utc();
1351
1352        let min_sec = Timestamp::new_second(naive_date_time_min.timestamp());
1353        let max_sec = Timestamp::new_second(naive_date_time_max.timestamp());
1354        check_conversion(min_sec, true);
1355        check_conversion(Timestamp::new_second(min_sec.value - 1), false);
1356        check_conversion(max_sec, true);
1357        check_conversion(Timestamp::new_second(max_sec.value + 1), false);
1358
1359        let min_millis = Timestamp::new_millisecond(naive_date_time_min.timestamp_millis());
1360        let max_millis = Timestamp::new_millisecond(naive_date_time_max.timestamp_millis());
1361        check_conversion(min_millis, true);
1362        check_conversion(Timestamp::new_millisecond(min_millis.value - 1), false);
1363        check_conversion(max_millis, true);
1364        check_conversion(Timestamp::new_millisecond(max_millis.value + 1), false);
1365
1366        let min_micros = Timestamp::new_microsecond(naive_date_time_min.timestamp_micros());
1367        let max_micros = Timestamp::new_microsecond(naive_date_time_max.timestamp_micros());
1368        check_conversion(min_micros, true);
1369        check_conversion(Timestamp::new_microsecond(min_micros.value - 1), false);
1370        check_conversion(max_micros, true);
1371        check_conversion(Timestamp::new_microsecond(max_micros.value + 1), false);
1372
1373        // the min time that can be represented by nanoseconds is: 1677-09-21T00:12:43.145224192
1374        let min_nanos = Timestamp::new_nanosecond(-9223372036854775000);
1375        let max_nanos = Timestamp::new_nanosecond(i64::MAX);
1376        check_conversion(min_nanos, true);
1377        check_conversion(Timestamp::new_nanosecond(min_nanos.value - 1), false);
1378        check_conversion(max_nanos, true);
1379    }
1380
1381    #[test]
1382    fn test_parse_timestamp_range() {
1383        let datetime_min = NaiveDateTime::MIN.format("%Y-%m-%d %H:%M:%SZ").to_string();
1384        assert_eq!("-262143-01-01 00:00:00Z", datetime_min);
1385        let datetime_max = NaiveDateTime::MAX.format("%Y-%m-%d %H:%M:%SZ").to_string();
1386        assert_eq!("+262142-12-31 23:59:59Z", datetime_max);
1387
1388        let valid_strings = vec![
1389            "-262143-01-01 00:00:00Z",
1390            "+262142-12-31 23:59:59Z",
1391            "+262142-12-31 23:59:59.999Z",
1392            "+262142-12-31 23:59:59.999999Z",
1393            "1677-09-21 00:12:43.145224192Z",
1394            "2262-04-11 23:47:16.854775807Z",
1395            "+100000-01-01 00:00:01.5Z",
1396        ];
1397
1398        for s in valid_strings {
1399            Timestamp::from_str_utc(s).unwrap();
1400        }
1401    }
1402
1403    #[test]
1404    fn test_min_nanos_roundtrip() {
1405        let (sec, nsec) = Timestamp::MIN_NANOSECOND.split();
1406        let ts = Timestamp::from_splits(sec, nsec).unwrap();
1407        assert_eq!(Timestamp::MIN_NANOSECOND, ts);
1408    }
1409
1410    #[test]
1411    fn test_timestamp_bound_format() {
1412        assert_eq!(
1413            "1677-09-21 00:12:43.145224192",
1414            Timestamp::MIN_NANOSECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1415        );
1416        assert_eq!(
1417            "2262-04-11 23:47:16.854775807",
1418            Timestamp::MAX_NANOSECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1419        );
1420        assert_eq!(
1421            "-262143-01-01 00:00:00",
1422            Timestamp::MIN_MICROSECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1423        );
1424        assert_eq!(
1425            "+262142-12-31 23:59:59.999999",
1426            Timestamp::MAX_MICROSECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1427        );
1428        assert_eq!(
1429            "-262143-01-01 00:00:00",
1430            Timestamp::MIN_MILLISECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1431        );
1432        assert_eq!(
1433            "+262142-12-31 23:59:59.999",
1434            Timestamp::MAX_MILLISECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1435        );
1436        assert_eq!(
1437            "-262143-01-01 00:00:00",
1438            Timestamp::MIN_SECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1439        );
1440        assert_eq!(
1441            "+262142-12-31 23:59:59",
1442            Timestamp::MAX_SECOND.to_timezone_aware_string(Some(&Timezone::Named(Tz::UTC)))
1443        );
1444    }
1445
1446    #[test]
1447    fn test_debug_timestamp() {
1448        assert_eq!(
1449            "1000::Second",
1450            format!("{:?}", Timestamp::new(1000, TimeUnit::Second))
1451        );
1452        assert_eq!(
1453            "1001::Millisecond",
1454            format!("{:?}", Timestamp::new(1001, TimeUnit::Millisecond))
1455        );
1456        assert_eq!(
1457            "1002::Microsecond",
1458            format!("{:?}", Timestamp::new(1002, TimeUnit::Microsecond))
1459        );
1460        assert_eq!(
1461            "1003::Nanosecond",
1462            format!("{:?}", Timestamp::new(1003, TimeUnit::Nanosecond))
1463        );
1464    }
1465}