Skip to main content

risingwave_common/types/
datetime.rs

1// Copyright 2023 RisingWave Labs
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
15//! Date, time, and timestamp types.
16
17use std::error::Error;
18use std::fmt::Display;
19use std::hash::Hash;
20use std::io::{Cursor, Write};
21use std::str::FromStr;
22
23use anyhow::Context;
24use byteorder::{BigEndian, ReadBytesExt};
25use bytes::BytesMut;
26use chrono::{
27    DateTime, Datelike, Days, Duration, NaiveDate, NaiveDateTime, NaiveTime, Timelike, Weekday,
28};
29use postgres_types::{FromSql, IsNull, ToSql, Type, accepts, to_sql_checked};
30use risingwave_common_estimate_size::ZeroHeapSize;
31use thiserror::Error;
32
33use super::to_text::ToText;
34use super::{CheckedAdd, DataType, Interval};
35use crate::array::{ArrayError, ArrayResult};
36
37/// The same as `NaiveDate::from_ymd(1970, 1, 1).num_days_from_ce()`.
38/// Minus this magic number to store the number of days since 1970-01-01.
39const UNIX_EPOCH_DAYS: i32 = 719_163;
40const LEAP_DAYS: &[i32] = &[0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
41const NORMAL_DAYS: &[i32] = &[0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
42
43macro_rules! impl_chrono_wrapper {
44    ($variant_name:ident, $chrono:ty, $pg_type:ident) => {
45        #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
46        #[repr(transparent)]
47        pub struct $variant_name(pub $chrono);
48
49        impl $variant_name {
50            pub const MIN: Self = Self(<$chrono>::MIN);
51
52            pub fn new(data: $chrono) -> Self {
53                $variant_name(data)
54            }
55        }
56
57        impl Display for $variant_name {
58            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59                ToText::write(self, f)
60            }
61        }
62
63        impl From<$chrono> for $variant_name {
64            fn from(data: $chrono) -> Self {
65                $variant_name(data)
66            }
67        }
68
69        impl ZeroHeapSize for $variant_name {}
70
71        impl ToSql for $variant_name {
72            accepts!($pg_type);
73
74            to_sql_checked!();
75
76            fn to_sql(
77                &self,
78                ty: &Type,
79                out: &mut BytesMut,
80            ) -> std::result::Result<IsNull, Box<dyn Error + Sync + Send>>
81            where
82                Self: Sized,
83            {
84                self.0.to_sql(ty, out)
85            }
86        }
87
88        impl<'a> FromSql<'a> for $variant_name {
89            fn from_sql(
90                ty: &Type,
91                raw: &'a [u8],
92            ) -> std::result::Result<Self, Box<dyn std::error::Error + Sync + Send>> {
93                let instant = <$chrono>::from_sql(ty, raw)?;
94                Ok(Self::from(instant))
95            }
96
97            fn accepts(ty: &Type) -> bool {
98                matches!(*ty, Type::$pg_type)
99            }
100        }
101    };
102}
103
104impl_chrono_wrapper!(Date, NaiveDate, DATE);
105impl_chrono_wrapper!(Timestamp, NaiveDateTime, TIMESTAMP);
106impl_chrono_wrapper!(Time, NaiveTime, TIME);
107
108/// Parse a date from varchar.
109///
110/// # Example
111/// ```
112/// use std::str::FromStr;
113///
114/// use risingwave_common::types::Date;
115///
116/// Date::from_str("1999-01-08").unwrap();
117/// ```
118impl FromStr for Date {
119    type Err = InvalidParamsError;
120
121    fn from_str(s: &str) -> Result<Self> {
122        let date = speedate::Date::parse_str_rfc3339(s).map_err(|_| ErrorKind::ParseDate)?;
123        Ok(Date::new(
124            Date::from_ymd_uncheck(date.year as i32, date.month as u32, date.day as u32).0,
125        ))
126    }
127}
128
129/// Parse a time from varchar.
130///
131/// # Example
132/// ```
133/// use std::str::FromStr;
134///
135/// use risingwave_common::types::Time;
136///
137/// Time::from_str("04:05").unwrap();
138/// Time::from_str("04:05:06").unwrap();
139/// ```
140impl FromStr for Time {
141    type Err = InvalidParamsError;
142
143    fn from_str(s: &str) -> Result<Self> {
144        let s_without_zone = s.trim_end_matches('Z');
145        let res = speedate::Time::parse_str(s_without_zone).map_err(|_| ErrorKind::ParseTime)?;
146        Ok(Time::from_hms_micro_uncheck(
147            res.hour as u32,
148            res.minute as u32,
149            res.second as u32,
150            res.microsecond,
151        ))
152    }
153}
154
155/// Parse a timestamp from varchar.
156///
157/// # Example
158/// ```
159/// use std::str::FromStr;
160///
161/// use risingwave_common::types::Timestamp;
162///
163/// Timestamp::from_str("1999-01-08 04:02").unwrap();
164/// Timestamp::from_str("1999-01-08 04:05:06").unwrap();
165/// Timestamp::from_str("1999-01-08T04:05:06").unwrap();
166/// ```
167impl FromStr for Timestamp {
168    type Err = InvalidParamsError;
169
170    fn from_str(s: &str) -> Result<Self> {
171        let dt = s
172            .parse::<jiff::civil::DateTime>()
173            .map_err(|_| ErrorKind::ParseTimestamp)?;
174        Ok(
175            Date::from_ymd_uncheck(dt.year() as i32, dt.month() as u32, dt.day() as u32)
176                .and_hms_nano_uncheck(
177                    dt.hour() as u32,
178                    dt.minute() as u32,
179                    dt.second() as u32,
180                    dt.subsec_nanosecond() as u32,
181                ),
182        )
183    }
184}
185
186/// In `PostgreSQL`, casting from timestamp to date discards the time part.
187///
188/// # Example
189/// ```
190/// use std::str::FromStr;
191///
192/// use risingwave_common::types::{Date, Timestamp};
193///
194/// let ts = Timestamp::from_str("1999-01-08 04:02").unwrap();
195/// let date = Date::from(ts);
196/// assert_eq!(date, Date::from_str("1999-01-08").unwrap());
197/// ```
198impl From<Timestamp> for Date {
199    fn from(ts: Timestamp) -> Self {
200        Date::new(ts.0.date())
201    }
202}
203
204/// In `PostgreSQL`, casting from timestamp to time discards the date part.
205///
206/// # Example
207/// ```
208/// use std::str::FromStr;
209///
210/// use risingwave_common::types::{Time, Timestamp};
211///
212/// let ts = Timestamp::from_str("1999-01-08 04:02").unwrap();
213/// let time = Time::from(ts);
214/// assert_eq!(time, Time::from_str("04:02").unwrap());
215/// ```
216impl From<Timestamp> for Time {
217    fn from(ts: Timestamp) -> Self {
218        Time::new(ts.0.time())
219    }
220}
221
222/// In `PostgreSQL`, casting from interval to time discards the days part.
223///
224/// # Example
225/// ```
226/// use std::str::FromStr;
227///
228/// use risingwave_common::types::{Interval, Time};
229///
230/// let interval = Interval::from_month_day_usec(1, 2, 61000003);
231/// let time = Time::from(interval);
232/// assert_eq!(time, Time::from_str("00:01:01.000003").unwrap());
233///
234/// let interval = Interval::from_month_day_usec(0, 0, -61000003);
235/// let time = Time::from(interval);
236/// assert_eq!(time, Time::from_str("23:58:58.999997").unwrap());
237/// ```
238impl From<Interval> for Time {
239    fn from(interval: Interval) -> Self {
240        let usecs = interval.usecs_of_day();
241        let secs = (usecs / 1_000_000) as u32;
242        let nano = (usecs % 1_000_000 * 1000) as u32;
243        Time::from_num_seconds_from_midnight_uncheck(secs, nano)
244    }
245}
246
247#[derive(Copy, Clone, Debug, Error)]
248enum ErrorKind {
249    #[error("Invalid date: days: {days}")]
250    Date { days: i32 },
251    #[error("Invalid time: secs: {secs}, nanoseconds: {nsecs}")]
252    Time { secs: u32, nsecs: u32 },
253    #[error("Invalid time: {value} {unit} is out of range for a time of day")]
254    TimeOfDay { value: u64, unit: &'static str },
255    #[error("Invalid datetime: seconds: {secs}, nanoseconds: {nsecs}")]
256    DateTime { secs: i64, nsecs: u32 },
257    #[error("Invalid datetime: {value} {unit} is out of range")]
258    Timestamp { value: i64, unit: &'static str },
259    #[error("Can't cast string to date (expected format is YYYY-MM-DD)")]
260    ParseDate,
261    #[error(
262        "Can't cast string to time (expected format is HH:MM:SS[.D+{{up to 6 digits}}][Z] or HH:MM)"
263    )]
264    ParseTime,
265    #[error(
266        "Can't cast string to timestamp (expected format is YYYY-MM-DD HH:MM:SS[.D+{{up to 9 digits}}] or YYYY-MM-DD HH:MM or YYYY-MM-DD or ISO 8601 format)"
267    )]
268    ParseTimestamp,
269}
270
271#[derive(Debug, Error)]
272#[error(transparent)]
273pub struct InvalidParamsError(#[from] ErrorKind);
274
275impl InvalidParamsError {
276    pub fn date(days: i32) -> Self {
277        ErrorKind::Date { days }.into()
278    }
279
280    pub fn time(secs: u32, nsecs: u32) -> Self {
281        ErrorKind::Time { secs, nsecs }.into()
282    }
283
284    pub fn time_of_day(value: u64, unit: &'static str) -> Self {
285        ErrorKind::TimeOfDay { value, unit }.into()
286    }
287
288    pub fn datetime(secs: i64, nsecs: u32) -> Self {
289        ErrorKind::DateTime { secs, nsecs }.into()
290    }
291
292    pub fn timestamp(value: i64, unit: &'static str) -> Self {
293        ErrorKind::Timestamp { value, unit }.into()
294    }
295}
296
297impl From<InvalidParamsError> for ArrayError {
298    fn from(e: InvalidParamsError) -> Self {
299        ArrayError::internal(e)
300    }
301}
302
303type Result<T> = std::result::Result<T, InvalidParamsError>;
304
305impl ToText for Date {
306    /// ```
307    /// # use risingwave_common::types::Date;
308    /// let date = Date::from_ymd_uncheck(2001, 5, 16);
309    /// assert_eq!(date.to_string(), "2001-05-16");
310    ///
311    /// let date = Date::from_ymd_uncheck(1, 10, 26);
312    /// assert_eq!(date.to_string(), "0001-10-26");
313    ///
314    /// let date = Date::from_ymd_uncheck(0, 10, 26);
315    /// assert_eq!(date.to_string(), "0001-10-26 BC");
316    /// ```
317    fn write<W: std::fmt::Write>(&self, f: &mut W) -> std::fmt::Result {
318        let (ce, year) = self.0.year_ce();
319        let suffix = if ce { "" } else { " BC" };
320        write!(
321            f,
322            "{:04}-{:02}-{:02}{}",
323            year,
324            self.0.month(),
325            self.0.day(),
326            suffix
327        )
328    }
329
330    fn write_with_type<W: std::fmt::Write>(&self, ty: &DataType, f: &mut W) -> std::fmt::Result {
331        match ty {
332            super::DataType::Date => self.write(f),
333            _ => unreachable!(),
334        }
335    }
336}
337
338impl ToText for Time {
339    fn write<W: std::fmt::Write>(&self, f: &mut W) -> std::fmt::Result {
340        write!(f, "{}", self.0)
341    }
342
343    fn write_with_type<W: std::fmt::Write>(&self, ty: &DataType, f: &mut W) -> std::fmt::Result {
344        match ty {
345            super::DataType::Time => self.write(f),
346            _ => unreachable!(),
347        }
348    }
349}
350
351impl ToText for Timestamp {
352    fn write<W: std::fmt::Write>(&self, f: &mut W) -> std::fmt::Result {
353        let (ce, year) = self.0.year_ce();
354        let suffix = if ce { "" } else { " BC" };
355        write!(
356            f,
357            "{:04}-{:02}-{:02} {}{}",
358            year,
359            self.0.month(),
360            self.0.day(),
361            self.0.time(),
362            suffix
363        )
364    }
365
366    fn write_with_type<W: std::fmt::Write>(&self, ty: &DataType, f: &mut W) -> std::fmt::Result {
367        match ty {
368            super::DataType::Timestamp => self.write(f),
369            _ => unreachable!(),
370        }
371    }
372}
373
374impl Date {
375    pub fn with_days_since_ce(days: i32) -> Result<Self> {
376        Ok(Date::new(
377            NaiveDate::from_num_days_from_ce_opt(days)
378                .ok_or_else(|| InvalidParamsError::date(days))?,
379        ))
380    }
381
382    pub fn with_days_since_unix_epoch(days: i32) -> Result<Self> {
383        Ok(Date::new(
384            NaiveDate::from_num_days_from_ce_opt(days)
385                .ok_or_else(|| InvalidParamsError::date(days))?
386                .checked_add_days(Days::new(UNIX_EPOCH_DAYS as u64))
387                .ok_or_else(|| InvalidParamsError::date(days))?,
388        ))
389    }
390
391    pub fn get_nums_days_unix_epoch(&self) -> i32 {
392        self.0
393            .checked_sub_days(Days::new(UNIX_EPOCH_DAYS as u64))
394            .unwrap()
395            .num_days_from_ce()
396    }
397
398    pub fn from_protobuf(cur: &mut Cursor<&[u8]>) -> ArrayResult<Date> {
399        let days = cur
400            .read_i32::<BigEndian>()
401            .context("failed to read i32 from Date buffer")?;
402
403        Ok(Date::with_days_since_ce(days)?)
404    }
405
406    pub fn to_protobuf<T: Write>(self, output: &mut T) -> ArrayResult<usize> {
407        output
408            .write(&(self.0.num_days_from_ce()).to_be_bytes())
409            .map_err(Into::into)
410    }
411
412    pub fn from_ymd_uncheck(year: i32, month: u32, day: u32) -> Self {
413        Self::new(NaiveDate::from_ymd_opt(year, month, day).unwrap())
414    }
415
416    pub fn from_num_days_from_ce_uncheck(days: i32) -> Self {
417        Self::with_days_since_ce(days).unwrap()
418    }
419
420    pub fn and_hms_uncheck(self, hour: u32, min: u32, sec: u32) -> Timestamp {
421        self.and_hms_micro_uncheck(hour, min, sec, 0)
422    }
423
424    pub fn and_hms_micro_uncheck(self, hour: u32, min: u32, sec: u32, micro: u32) -> Timestamp {
425        Timestamp::new(
426            self.0
427                .and_time(Time::from_hms_micro_uncheck(hour, min, sec, micro).0),
428        )
429    }
430
431    pub fn and_hms_nano_uncheck(self, hour: u32, min: u32, sec: u32, nano: u32) -> Timestamp {
432        Timestamp::new(
433            self.0
434                .and_time(Time::from_hms_nano_uncheck(hour, min, sec, nano).0),
435        )
436    }
437}
438
439/// Exclusive upper bounds of a time of day.
440const NANOS_PER_DAY: u64 = 86_400 * 1_000_000_000;
441const MICROS_PER_DAY: u64 = 86_400 * 1_000_000;
442
443impl Time {
444    pub fn with_secs_nano(secs: u32, nano: u32) -> Result<Self> {
445        Ok(Time::new(
446            NaiveTime::from_num_seconds_from_midnight_opt(secs, nano)
447                .ok_or_else(|| InvalidParamsError::time(secs, nano))?,
448        ))
449    }
450
451    pub fn from_protobuf(cur: &mut Cursor<&[u8]>) -> ArrayResult<Time> {
452        let nano = cur
453            .read_u64::<BigEndian>()
454            .context("failed to read u64 from Time buffer")?;
455
456        Ok(Time::with_nano(nano)?)
457    }
458
459    pub fn to_protobuf<T: Write>(self, output: &mut T) -> ArrayResult<usize> {
460        output
461            .write(&self.nanos_of_day().to_be_bytes())
462            .map_err(Into::into)
463    }
464
465    pub fn with_nano(nano: u64) -> Result<Self> {
466        // Rejecting out-of-day values here also keeps the casts below lossless.
467        if nano >= NANOS_PER_DAY {
468            return Err(InvalidParamsError::time_of_day(nano, "nanoseconds"));
469        }
470        Self::with_secs_nano((nano / 1_000_000_000) as u32, (nano % 1_000_000_000) as u32)
471    }
472
473    pub fn with_micro(micro: u64) -> Result<Self> {
474        if micro >= MICROS_PER_DAY {
475            return Err(InvalidParamsError::time_of_day(micro, "microseconds"));
476        }
477        Self::with_secs_nano(
478            (micro / 1_000_000) as u32,
479            ((micro % 1_000_000) * 1_000) as u32,
480        )
481    }
482
483    /// Nanoseconds since midnight, the inverse of [`Time::with_nano`].
484    pub fn nanos_of_day(self) -> u64 {
485        self.0.num_seconds_from_midnight() as u64 * 1_000_000_000 + self.0.nanosecond() as u64
486    }
487
488    /// Microseconds since midnight, truncating sub-microsecond precision.
489    pub fn micros_of_day(self) -> u64 {
490        self.0.num_seconds_from_midnight() as u64 * 1_000_000 + self.0.nanosecond() as u64 / 1_000
491    }
492
493    pub fn with_milli(milli: u32) -> Result<Self> {
494        let secs = milli / 1_000;
495        let nano = (milli % 1_000) * 1_000_000;
496        Self::with_secs_nano(secs, nano)
497    }
498
499    pub fn from_hms_uncheck(hour: u32, min: u32, sec: u32) -> Self {
500        Self::from_hms_nano_uncheck(hour, min, sec, 0)
501    }
502
503    pub fn from_hms_micro_uncheck(hour: u32, min: u32, sec: u32, micro: u32) -> Self {
504        Self::new(NaiveTime::from_hms_micro_opt(hour, min, sec, micro).unwrap())
505    }
506
507    pub fn from_hms_nano_uncheck(hour: u32, min: u32, sec: u32, nano: u32) -> Self {
508        Self::new(NaiveTime::from_hms_nano_opt(hour, min, sec, nano).unwrap())
509    }
510
511    pub fn from_num_seconds_from_midnight_uncheck(secs: u32, nano: u32) -> Self {
512        Self::new(NaiveTime::from_num_seconds_from_midnight_opt(secs, nano).unwrap())
513    }
514}
515
516// The first 64 bits of protobuf encoding for `Timestamp` type has 2 possible meanings.
517// * When the highest 2 bits are `11` or `00` (i.e. values ranging from `0b1100...00` to `0b0011..11`),
518//   it is *microseconds* since 1970-01-01 midnight. 2^62 microseconds covers 146235 years.
519// * When the highest 2 bits are `10` or `01`, we flip the second bit to get values from `0b1100...00` to `0b0011..11` again.
520//   It is *seconds* since 1970-01-01 midnight. It is then followed by another 32 bits as nanoseconds within a second.
521// Since timestamp is negative when it is less than 1970-1-1, you need to take both cases into account(`11+00`` or `01+10``).
522enum FirstI64 {
523    V0 { usecs: i64 },
524    V1 { secs: i64 },
525}
526impl FirstI64 {
527    pub fn to_protobuf(&self) -> i64 {
528        match self {
529            FirstI64::V0 { usecs } => *usecs,
530            FirstI64::V1 { secs } => secs ^ (0b01 << 62),
531        }
532    }
533
534    pub fn from_protobuf(cur: &mut Cursor<&[u8]>) -> ArrayResult<FirstI64> {
535        let value = cur
536            .read_i64::<BigEndian>()
537            .context("failed to read i64 from Time buffer")?;
538        if Self::is_v1_format_state(value) {
539            let secs = value ^ (0b01 << 62);
540            Ok(FirstI64::V1 { secs })
541        } else {
542            Ok(FirstI64::V0 { usecs: value })
543        }
544    }
545
546    fn is_v1_format_state(value: i64) -> bool {
547        let state = (value >> 62) & 0b11;
548        state == 0b10 || state == 0b01
549    }
550}
551
552impl Timestamp {
553    pub fn with_secs_nsecs(secs: i64, nsecs: u32) -> Result<Self> {
554        DateTime::from_timestamp(secs, nsecs)
555            .map(|t| Timestamp(t.naive_utc()))
556            .ok_or_else(|| InvalidParamsError::datetime(secs, nsecs))
557    }
558
559    pub fn from_protobuf(cur: &mut Cursor<&[u8]>) -> ArrayResult<Timestamp> {
560        match FirstI64::from_protobuf(cur)? {
561            FirstI64::V0 { usecs } => Ok(Timestamp::with_micros(usecs)?),
562            FirstI64::V1 { secs } => {
563                let nsecs = cur
564                    .read_u32::<BigEndian>()
565                    .context("failed to read u32 from Time buffer")?;
566                Ok(Timestamp::with_secs_nsecs(secs, nsecs)?)
567            }
568        }
569    }
570
571    // Since timestamp secs is much smaller than i64, we use the highest 2 bit to store the format information, which is compatible with the old format.
572    // New format: secs(i64) + nsecs(u32)
573    // Old format: micros(i64)
574    pub fn to_protobuf<T: Write>(self, output: &mut T) -> ArrayResult<usize> {
575        let timestamp_size = output
576            .write(
577                &(FirstI64::V1 {
578                    secs: self.0.and_utc().timestamp(),
579                }
580                .to_protobuf())
581                .to_be_bytes(),
582            )
583            .map_err(Into::<ArrayError>::into)?;
584        let timestamp_subsec_nanos_size = output
585            .write(&(self.0.and_utc().timestamp_subsec_nanos()).to_be_bytes())
586            .map_err(Into::<ArrayError>::into)?;
587        Ok(timestamp_subsec_nanos_size + timestamp_size)
588    }
589
590    pub fn get_timestamp_nanos(&self) -> i64 {
591        self.0.and_utc().timestamp_nanos_opt().unwrap()
592    }
593
594    pub fn with_millis(timestamp_millis: i64) -> Result<Self> {
595        DateTime::from_timestamp_millis(timestamp_millis)
596            .map(|t| Timestamp(t.naive_utc()))
597            .ok_or_else(|| InvalidParamsError::timestamp(timestamp_millis, "milliseconds"))
598    }
599
600    pub fn with_micros(timestamp_micros: i64) -> Result<Self> {
601        DateTime::from_timestamp_micros(timestamp_micros)
602            .map(|t| Timestamp(t.naive_utc()))
603            .ok_or_else(|| InvalidParamsError::timestamp(timestamp_micros, "microseconds"))
604    }
605
606    /// An `i64` nanosecond count is always representable, so this cannot fail.
607    pub fn with_nanos(timestamp_nanos: i64) -> Self {
608        Timestamp(DateTime::from_timestamp_nanos(timestamp_nanos).naive_utc())
609    }
610
611    pub fn from_timestamp_uncheck(secs: i64, nsecs: u32) -> Self {
612        Self::new(DateTime::from_timestamp(secs, nsecs).unwrap().naive_utc())
613    }
614
615    /// Truncate the timestamp to the precision of microseconds.
616    ///
617    /// # Example
618    /// ```
619    /// # use risingwave_common::types::Timestamp;
620    /// let ts = "2001-05-16T20:38:40.123456789".parse().unwrap();
621    /// assert_eq!(
622    ///     Timestamp::new(ts).truncate_micros().to_string(),
623    ///     "2001-05-16 20:38:40.123456"
624    /// );
625    /// ```
626    pub fn truncate_micros(self) -> Self {
627        Self::new(
628            self.0
629                .with_nanosecond(self.0.nanosecond() / 1000 * 1000)
630                .unwrap(),
631        )
632    }
633
634    /// Truncate the timestamp to the precision of milliseconds.
635    ///
636    /// # Example
637    /// ```
638    /// # use risingwave_common::types::Timestamp;
639    /// let ts = "2001-05-16T20:38:40.123456789".parse().unwrap();
640    /// assert_eq!(
641    ///     Timestamp::new(ts).truncate_millis().to_string(),
642    ///     "2001-05-16 20:38:40.123"
643    /// );
644    /// ```
645    pub fn truncate_millis(self) -> Self {
646        Self::new(
647            self.0
648                .with_nanosecond(self.0.nanosecond() / 1_000_000 * 1_000_000)
649                .unwrap(),
650        )
651    }
652
653    /// Truncate the timestamp to the precision of seconds.
654    ///
655    /// # Example
656    /// ```
657    /// # use risingwave_common::types::Timestamp;
658    /// let ts = "2001-05-16T20:38:40.123456789".parse().unwrap();
659    /// assert_eq!(
660    ///     Timestamp::new(ts).truncate_second().to_string(),
661    ///     "2001-05-16 20:38:40"
662    /// );
663    /// ```
664    pub fn truncate_second(self) -> Self {
665        Self::new(self.0.with_nanosecond(0).unwrap())
666    }
667
668    /// Truncate the timestamp to the precision of minutes.
669    ///
670    /// # Example
671    /// ```
672    /// # use risingwave_common::types::Timestamp;
673    /// let ts = "2001-05-16T20:38:40.123456789".parse().unwrap();
674    /// assert_eq!(
675    ///     Timestamp::new(ts).truncate_minute().to_string(),
676    ///     "2001-05-16 20:38:00"
677    /// );
678    /// ```
679    pub fn truncate_minute(self) -> Self {
680        Date::new(self.0.date()).and_hms_uncheck(self.0.hour(), self.0.minute(), 0)
681    }
682
683    /// Truncate the timestamp to the precision of hours.
684    ///
685    /// # Example
686    /// ```
687    /// # use risingwave_common::types::Timestamp;
688    /// let ts = "2001-05-16T20:38:40.123456789".parse().unwrap();
689    /// assert_eq!(
690    ///     Timestamp::new(ts).truncate_hour().to_string(),
691    ///     "2001-05-16 20:00:00"
692    /// );
693    /// ```
694    pub fn truncate_hour(self) -> Self {
695        Date::new(self.0.date()).and_hms_uncheck(self.0.hour(), 0, 0)
696    }
697
698    /// Truncate the timestamp to the precision of days.
699    ///
700    /// # Example
701    /// ```
702    /// # use risingwave_common::types::Timestamp;
703    /// let ts = "2001-05-16T20:38:40.123456789".parse().unwrap();
704    /// assert_eq!(
705    ///     Timestamp::new(ts).truncate_day().to_string(),
706    ///     "2001-05-16 00:00:00"
707    /// );
708    /// ```
709    pub fn truncate_day(self) -> Self {
710        Date::new(self.0.date()).into()
711    }
712
713    /// Truncate the timestamp to the precision of weeks.
714    ///
715    /// # Example
716    /// ```
717    /// # use risingwave_common::types::Timestamp;
718    /// let ts = "2001-05-16T20:38:40.123456789".parse().unwrap();
719    /// assert_eq!(
720    ///     Timestamp::new(ts).truncate_week().to_string(),
721    ///     "2001-05-14 00:00:00"
722    /// );
723    /// ```
724    pub fn truncate_week(self) -> Self {
725        Date::new(self.0.date().week(Weekday::Mon).first_day()).into()
726    }
727
728    /// Truncate the timestamp to the precision of months.
729    ///
730    /// # Example
731    /// ```
732    /// # use risingwave_common::types::Timestamp;
733    /// let ts = "2001-05-16T20:38:40.123456789".parse().unwrap();
734    /// assert_eq!(
735    ///     Timestamp::new(ts).truncate_month().to_string(),
736    ///     "2001-05-01 00:00:00"
737    /// );
738    /// ```
739    pub fn truncate_month(self) -> Self {
740        Date::new(self.0.date().with_day(1).unwrap()).into()
741    }
742
743    /// Truncate the timestamp to the precision of quarters.
744    ///
745    /// # Example
746    /// ```
747    /// # use risingwave_common::types::Timestamp;
748    /// let ts = "2001-05-16T20:38:40.123456789".parse().unwrap();
749    /// assert_eq!(
750    ///     Timestamp::new(ts).truncate_quarter().to_string(),
751    ///     "2001-04-01 00:00:00"
752    /// );
753    /// ```
754    pub fn truncate_quarter(self) -> Self {
755        Date::from_ymd_uncheck(self.0.year(), self.0.month0() / 3 * 3 + 1, 1).into()
756    }
757
758    /// Truncate the timestamp to the precision of years.
759    ///
760    /// # Example
761    /// ```
762    /// # use risingwave_common::types::Timestamp;
763    /// let ts = "2001-05-16T20:38:40.123456789".parse().unwrap();
764    /// assert_eq!(
765    ///     Timestamp::new(ts).truncate_year().to_string(),
766    ///     "2001-01-01 00:00:00"
767    /// );
768    /// ```
769    pub fn truncate_year(self) -> Self {
770        Date::from_ymd_uncheck(self.0.year(), 1, 1).into()
771    }
772
773    /// Truncate the timestamp to the precision of decades.
774    ///
775    /// # Example
776    /// ```
777    /// # use risingwave_common::types::Timestamp;
778    /// let ts = "2001-05-16T20:38:40.123456789".parse().unwrap();
779    /// assert_eq!(
780    ///     Timestamp::new(ts).truncate_decade().to_string(),
781    ///     "2000-01-01 00:00:00"
782    /// );
783    /// ```
784    pub fn truncate_decade(self) -> Self {
785        Date::from_ymd_uncheck(self.0.year() / 10 * 10, 1, 1).into()
786    }
787
788    /// Truncate the timestamp to the precision of centuries.
789    ///
790    /// # Example
791    /// ```
792    /// # use risingwave_common::types::Timestamp;
793    /// let ts = "3202-05-16T20:38:40.123456789".parse().unwrap();
794    /// assert_eq!(
795    ///     Timestamp::new(ts).truncate_century().to_string(),
796    ///     "3201-01-01 00:00:00"
797    /// );
798    /// ```
799    pub fn truncate_century(self) -> Self {
800        Date::from_ymd_uncheck((self.0.year() - 1) / 100 * 100 + 1, 1, 1).into()
801    }
802
803    /// Truncate the timestamp to the precision of millenniums.
804    ///
805    /// # Example
806    /// ```
807    /// # use risingwave_common::types::Timestamp;
808    /// let ts = "3202-05-16T20:38:40.123456789".parse().unwrap();
809    /// assert_eq!(
810    ///     Timestamp::new(ts).truncate_millennium().to_string(),
811    ///     "3001-01-01 00:00:00"
812    /// );
813    /// ```
814    pub fn truncate_millennium(self) -> Self {
815        Date::from_ymd_uncheck((self.0.year() - 1) / 1000 * 1000 + 1, 1, 1).into()
816    }
817}
818
819impl From<Date> for Timestamp {
820    fn from(date: Date) -> Self {
821        date.and_hms_uncheck(0, 0, 0)
822    }
823}
824
825/// return the days of the `year-month`
826fn get_mouth_days(year: i32, month: usize) -> i32 {
827    if is_leap_year(year) {
828        LEAP_DAYS[month]
829    } else {
830        NORMAL_DAYS[month]
831    }
832}
833
834fn is_leap_year(year: i32) -> bool {
835    year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
836}
837
838impl CheckedAdd<Interval> for Timestamp {
839    type Output = Timestamp;
840
841    fn checked_add(self, rhs: Interval) -> Option<Timestamp> {
842        let mut date = self.0.date();
843        if rhs.months() != 0 {
844            // NaiveDate don't support add months. We need calculate manually
845            let mut day = date.day() as i32;
846            let mut month = date.month() as i32;
847            let mut year = date.year();
848            // Calculate the number of year in this interval
849            let interval_months = rhs.months();
850            let year_diff = interval_months / 12;
851            year += year_diff;
852
853            // Calculate the number of month in this interval except the added year
854            // The range of month_diff is (-12, 12) (The month is negative when the interval is
855            // negative)
856            let month_diff = interval_months - year_diff * 12;
857            // The range of new month is (-12, 24) ( original month:[1, 12] + month_diff:(-12, 12) )
858            month += month_diff;
859            // Process the overflow months
860            if month > 12 {
861                year += 1;
862                month -= 12;
863            } else if month <= 0 {
864                year -= 1;
865                month += 12;
866            }
867
868            // Fix the days after changing date.
869            // For example, 1970.1.31 + 1 month = 1970.2.28
870            day = day.min(get_mouth_days(year, month as usize));
871            date = NaiveDate::from_ymd_opt(year, month as u32, day as u32)?;
872        }
873        let mut datetime = NaiveDateTime::new(date, self.0.time());
874        datetime = datetime.checked_add_signed(Duration::days(rhs.days().into()))?;
875        datetime = datetime.checked_add_signed(Duration::microseconds(rhs.usecs()))?;
876
877        Some(Timestamp::new(datetime))
878    }
879}
880
881#[cfg(test)]
882mod tests {
883    use super::*;
884
885    #[test]
886    fn parse() {
887        assert_eq!(
888            Timestamp::from_str("2022-08-03T10:34:02").unwrap(),
889            Timestamp::from_str("2022-08-03 10:34:02").unwrap()
890        );
891        let ts = Timestamp::from_str("0001-11-15 07:35:40.999999").unwrap();
892        assert_eq!(ts.0.and_utc().timestamp_micros(), -62108094259000001);
893
894        let ts = Timestamp::from_str("1969-12-31 23:59:59.999999").unwrap();
895        assert_eq!(ts.0.and_utc().timestamp_micros(), -1);
896
897        // invalid datetime
898        Date::from_str("1999-01-08AA").unwrap_err();
899        Time::from_str("AA04:05:06").unwrap_err();
900        Timestamp::from_str("1999-01-08 04:05:06AA").unwrap_err();
901    }
902
903    #[test]
904    fn time_of_day_bounds() {
905        assert_eq!(
906            Time::with_micro(86_399_999_999).unwrap(),
907            Time::from_hms_micro_uncheck(23, 59, 59, 999_999)
908        );
909        assert_eq!(
910            Time::with_nano(86_399_999_999_999).unwrap(),
911            Time::from_hms_nano_uncheck(23, 59, 59, 999_999_999)
912        );
913
914        Time::with_micro(86_400_000_000).unwrap_err();
915        Time::with_nano(86_400_000_000_000).unwrap_err();
916
917        // A seconds count at a multiple of 2^32 used to wrap into the valid range.
918        Time::with_micro(4_294_967_296_000_000).unwrap_err();
919        Time::with_nano(4_294_967_296_000_000_000).unwrap_err();
920    }
921}