dtt/datetime/builder.rs
1// Copyright © 2025 DateTime (DTT) library.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4//! Fluent builder for [`DateTime`].
5//!
6//! Lives in its own module so the `mod.rs` file can focus on the
7//! `DateTime` type and its core impls.
8
9use super::DateTime;
10use crate::error::DateTimeError;
11#[cfg(feature = "serde")]
12use serde::{Deserialize, Serialize};
13use time::UtcOffset;
14
15/// A builder for [`DateTime`] objects, allowing more ergonomic creation of
16/// datetimes with customized year, month, day, hour, minute, second, and offset.
17///
18/// # Examples
19///
20/// ```
21/// use dtt::datetime::{DateTime, DateTimeBuilder};
22/// use time::UtcOffset;
23///
24/// let builder = DateTimeBuilder::new()
25/// .year(2024)
26/// .month(1)
27/// .day(1)
28/// .hour(12)
29/// .minute(30)
30/// .second(45)
31/// .offset(UtcOffset::UTC);
32///
33/// let dt = builder.build();
34/// assert!(dt.is_ok());
35///
36/// let dt_unwrapped = dt.unwrap();
37/// assert_eq!(dt_unwrapped.year(), 2024);
38/// assert_eq!(dt_unwrapped.month().to_string(), "January");
39/// assert_eq!(dt_unwrapped.day(), 1);
40/// assert_eq!(dt_unwrapped.hour(), 12);
41/// assert_eq!(dt_unwrapped.minute(), 30);
42/// assert_eq!(dt_unwrapped.second(), 45);
43/// assert_eq!(dt_unwrapped.offset(), UtcOffset::UTC);
44/// ```
45#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
46#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
47pub struct DateTimeBuilder {
48 /// Calendar year, e.g. 2024.
49 year: i32,
50 /// Month (1-12).
51 month: u8,
52 /// Day of the month (1-31, depends on month).
53 day: u8,
54 /// Hour of the day (0-23).
55 hour: u8,
56 /// Minute of the hour (0-59).
57 minute: u8,
58 /// Second of the minute (0-59).
59 second: u8,
60 /// The time zone offset from UTC.
61 offset: UtcOffset,
62}
63
64impl Default for DateTimeBuilder {
65 fn default() -> Self {
66 Self::new()
67 }
68}
69
70impl DateTimeBuilder {
71 /// Creates a new `DateTimeBuilder` with default values set to
72 /// midnight, January 1, 1970 (UTC).
73 #[must_use]
74 pub const fn new() -> Self {
75 Self {
76 year: 1970,
77 month: 1,
78 day: 1,
79 hour: 0,
80 minute: 0,
81 second: 0,
82 offset: UtcOffset::UTC,
83 }
84 }
85
86 /// Sets the year component.
87 #[must_use]
88 pub const fn year(mut self, year: i32) -> Self {
89 self.year = year;
90 self
91 }
92
93 /// Sets the month component.
94 #[must_use]
95 pub const fn month(mut self, month: u8) -> Self {
96 self.month = month;
97 self
98 }
99
100 /// Sets the day component.
101 #[must_use]
102 pub const fn day(mut self, day: u8) -> Self {
103 self.day = day;
104 self
105 }
106
107 /// Sets the hour component.
108 #[must_use]
109 pub const fn hour(mut self, hour: u8) -> Self {
110 self.hour = hour;
111 self
112 }
113
114 /// Sets the minute component.
115 #[must_use]
116 pub const fn minute(mut self, minute: u8) -> Self {
117 self.minute = minute;
118 self
119 }
120
121 /// Sets the second component.
122 #[must_use]
123 pub const fn second(mut self, second: u8) -> Self {
124 self.second = second;
125 self
126 }
127
128 /// Sets the time zone offset component.
129 #[must_use]
130 pub const fn offset(mut self, offset: UtcOffset) -> Self {
131 self.offset = offset;
132 self
133 }
134
135 /// Builds the final [`DateTime`] from the builder state.
136 ///
137 /// # Errors
138 ///
139 /// Returns a `DateTimeError` if any of the date components are invalid
140 /// (e.g., `month = 13` or `day = 32`).
141 pub fn build(&self) -> Result<DateTime, DateTimeError> {
142 DateTime::from_components(
143 self.year,
144 self.month,
145 self.day,
146 self.hour,
147 self.minute,
148 self.second,
149 self.offset,
150 )
151 }
152}