Skip to main content

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}