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}