Skip to main content

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