bson/datetime/
builder.rs

1use std::convert::TryFrom;
2
3use time::Date;
4
5use crate::{
6    datetime::DateTime,
7    error::{Error, Result},
8};
9
10/// Builder for constructing a BSON [`DateTime`]
11pub struct DateTimeBuilder<Y = NoYear, M = NoMonth, D = NoDay> {
12    pub(crate) year: Y,
13    pub(crate) month: M,
14    pub(crate) day: D,
15
16    pub(crate) hour: Option<u8>,
17    pub(crate) minute: Option<u8>,
18    pub(crate) second: Option<u8>,
19    pub(crate) millisecond: Option<u16>,
20}
21
22impl Default for DateTimeBuilder {
23    fn default() -> Self {
24        Self {
25            year: NoYear,
26            month: NoMonth,
27            day: NoDay,
28            hour: None,
29            minute: None,
30            second: None,
31            millisecond: None,
32        }
33    }
34}
35
36pub struct Year(i32);
37pub struct NoYear;
38
39pub struct Month(u8);
40pub struct NoMonth;
41
42pub struct Day(u8);
43pub struct NoDay;
44
45impl<M, D> DateTimeBuilder<NoYear, M, D> {
46    /// Sets the year for the builder instance. Years between ±9999 inclusive are valid.
47    /// If the specified value is out of range, calling the `build()` method will return
48    /// an error.
49    ///
50    /// Note: This is a required method. You will not be able to call `build()` before calling
51    /// this method.
52    pub fn year(self, y: i32) -> DateTimeBuilder<Year, M, D> {
53        let Self {
54            year: _,
55            month,
56            day,
57            hour,
58            minute,
59            second,
60            millisecond,
61        } = self;
62        DateTimeBuilder {
63            year: Year(y),
64            month,
65            day,
66            hour,
67            minute,
68            second,
69            millisecond,
70        }
71    }
72}
73
74impl<Y, D> DateTimeBuilder<Y, NoMonth, D> {
75    /// Sets the month for the builder instance. Maps months as 1-January to 12-December.
76    /// If the specified value is out of range, calling the `build()` method will return
77    /// an error.
78    ///
79    /// Note: This is a required method. You will not be able to call `build()` before calling
80    /// this method.
81    pub fn month(self, m: u8) -> DateTimeBuilder<Y, Month, D> {
82        let Self {
83            year,
84            month: _,
85            day,
86            hour,
87            minute,
88            second,
89            millisecond,
90        } = self;
91        DateTimeBuilder {
92            year,
93            month: Month(m),
94            day,
95            hour,
96            minute,
97            second,
98            millisecond,
99        }
100    }
101}
102
103impl<Y, M> DateTimeBuilder<Y, M, NoDay> {
104    /// Sets the day for the builder instance. Values in the range `1..=31` are valid.
105    /// If the specified value does not exist for the provided month/year or is out of range,
106    /// calling the `build()` method will return an error.
107    ///
108    /// Note: This is a required method. You will not be able to call `build()` before calling
109    /// this method.
110    pub fn day(self, d: u8) -> DateTimeBuilder<Y, M, Day> {
111        let Self {
112            year,
113            month,
114            day: _,
115            hour,
116            minute,
117            second,
118            millisecond,
119        } = self;
120        DateTimeBuilder {
121            year,
122            month,
123            day: Day(d),
124            hour,
125            minute,
126            second,
127            millisecond,
128        }
129    }
130}
131
132impl<Y, M, D> DateTimeBuilder<Y, M, D> {
133    /// Sets the hour (24-hour format) for the builder instance. Values must be in the range
134    /// `0..=23`. If the specified value is out of range, calling the `build()` method will
135    /// return an error.
136    ///
137    /// Note: This is an optional method. The hour will default to 0 if not explicitly set.
138    pub fn hour(mut self, hour: u8) -> DateTimeBuilder<Y, M, D> {
139        self.hour = Some(hour);
140        self
141    }
142
143    /// Sets the minute for the builder instance. Values must be in the range `0..=59`.
144    /// If the specified value is out of range, calling the `build()` method will return an error.
145    ///
146    /// Note: This is an optional method. The minute will default to 0 if not explicitly set.
147    pub fn minute(mut self, minute: u8) -> DateTimeBuilder<Y, M, D> {
148        self.minute = Some(minute);
149        self
150    }
151
152    /// Sets the second for the builder instance. Values must be in range `0..=59`.
153    /// If the specified value is out of range, calling the `build()` method will return an error.
154    ///
155    /// Note: This is an optional method. The second will default to 0 if not explicitly set.
156    pub fn second(mut self, second: u8) -> DateTimeBuilder<Y, M, D> {
157        self.second = Some(second);
158        self
159    }
160
161    /// Sets the millisecond for the builder instance. Values must be in the range `0..=999`.
162    /// If the specified value is out of range, calling the `build()` method will return an error.
163    ///
164    /// Note: This is an optional method. The millisecond will default to 0 if not explicitly set.
165    pub fn millisecond(mut self, millisecond: u16) -> DateTimeBuilder<Y, M, D> {
166        self.millisecond = Some(millisecond);
167        self
168    }
169}
170
171impl DateTimeBuilder<Year, Month, Day> {
172    /// Convert a builder with a specified year, month, day, and optionally, an hour, minute, second
173    /// and millisecond to a [`DateTime`].
174    ///
175    /// Note: You cannot call `build()` before setting at least the year, month and day.
176    pub fn build(self) -> Result<DateTime> {
177        let month = time::Month::try_from(self.month.0).map_err(Error::datetime)?;
178        let dt = Date::from_calendar_date(self.year.0, month, self.day.0)
179            .map_err(Error::datetime)?
180            .with_hms_milli(
181                self.hour.unwrap_or(0),
182                self.minute.unwrap_or(0),
183                self.second.unwrap_or(0),
184                self.millisecond.unwrap_or(0),
185            )
186            .map_err(Error::datetime)?;
187        Ok(DateTime::from_time_private(dt.assume_utc()))
188    }
189}