1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{cmp, fmt, hash};
4
5use crate::{translate::*, BoolError, DateDay, DateMonth, DateWeekday, DateYear};
6
7wrapper! {
8 #[doc(alias = "GDate")]
9 pub struct Date(BoxedInline<ffi::GDate>);
10
11 match fn {
12 copy => |ptr| gobject_ffi::g_boxed_copy(ffi::g_date_get_type(), ptr as *const _) as *mut _,
13 free => |ptr| ffi::g_date_free(ptr),
14 type_ => || ffi::g_date_get_type(),
15 }
16}
17
18unsafe impl Send for Date {}
19unsafe impl Sync for Date {}
20
21impl Date {
22 #[doc(alias = "g_date_new_dmy")]
23 pub fn from_dmy(day: DateDay, month: DateMonth, year: DateYear) -> Result<Date, BoolError> {
24 let month = month.into_glib();
25 unsafe {
26 let check: bool = from_glib(ffi::g_date_valid_dmy(day, month, year));
27 if !check {
28 Err(bool_error!("Invalid date"))
29 } else {
30 Ok(from_glib_full(ffi::g_date_new_dmy(day, month, year)))
31 }
32 }
33 }
34
35 #[doc(alias = "g_date_new_julian")]
36 pub fn from_julian(julian_day: u32) -> Result<Date, BoolError> {
37 if !Self::valid_julian(julian_day) {
38 Err(bool_error!("Invalid date"))
39 } else {
40 unsafe { Ok(from_glib_full(ffi::g_date_new_julian(julian_day))) }
41 }
42 }
43
44 #[doc(alias = "g_date_add_days")]
45 pub fn add_days(&mut self, n_days: u32) -> Result<(), BoolError> {
46 let julian_days = self.julian();
47 if julian_days == 0 || n_days > u32::MAX - julian_days {
48 Err(bool_error!("Invalid date"))
49 } else {
50 unsafe {
51 ffi::g_date_add_days(self.to_glib_none_mut().0, n_days);
52 }
53 Ok(())
54 }
55 }
56
57 #[doc(alias = "g_date_add_months")]
58 pub fn add_months(&mut self, n_months: u32) -> Result<(), BoolError> {
59 // The checks for this function are just a mess in the C code, allowing intermediate
60 // unknown state. So for now, nothing can be done...
61 unsafe {
62 ffi::g_date_add_months(self.to_glib_none_mut().0, n_months);
63 }
64 Ok(())
65 }
66
67 #[doc(alias = "g_date_add_years")]
68 pub fn add_years(&mut self, n_years: u16) -> Result<(), BoolError> {
69 let year = self.year();
70 if n_years > u16::MAX - year {
71 Err(bool_error!("Invalid date"))
72 } else {
73 unsafe {
74 ffi::g_date_add_years(self.to_glib_none_mut().0, n_years as _);
75 }
76 Ok(())
77 }
78 }
79
80 #[doc(alias = "g_date_clamp")]
81 pub fn clamp(&mut self, min_date: &Date, max_date: &Date) -> Result<(), BoolError> {
82 if min_date >= max_date {
83 Err(bool_error!("`min_date` must be before `max_date`"))
84 } else {
85 unsafe {
86 ffi::g_date_clamp(
87 self.to_glib_none_mut().0,
88 min_date.to_glib_none().0,
89 max_date.to_glib_none().0,
90 );
91 }
92 Ok(())
93 }
94 }
95
96 #[doc(alias = "g_date_compare")]
97 fn compare(&self, rhs: &Date) -> i32 {
98 unsafe { ffi::g_date_compare(self.to_glib_none().0, rhs.to_glib_none().0) }
99 }
100
101 #[doc(alias = "g_date_days_between")]
102 pub fn days_between(&self, date2: &Date) -> i32 {
103 unsafe { ffi::g_date_days_between(self.to_glib_none().0, date2.to_glib_none().0) }
104 }
105
106 #[doc(alias = "g_date_get_day")]
107 #[doc(alias = "get_day")]
108 pub fn day(&self) -> DateDay {
109 unsafe { ffi::g_date_get_day(self.to_glib_none().0) }
110 }
111
112 #[doc(alias = "g_date_get_day_of_year")]
113 #[doc(alias = "get_day_of_year")]
114 pub fn day_of_year(&self) -> u32 {
115 unsafe { ffi::g_date_get_day_of_year(self.to_glib_none().0) }
116 }
117
118 #[doc(alias = "g_date_get_iso8601_week_of_year")]
119 #[doc(alias = "get_iso8601_week_of_year")]
120 pub fn iso8601_week_of_year(&self) -> u32 {
121 unsafe { ffi::g_date_get_iso8601_week_of_year(self.to_glib_none().0) }
122 }
123
124 #[doc(alias = "g_date_get_julian")]
125 #[doc(alias = "get_julian")]
126 pub fn julian(&self) -> u32 {
127 unsafe { ffi::g_date_get_julian(self.to_glib_none().0) }
128 }
129
130 #[doc(alias = "g_date_get_monday_week_of_year")]
131 #[doc(alias = "get_monday_week_of_year")]
132 pub fn monday_week_of_year(&self) -> u32 {
133 unsafe { ffi::g_date_get_monday_week_of_year(self.to_glib_none().0) }
134 }
135
136 #[doc(alias = "g_date_get_month")]
137 #[doc(alias = "get_month")]
138 pub fn month(&self) -> DateMonth {
139 unsafe { from_glib(ffi::g_date_get_month(self.to_glib_none().0)) }
140 }
141
142 #[doc(alias = "g_date_get_sunday_week_of_year")]
143 #[doc(alias = "get_sunday_week_of_year")]
144 pub fn sunday_week_of_year(&self) -> u32 {
145 unsafe { ffi::g_date_get_sunday_week_of_year(self.to_glib_none().0) }
146 }
147
148 #[doc(alias = "g_date_get_weekday")]
149 #[doc(alias = "get_weekday")]
150 pub fn weekday(&self) -> DateWeekday {
151 unsafe { from_glib(ffi::g_date_get_weekday(self.to_glib_none().0)) }
152 }
153
154 #[doc(alias = "g_date_get_year")]
155 #[doc(alias = "get_year")]
156 pub fn year(&self) -> DateYear {
157 unsafe { ffi::g_date_get_year(self.to_glib_none().0) }
158 }
159
160 #[doc(alias = "g_date_is_first_of_month")]
161 pub fn is_first_of_month(&self) -> bool {
162 unsafe { from_glib(ffi::g_date_is_first_of_month(self.to_glib_none().0)) }
163 }
164
165 #[doc(alias = "g_date_is_last_of_month")]
166 pub fn is_last_of_month(&self) -> bool {
167 unsafe { from_glib(ffi::g_date_is_last_of_month(self.to_glib_none().0)) }
168 }
169
170 #[doc(alias = "g_date_order")]
171 pub fn order(&mut self, date2: &mut Date) {
172 unsafe {
173 ffi::g_date_order(self.to_glib_none_mut().0, date2.to_glib_none_mut().0);
174 }
175 }
176
177 #[doc(alias = "g_date_set_day")]
178 pub fn set_day(&mut self, day: DateDay) -> Result<(), BoolError> {
179 if !Self::valid_dmy(day, self.month(), self.year()) {
180 Err(bool_error!("invalid day"))
181 } else {
182 unsafe {
183 ffi::g_date_set_day(self.to_glib_none_mut().0, day);
184 }
185 Ok(())
186 }
187 }
188
189 #[doc(alias = "g_date_set_dmy")]
190 pub fn set_dmy(
191 &mut self,
192 day: DateDay,
193 month: DateMonth,
194 y: DateYear,
195 ) -> Result<(), BoolError> {
196 if !Self::valid_dmy(day, month, y) {
197 Err(bool_error!("invalid date"))
198 } else {
199 unsafe {
200 ffi::g_date_set_dmy(self.to_glib_none_mut().0, day, month.into_glib(), y);
201 }
202 Ok(())
203 }
204 }
205
206 #[doc(alias = "g_date_set_julian")]
207 pub fn set_julian(&mut self, julian_date: u32) -> Result<(), BoolError> {
208 if !Self::valid_julian(julian_date) {
209 Err(bool_error!("invalid date"))
210 } else {
211 unsafe {
212 ffi::g_date_set_julian(self.to_glib_none_mut().0, julian_date);
213 }
214 Ok(())
215 }
216 }
217
218 #[doc(alias = "g_date_set_month")]
219 pub fn set_month(&mut self, month: DateMonth) -> Result<(), BoolError> {
220 if !Self::valid_dmy(self.day(), month, self.year()) {
221 Err(bool_error!("invalid month"))
222 } else {
223 unsafe {
224 ffi::g_date_set_month(self.to_glib_none_mut().0, month.into_glib());
225 }
226 Ok(())
227 }
228 }
229
230 #[doc(alias = "g_date_set_parse")]
231 pub fn set_parse(&mut self, str: &str) -> Result<(), BoolError> {
232 let mut c = *self;
233 if !unsafe {
234 ffi::g_date_set_parse(c.to_glib_none_mut().0, str.to_glib_none().0);
235 ffi::g_date_valid(c.to_glib_none().0) == 0
236 } {
237 Err(bool_error!("invalid parse string"))
238 } else {
239 *self = c;
240 Ok(())
241 }
242 }
243
244 #[doc(alias = "g_date_set_time_t")]
245 pub fn set_time(&mut self, time_: u32) -> Result<(), BoolError> {
246 let mut c = *self;
247 unsafe {
248 ffi::g_date_set_time_t(c.to_glib_none_mut().0, time_ as _);
249 }
250 if !Self::valid_dmy(c.day(), c.month(), c.year()) {
251 Err(bool_error!("invalid time"))
252 } else {
253 *self = c;
254 Ok(())
255 }
256 }
257
258 //pub fn set_time_val(&mut self, timeval: /*Ignored*/&mut TimeVal) {
259 // unsafe { TODO: call ffi::g_date_set_time_val() }
260 //}
261
262 #[doc(alias = "g_date_set_year")]
263 pub fn set_year(&mut self, year: DateYear) -> Result<(), BoolError> {
264 if !Self::valid_dmy(self.day(), self.month(), year) {
265 Err(bool_error!("invalid year"))
266 } else {
267 unsafe {
268 ffi::g_date_set_year(self.to_glib_none_mut().0, year);
269 }
270 Ok(())
271 }
272 }
273
274 #[doc(alias = "g_date_subtract_days")]
275 pub fn subtract_days(&mut self, n_days: u32) -> Result<(), BoolError> {
276 let julian = self.julian();
277 if julian > n_days {
278 Err(bool_error!("invalid number of days"))
279 } else {
280 unsafe {
281 ffi::g_date_subtract_days(self.to_glib_none_mut().0, n_days);
282 }
283 Ok(())
284 }
285 }
286
287 #[doc(alias = "g_date_subtract_months")]
288 pub fn subtract_months(&mut self, n_months: u32) -> Result<(), BoolError> {
289 // The checks for this function are just a mess in the C code, allowing intermediate
290 // unknown state. So for now, nothing can be done...
291 unsafe {
292 ffi::g_date_subtract_months(self.to_glib_none_mut().0, n_months);
293 }
294 Ok(())
295 }
296
297 #[doc(alias = "g_date_subtract_years")]
298 pub fn subtract_years(&mut self, n_years: u16) -> Result<(), BoolError> {
299 if self.year() < n_years {
300 Err(bool_error!("invalid number of years"))
301 } else {
302 unsafe {
303 ffi::g_date_subtract_years(self.to_glib_none_mut().0, n_years as _);
304 }
305 Ok(())
306 }
307 }
308
309 //#[doc(alias="g_date_to_struct_tm")]
310 //pub fn to_struct_tm(&self, tm: /*Unimplemented*/Fundamental: Pointer) {
311 // unsafe { TODO: call ffi::g_date_to_struct_tm() }
312 //}
313
314 #[doc(alias = "g_date_valid")]
315 pub fn valid(&self) -> bool {
316 unsafe { from_glib(ffi::g_date_valid(self.to_glib_none().0)) }
317 }
318
319 #[doc(alias = "g_date_get_days_in_month")]
320 #[doc(alias = "get_days_in_month")]
321 pub fn days_in_month(month: DateMonth, year: DateYear) -> u8 {
322 unsafe { ffi::g_date_get_days_in_month(month.into_glib(), year) }
323 }
324
325 #[doc(alias = "g_date_get_monday_weeks_in_year")]
326 #[doc(alias = "get_monday_weeks_in_year")]
327 pub fn monday_weeks_in_year(year: DateYear) -> u8 {
328 unsafe { ffi::g_date_get_monday_weeks_in_year(year) }
329 }
330
331 #[doc(alias = "g_date_get_sunday_weeks_in_year")]
332 #[doc(alias = "get_sunday_weeks_in_year")]
333 pub fn sunday_weeks_in_year(year: DateYear) -> u8 {
334 unsafe { ffi::g_date_get_sunday_weeks_in_year(year) }
335 }
336
337 #[doc(alias = "g_date_is_leap_year")]
338 pub fn is_leap_year(year: DateYear) -> bool {
339 unsafe { from_glib(ffi::g_date_is_leap_year(year)) }
340 }
341
342 #[doc(alias = "g_date_strftime")]
343 pub fn strftime(s: &str, format: &str, date: &Date) -> usize {
344 let slen = s.len() as _;
345 unsafe {
346 ffi::g_date_strftime(
347 s.to_glib_none().0,
348 slen,
349 format.to_glib_none().0,
350 date.to_glib_none().0,
351 )
352 }
353 }
354
355 #[doc(alias = "g_date_valid_day")]
356 pub fn valid_day(day: DateDay) -> bool {
357 unsafe { from_glib(ffi::g_date_valid_day(day)) }
358 }
359
360 #[doc(alias = "g_date_valid_dmy")]
361 pub fn valid_dmy(day: DateDay, month: DateMonth, year: DateYear) -> bool {
362 unsafe { from_glib(ffi::g_date_valid_dmy(day, month.into_glib(), year)) }
363 }
364
365 #[doc(alias = "g_date_valid_julian")]
366 pub fn valid_julian(julian_date: u32) -> bool {
367 unsafe { from_glib(ffi::g_date_valid_julian(julian_date)) }
368 }
369
370 #[doc(alias = "g_date_valid_month")]
371 pub fn valid_month(month: DateMonth) -> bool {
372 unsafe { from_glib(ffi::g_date_valid_month(month.into_glib())) }
373 }
374
375 #[doc(alias = "g_date_valid_weekday")]
376 pub fn valid_weekday(weekday: DateWeekday) -> bool {
377 unsafe { from_glib(ffi::g_date_valid_weekday(weekday.into_glib())) }
378 }
379
380 #[doc(alias = "g_date_valid_year")]
381 pub fn valid_year(year: DateYear) -> bool {
382 unsafe { from_glib(ffi::g_date_valid_year(year)) }
383 }
384}
385
386impl PartialEq for Date {
387 #[inline]
388 fn eq(&self, other: &Self) -> bool {
389 self.compare(other) == 0
390 }
391}
392
393impl Eq for Date {}
394
395impl PartialOrd for Date {
396 #[inline]
397 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
398 Some(self.cmp(other))
399 }
400}
401
402impl Ord for Date {
403 #[inline]
404 fn cmp(&self, other: &Self) -> cmp::Ordering {
405 self.compare(other).cmp(&0)
406 }
407}
408
409impl fmt::Debug for Date {
410 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
411 f&mut DebugStruct<'_, '_>.debug_struct("Date")
412 .field("year", &self.year())
413 .field("month", &self.month())
414 .field(name:"day", &self.day())
415 .finish()
416 }
417}
418
419impl hash::Hash for Date {
420 fn hash<H>(&self, state: &mut H)
421 where
422 H: hash::Hasher,
423 {
424 self.year().hash(state);
425 self.month().hash(state);
426 self.day().hash(state);
427 }
428}
429
430#[cfg(test)]
431mod test {
432 use super::*;
433 use crate::value::ToValue;
434
435 #[test]
436 fn test_value() {
437 let d1 = Date::from_dmy(20, crate::DateMonth::November, 2021).unwrap();
438 let v = d1.to_value();
439 let d2 = v.get::<&Date>().unwrap();
440
441 assert_eq!(&d1, d2);
442 }
443}
444