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