1// This is a part of Chrono.
2// See README.md and LICENSE.txt for details.
34//! ISO 8601 calendar date with time zone.
5#![allow(deprecated)]
67#[cfg(feature = "alloc")]
8use core::borrow::Borrow;
9use core::cmp::Ordering;
10use core::ops::{Add, AddAssign, Sub, SubAssign};
11use core::{fmt, hash};
1213#[cfg(feature = "rkyv")]
14use rkyv::{Archive, Deserialize, Serialize};
1516#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
17use crate::format::Locale;
18#[cfg(feature = "alloc")]
19use crate::format::{DelayedFormat, Item, StrftimeItems};
20use crate::naive::{IsoWeek, NaiveDate, NaiveTime};
21use crate::offset::{TimeZone, Utc};
22use crate::{DateTime, Datelike, TimeDelta, Weekday};
2324/// ISO 8601 calendar date with time zone.
25///
26/// You almost certainly want to be using a [`NaiveDate`] instead of this type.
27///
28/// This type primarily exists to aid in the construction of DateTimes that
29/// have a timezone by way of the [`TimeZone`] datelike constructors (e.g.
30/// [`TimeZone::ymd`]).
31///
32/// This type should be considered ambiguous at best, due to the inherent lack
33/// of precision required for the time zone resolution.
34///
35/// There are some guarantees on the usage of `Date<Tz>`:
36///
37/// - If properly constructed via [`TimeZone::ymd`] and others without an error,
38/// the corresponding local date should exist for at least a moment.
39/// (It may still have a gap from the offset changes.)
40///
41/// - The `TimeZone` is free to assign *any* [`Offset`](crate::offset::Offset) to the
42/// local date, as long as that offset did occur in given day.
43///
44/// For example, if `2015-03-08T01:59-08:00` is followed by `2015-03-08T03:00-07:00`,
45/// it may produce either `2015-03-08-08:00` or `2015-03-08-07:00`
46/// but *not* `2015-03-08+00:00` and others.
47///
48/// - Once constructed as a full `DateTime`, [`DateTime::date`] and other associated
49/// methods should return those for the original `Date`. For example, if `dt =
50/// tz.ymd_opt(y,m,d).unwrap().hms(h,n,s)` were valid, `dt.date() == tz.ymd_opt(y,m,d).unwrap()`.
51///
52/// - The date is timezone-agnostic up to one day (i.e. practically always),
53/// so the local date and UTC date should be equal for most cases
54/// even though the raw calculation between `NaiveDate` and `TimeDelta` may not.
55#[deprecated(since = "0.4.23", note = "Use `NaiveDate` or `DateTime<Tz>` instead")]
56#[derive(#[automatically_derived]
impl<Tz: ::core::clone::Clone + TimeZone> ::core::clone::Clone for Date<Tz>
where Tz::Offset: ::core::clone::Clone {
#[inline]
fn clone(&self) -> Date<Tz> {
Date {
date: ::core::clone::Clone::clone(&self.date),
offset: ::core::clone::Clone::clone(&self.offset),
}
}
}Clone)]
57#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
58pub struct Date<Tz: TimeZone> {
59 date: NaiveDate,
60 offset: Tz::Offset,
61}
6263/// The minimum possible `Date`.
64#[allow(deprecated)]
65#[deprecated(since = "0.4.20", note = "Use Date::MIN_UTC instead")]
66pub const MIN_DATE: Date<Utc> = Date::<Utc>::MIN_UTC;
67/// The maximum possible `Date`.
68#[allow(deprecated)]
69#[deprecated(since = "0.4.20", note = "Use Date::MAX_UTC instead")]
70pub const MAX_DATE: Date<Utc> = Date::<Utc>::MAX_UTC;
7172impl<Tz: TimeZone> Date<Tz> {
73/// Makes a new `Date` with given *UTC* date and offset.
74 /// The local date should be constructed via the `TimeZone` trait.
75#[inline]
76 #[must_use]
77pub fn from_utc(date: NaiveDate, offset: Tz::Offset) -> Date<Tz> {
78Date { date, offset }
79 }
8081/// Makes a new `DateTime` from the current date and given `NaiveTime`.
82 /// The offset in the current date is preserved.
83 ///
84 /// Returns `None` on invalid datetime.
85#[inline]
86 #[must_use]
87pub fn and_time(&self, time: NaiveTime) -> Option<DateTime<Tz>> {
88let localdt = self.naive_local().and_time(time);
89self.timezone().from_local_datetime(&localdt).single()
90 }
9192/// Makes a new `DateTime` from the current date, hour, minute and second.
93 /// The offset in the current date is preserved.
94 ///
95 /// Panics on invalid hour, minute and/or second.
96#[deprecated(since = "0.4.23", note = "Use and_hms_opt() instead")]
97 #[inline]
98 #[must_use]
99pub fn and_hms(&self, hour: u32, min: u32, sec: u32) -> DateTime<Tz> {
100self.and_hms_opt(hour, min, sec).expect("invalid time")
101 }
102103/// Makes a new `DateTime` from the current date, hour, minute and second.
104 /// The offset in the current date is preserved.
105 ///
106 /// Returns `None` on invalid hour, minute and/or second.
107#[inline]
108 #[must_use]
109pub fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Option<DateTime<Tz>> {
110NaiveTime::from_hms_opt(hour, min, sec).and_then(|time| self.and_time(time))
111 }
112113/// Makes a new `DateTime` from the current date, hour, minute, second and millisecond.
114 /// The millisecond part can exceed 1,000 in order to represent the leap second.
115 /// The offset in the current date is preserved.
116 ///
117 /// Panics on invalid hour, minute, second and/or millisecond.
118#[deprecated(since = "0.4.23", note = "Use and_hms_milli_opt() instead")]
119 #[inline]
120 #[must_use]
121pub fn and_hms_milli(&self, hour: u32, min: u32, sec: u32, milli: u32) -> DateTime<Tz> {
122self.and_hms_milli_opt(hour, min, sec, milli).expect("invalid time")
123 }
124125/// Makes a new `DateTime` from the current date, hour, minute, second and millisecond.
126 /// The millisecond part can exceed 1,000 in order to represent the leap second.
127 /// The offset in the current date is preserved.
128 ///
129 /// Returns `None` on invalid hour, minute, second and/or millisecond.
130#[inline]
131 #[must_use]
132pub fn and_hms_milli_opt(
133&self,
134 hour: u32,
135 min: u32,
136 sec: u32,
137 milli: u32,
138 ) -> Option<DateTime<Tz>> {
139NaiveTime::from_hms_milli_opt(hour, min, sec, milli).and_then(|time| self.and_time(time))
140 }
141142/// Makes a new `DateTime` from the current date, hour, minute, second and microsecond.
143 /// The microsecond part can exceed 1,000,000 in order to represent the leap second.
144 /// The offset in the current date is preserved.
145 ///
146 /// Panics on invalid hour, minute, second and/or microsecond.
147#[deprecated(since = "0.4.23", note = "Use and_hms_micro_opt() instead")]
148 #[inline]
149 #[must_use]
150pub fn and_hms_micro(&self, hour: u32, min: u32, sec: u32, micro: u32) -> DateTime<Tz> {
151self.and_hms_micro_opt(hour, min, sec, micro).expect("invalid time")
152 }
153154/// Makes a new `DateTime` from the current date, hour, minute, second and microsecond.
155 /// The microsecond part can exceed 1,000,000 in order to represent the leap second.
156 /// The offset in the current date is preserved.
157 ///
158 /// Returns `None` on invalid hour, minute, second and/or microsecond.
159#[inline]
160 #[must_use]
161pub fn and_hms_micro_opt(
162&self,
163 hour: u32,
164 min: u32,
165 sec: u32,
166 micro: u32,
167 ) -> Option<DateTime<Tz>> {
168NaiveTime::from_hms_micro_opt(hour, min, sec, micro).and_then(|time| self.and_time(time))
169 }
170171/// Makes a new `DateTime` from the current date, hour, minute, second and nanosecond.
172 /// The nanosecond part can exceed 1,000,000,000 in order to represent the leap second.
173 /// The offset in the current date is preserved.
174 ///
175 /// Panics on invalid hour, minute, second and/or nanosecond.
176#[deprecated(since = "0.4.23", note = "Use and_hms_nano_opt() instead")]
177 #[inline]
178 #[must_use]
179pub fn and_hms_nano(&self, hour: u32, min: u32, sec: u32, nano: u32) -> DateTime<Tz> {
180self.and_hms_nano_opt(hour, min, sec, nano).expect("invalid time")
181 }
182183/// Makes a new `DateTime` from the current date, hour, minute, second and nanosecond.
184 /// The nanosecond part can exceed 1,000,000,000 in order to represent the leap second.
185 /// The offset in the current date is preserved.
186 ///
187 /// Returns `None` on invalid hour, minute, second and/or nanosecond.
188#[inline]
189 #[must_use]
190pub fn and_hms_nano_opt(
191&self,
192 hour: u32,
193 min: u32,
194 sec: u32,
195 nano: u32,
196 ) -> Option<DateTime<Tz>> {
197NaiveTime::from_hms_nano_opt(hour, min, sec, nano).and_then(|time| self.and_time(time))
198 }
199200/// Makes a new `Date` for the next date.
201 ///
202 /// Panics when `self` is the last representable date.
203#[deprecated(since = "0.4.23", note = "Use succ_opt() instead")]
204 #[inline]
205 #[must_use]
206pub fn succ(&self) -> Date<Tz> {
207self.succ_opt().expect("out of bound")
208 }
209210/// Makes a new `Date` for the next date.
211 ///
212 /// Returns `None` when `self` is the last representable date.
213#[inline]
214 #[must_use]
215pub fn succ_opt(&self) -> Option<Date<Tz>> {
216self.date.succ_opt().map(|date| Date::from_utc(date, self.offset.clone()))
217 }
218219/// Makes a new `Date` for the prior date.
220 ///
221 /// Panics when `self` is the first representable date.
222#[deprecated(since = "0.4.23", note = "Use pred_opt() instead")]
223 #[inline]
224 #[must_use]
225pub fn pred(&self) -> Date<Tz> {
226self.pred_opt().expect("out of bound")
227 }
228229/// Makes a new `Date` for the prior date.
230 ///
231 /// Returns `None` when `self` is the first representable date.
232#[inline]
233 #[must_use]
234pub fn pred_opt(&self) -> Option<Date<Tz>> {
235self.date.pred_opt().map(|date| Date::from_utc(date, self.offset.clone()))
236 }
237238/// Retrieves an associated offset from UTC.
239#[inline]
240 #[must_use]
241pub fn offset(&self) -> &Tz::Offset {
242&self.offset
243 }
244245/// Retrieves an associated time zone.
246#[inline]
247 #[must_use]
248pub fn timezone(&self) -> Tz {
249 TimeZone::from_offset(&self.offset)
250 }
251252/// Changes the associated time zone.
253 /// This does not change the actual `Date` (but will change the string representation).
254#[inline]
255 #[must_use]
256pub fn with_timezone<Tz2: TimeZone>(&self, tz: &Tz2) -> Date<Tz2> {
257tz.from_utc_date(&self.date)
258 }
259260/// Adds given `TimeDelta` to the current date.
261 ///
262 /// Returns `None` when it will result in overflow.
263#[inline]
264 #[must_use]
265pub fn checked_add_signed(self, rhs: TimeDelta) -> Option<Date<Tz>> {
266let date = self.date.checked_add_signed(rhs)?;
267Some(Date { date, offset: self.offset })
268 }
269270/// Subtracts given `TimeDelta` from the current date.
271 ///
272 /// Returns `None` when it will result in overflow.
273#[inline]
274 #[must_use]
275pub fn checked_sub_signed(self, rhs: TimeDelta) -> Option<Date<Tz>> {
276let date = self.date.checked_sub_signed(rhs)?;
277Some(Date { date, offset: self.offset })
278 }
279280/// Subtracts another `Date` from the current date.
281 /// Returns a `TimeDelta` of integral numbers.
282 ///
283 /// This does not overflow or underflow at all,
284 /// as all possible output fits in the range of `TimeDelta`.
285#[inline]
286 #[must_use]
287pub fn signed_duration_since<Tz2: TimeZone>(self, rhs: Date<Tz2>) -> TimeDelta {
288self.date.signed_duration_since(rhs.date)
289 }
290291/// Returns a view to the naive UTC date.
292#[inline]
293 #[must_use]
294pub fn naive_utc(&self) -> NaiveDate {
295self.date
296 }
297298/// Returns a view to the naive local date.
299 ///
300 /// This is technically the same as [`naive_utc`](#method.naive_utc)
301 /// because the offset is restricted to never exceed one day,
302 /// but provided for the consistency.
303#[inline]
304 #[must_use]
305pub fn naive_local(&self) -> NaiveDate {
306self.date
307 }
308309/// Returns the number of whole years from the given `base` until `self`.
310#[must_use]
311pub fn years_since(&self, base: Self) -> Option<u32> {
312self.date.years_since(base.date)
313 }
314315/// The minimum possible `Date`.
316pub const MIN_UTC: Date<Utc> = Date { date: NaiveDate::MIN, offset: Utc };
317/// The maximum possible `Date`.
318pub const MAX_UTC: Date<Utc> = Date { date: NaiveDate::MAX, offset: Utc };
319}
320321/// Maps the local date to other date with given conversion function.
322fn map_local<Tz: TimeZone, F>(d: &Date<Tz>, mut f: F) -> Option<Date<Tz>>
323where
324F: FnMut(NaiveDate) -> Option<NaiveDate>,
325{
326f(d.naive_local()).and_then(|date| d.timezone().from_local_date(&date).single())
327}
328329impl<Tz: TimeZone> Date<Tz>
330where
331Tz::Offset: fmt::Display,
332{
333/// Formats the date with the specified formatting items.
334#[cfg(feature = "alloc")]
335 #[inline]
336 #[must_use]
337pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
338where
339I: Iterator<Item = B> + Clone,
340 B: Borrow<Item<'a>>,
341 {
342DelayedFormat::new_with_offset(Some(self.naive_local()), None, &self.offset, items)
343 }
344345/// Formats the date with the specified format string.
346 /// See the [`crate::format::strftime`] module
347 /// on the supported escape sequences.
348#[cfg(feature = "alloc")]
349 #[inline]
350 #[must_use]
351pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
352self.format_with_items(StrftimeItems::new(fmt))
353 }
354355/// Formats the date with the specified formatting items and locale.
356#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
357 #[inline]
358 #[must_use]
359pub fn format_localized_with_items<'a, I, B>(
360&self,
361 items: I,
362 locale: Locale,
363 ) -> DelayedFormat<I>
364where
365I: Iterator<Item = B> + Clone,
366 B: Borrow<Item<'a>>,
367 {
368 DelayedFormat::new_with_offset_and_locale(
369Some(self.naive_local()),
370None,
371&self.offset,
372 items,
373 locale,
374 )
375 }
376377/// Formats the date with the specified format string and locale.
378 /// See the [`crate::format::strftime`] module
379 /// on the supported escape sequences.
380#[cfg(all(feature = "unstable-locales", feature = "alloc"))]
381 #[inline]
382 #[must_use]
383pub fn format_localized<'a>(
384&self,
385 fmt: &'a str,
386 locale: Locale,
387 ) -> DelayedFormat<StrftimeItems<'a>> {
388self.format_localized_with_items(StrftimeItems::new_with_locale(fmt, locale), locale)
389 }
390}
391392impl<Tz: TimeZone> Datelikefor Date<Tz> {
393#[inline]
394fn year(&self) -> i32 {
395self.naive_local().year()
396 }
397#[inline]
398fn month(&self) -> u32 {
399self.naive_local().month()
400 }
401#[inline]
402fn month0(&self) -> u32 {
403self.naive_local().month0()
404 }
405#[inline]
406fn day(&self) -> u32 {
407self.naive_local().day()
408 }
409#[inline]
410fn day0(&self) -> u32 {
411self.naive_local().day0()
412 }
413#[inline]
414fn ordinal(&self) -> u32 {
415self.naive_local().ordinal()
416 }
417#[inline]
418fn ordinal0(&self) -> u32 {
419self.naive_local().ordinal0()
420 }
421#[inline]
422fn weekday(&self) -> Weekday {
423self.naive_local().weekday()
424 }
425#[inline]
426fn iso_week(&self) -> IsoWeek {
427self.naive_local().iso_week()
428 }
429430#[inline]
431fn with_year(&self, year: i32) -> Option<Date<Tz>> {
432map_local(self, |date| date.with_year(year))
433 }
434435#[inline]
436fn with_month(&self, month: u32) -> Option<Date<Tz>> {
437map_local(self, |date| date.with_month(month))
438 }
439440#[inline]
441fn with_month0(&self, month0: u32) -> Option<Date<Tz>> {
442map_local(self, |date| date.with_month0(month0))
443 }
444445#[inline]
446fn with_day(&self, day: u32) -> Option<Date<Tz>> {
447map_local(self, |date| date.with_day(day))
448 }
449450#[inline]
451fn with_day0(&self, day0: u32) -> Option<Date<Tz>> {
452map_local(self, |date| date.with_day0(day0))
453 }
454455#[inline]
456fn with_ordinal(&self, ordinal: u32) -> Option<Date<Tz>> {
457map_local(self, |date| date.with_ordinal(ordinal))
458 }
459460#[inline]
461fn with_ordinal0(&self, ordinal0: u32) -> Option<Date<Tz>> {
462map_local(self, |date| date.with_ordinal0(ordinal0))
463 }
464}
465466// we need them as automatic impls cannot handle associated types
467impl<Tz: TimeZone> Copyfor Date<Tz> where <Tz as TimeZone>::Offset: Copy {}
468unsafe impl<Tz: TimeZone> Sendfor Date<Tz> where <Tz as TimeZone>::Offset: Send {}
469470impl<Tz: TimeZone, Tz2: TimeZone> PartialEq<Date<Tz2>> for Date<Tz> {
471fn eq(&self, other: &Date<Tz2>) -> bool {
472self.date == other.date
473 }
474}
475476impl<Tz: TimeZone> Eqfor Date<Tz> {}
477478impl<Tz: TimeZone> PartialOrdfor Date<Tz> {
479fn partial_cmp(&self, other: &Date<Tz>) -> Option<Ordering> {
480Some(self.cmp(other))
481 }
482}
483484impl<Tz: TimeZone> Ordfor Date<Tz> {
485fn cmp(&self, other: &Date<Tz>) -> Ordering {
486self.date.cmp(&other.date)
487 }
488}
489490impl<Tz: TimeZone> hash::Hashfor Date<Tz> {
491fn hash<H: hash::Hasher>(&self, state: &mut H) {
492self.date.hash(state)
493 }
494}
495496impl<Tz: TimeZone> Add<TimeDelta> for Date<Tz> {
497type Output = Date<Tz>;
498499#[inline]
500fn add(self, rhs: TimeDelta) -> Date<Tz> {
501self.checked_add_signed(rhs).expect("`Date + TimeDelta` overflowed")
502 }
503}
504505impl<Tz: TimeZone> AddAssign<TimeDelta> for Date<Tz> {
506#[inline]
507fn add_assign(&mut self, rhs: TimeDelta) {
508self.date = self.date.checked_add_signed(rhs).expect("`Date + TimeDelta` overflowed");
509 }
510}
511512impl<Tz: TimeZone> Sub<TimeDelta> for Date<Tz> {
513type Output = Date<Tz>;
514515#[inline]
516fn sub(self, rhs: TimeDelta) -> Date<Tz> {
517self.checked_sub_signed(rhs).expect("`Date - TimeDelta` overflowed")
518 }
519}
520521impl<Tz: TimeZone> SubAssign<TimeDelta> for Date<Tz> {
522#[inline]
523fn sub_assign(&mut self, rhs: TimeDelta) {
524self.date = self.date.checked_sub_signed(rhs).expect("`Date - TimeDelta` overflowed");
525 }
526}
527528impl<Tz: TimeZone> Sub<Date<Tz>> for Date<Tz> {
529type Output = TimeDelta;
530531#[inline]
532fn sub(self, rhs: Date<Tz>) -> TimeDelta {
533self.signed_duration_since(rhs)
534 }
535}
536537impl<Tz: TimeZone> fmt::Debugfor Date<Tz> {
538fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
539self.naive_local().fmt(f)?;
540self.offset.fmt(f)
541 }
542}
543544impl<Tz: TimeZone> fmt::Displayfor Date<Tz>
545where
546Tz::Offset: fmt::Display,
547{
548fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
549self.naive_local().fmt(f)?;
550self.offset.fmt(f)
551 }
552}
553554// Note that implementation of Arbitrary cannot be automatically derived for Date<Tz>, due to
555// the nontrivial bound <Tz as TimeZone>::Offset: Arbitrary.
556#[cfg(all(feature = "arbitrary", feature = "std"))]
557impl<'a, Tz> arbitrary::Arbitrary<'a> for Date<Tz>
558where
559Tz: TimeZone,
560 <Tz as TimeZone>::Offset: arbitrary::Arbitrary<'a>,
561{
562fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Date<Tz>> {
563let date = NaiveDate::arbitrary(u)?;
564let offset = <Tz as TimeZone>::Offset::arbitrary(u)?;
565Ok(Date::from_utc(date, offset))
566 }
567}
568569#[cfg(test)]
570mod tests {
571use super::Date;
572573use crate::{FixedOffset, NaiveDate, TimeDelta, Utc};
574575#[cfg(feature = "clock")]
576use crate::offset::{Local, TimeZone};
577578#[test]
579 #[cfg(feature = "clock")]
580fn test_years_elapsed() {
581const WEEKS_PER_YEAR: f32 = 52.1775;
582583// This is always at least one year because 1 year = 52.1775 weeks.
584let one_year_ago = Utc::today() - TimeDelta::weeks((WEEKS_PER_YEAR * 1.5).ceil() as i64);
585// A bit more than 2 years.
586let two_year_ago = Utc::today() - TimeDelta::weeks((WEEKS_PER_YEAR * 2.5).ceil() as i64);
587588assert_eq!(Utc::today().years_since(one_year_ago), Some(1));
589assert_eq!(Utc::today().years_since(two_year_ago), Some(2));
590591// If the given DateTime is later than now, the function will always return 0.
592let future = Utc::today() + TimeDelta::weeks(12);
593assert_eq!(Utc::today().years_since(future), None);
594 }
595596#[test]
597fn test_date_add_assign() {
598let naivedate = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap();
599let date = Date::<Utc>::from_utc(naivedate, Utc);
600let mut date_add = date;
601602 date_add += TimeDelta::days(5);
603assert_eq!(date_add, date + TimeDelta::days(5));
604605let timezone = FixedOffset::east_opt(60 * 60).unwrap();
606let date = date.with_timezone(&timezone);
607let date_add = date_add.with_timezone(&timezone);
608609assert_eq!(date_add, date + TimeDelta::days(5));
610611let timezone = FixedOffset::west_opt(2 * 60 * 60).unwrap();
612let date = date.with_timezone(&timezone);
613let date_add = date_add.with_timezone(&timezone);
614615assert_eq!(date_add, date + TimeDelta::days(5));
616 }
617618#[test]
619 #[cfg(feature = "clock")]
620fn test_date_add_assign_local() {
621let naivedate = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap();
622623let date = Local.from_utc_date(&naivedate);
624let mut date_add = date;
625626 date_add += TimeDelta::days(5);
627assert_eq!(date_add, date + TimeDelta::days(5));
628 }
629630#[test]
631fn test_date_sub_assign() {
632let naivedate = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap();
633let date = Date::<Utc>::from_utc(naivedate, Utc);
634let mut date_sub = date;
635636 date_sub -= TimeDelta::days(5);
637assert_eq!(date_sub, date - TimeDelta::days(5));
638639let timezone = FixedOffset::east_opt(60 * 60).unwrap();
640let date = date.with_timezone(&timezone);
641let date_sub = date_sub.with_timezone(&timezone);
642643assert_eq!(date_sub, date - TimeDelta::days(5));
644645let timezone = FixedOffset::west_opt(2 * 60 * 60).unwrap();
646let date = date.with_timezone(&timezone);
647let date_sub = date_sub.with_timezone(&timezone);
648649assert_eq!(date_sub, date - TimeDelta::days(5));
650 }
651652#[test]
653 #[cfg(feature = "clock")]
654fn test_date_sub_assign_local() {
655let naivedate = NaiveDate::from_ymd_opt(2000, 1, 1).unwrap();
656657let date = Local.from_utc_date(&naivedate);
658let mut date_sub = date;
659660 date_sub -= TimeDelta::days(5);
661assert_eq!(date_sub, date - TimeDelta::days(5));
662 }
663}