chrono/datetime/mod.rs
1// This is a part of Chrono.
2// See README.md and LICENSE.txt for details.
3
4//! ISO 8601 date and time with time zone.
5
6#[cfg(all(not(feature = "std"), feature = "alloc"))]
7use alloc::string::String;
8use core::borrow::Borrow;
9use core::cmp::Ordering;
10use core::fmt::Write;
11use core::ops::{Add, AddAssign, Sub, SubAssign};
12use core::time::Duration;
13use core::{fmt, hash, str};
14#[cfg(feature = "std")]
15use std::time::{SystemTime, UNIX_EPOCH};
16
17use crate::duration::Duration as OldDuration;
18#[cfg(feature = "unstable-locales")]
19use crate::format::Locale;
20use crate::format::{
21 parse, parse_and_remainder, parse_rfc3339, Fixed, Item, ParseError, ParseResult, Parsed,
22 StrftimeItems, TOO_LONG,
23};
24#[cfg(any(feature = "alloc", feature = "std"))]
25use crate::format::{write_rfc3339, DelayedFormat};
26use crate::naive::{Days, IsoWeek, NaiveDate, NaiveDateTime, NaiveTime};
27#[cfg(feature = "clock")]
28use crate::offset::Local;
29use crate::offset::{FixedOffset, Offset, TimeZone, Utc};
30#[allow(deprecated)]
31use crate::Date;
32use crate::{Datelike, Months, Timelike, Weekday};
33
34#[cfg(feature = "rkyv")]
35use rkyv::{Archive, Deserialize, Serialize};
36
37#[cfg(feature = "rustc-serialize")]
38pub(super) mod rustc_serialize;
39
40/// documented at re-export site
41#[cfg(feature = "serde")]
42pub(super) mod serde;
43
44#[cfg(test)]
45mod tests;
46
47/// Specific formatting options for seconds. This may be extended in the
48/// future, so exhaustive matching in external code is not recommended.
49///
50/// See the `TimeZone::to_rfc3339_opts` function for usage.
51#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
52#[allow(clippy::manual_non_exhaustive)]
53pub enum SecondsFormat {
54 /// Format whole seconds only, with no decimal point nor subseconds.
55 Secs,
56
57 /// Use fixed 3 subsecond digits. This corresponds to
58 /// [Fixed::Nanosecond3](format/enum.Fixed.html#variant.Nanosecond3).
59 Millis,
60
61 /// Use fixed 6 subsecond digits. This corresponds to
62 /// [Fixed::Nanosecond6](format/enum.Fixed.html#variant.Nanosecond6).
63 Micros,
64
65 /// Use fixed 9 subsecond digits. This corresponds to
66 /// [Fixed::Nanosecond9](format/enum.Fixed.html#variant.Nanosecond9).
67 Nanos,
68
69 /// Automatically select one of `Secs`, `Millis`, `Micros`, or `Nanos` to
70 /// display all available non-zero sub-second digits. This corresponds to
71 /// [Fixed::Nanosecond](format/enum.Fixed.html#variant.Nanosecond).
72 AutoSi,
73
74 // Do not match against this.
75 #[doc(hidden)]
76 __NonExhaustive,
77}
78
79/// ISO 8601 combined date and time with time zone.
80///
81/// There are some constructors implemented here (the `from_*` methods), but
82/// the general-purpose constructors are all via the methods on the
83/// [`TimeZone`](./offset/trait.TimeZone.html) implementations.
84#[derive(Clone)]
85#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
86pub struct DateTime<Tz: TimeZone> {
87 datetime: NaiveDateTime,
88 offset: Tz::Offset,
89}
90
91/// The minimum possible `DateTime<Utc>`.
92#[deprecated(since = "0.4.20", note = "Use DateTime::MIN_UTC instead")]
93pub const MIN_DATETIME: DateTime<Utc> = DateTime::<Utc>::MIN_UTC;
94/// The maximum possible `DateTime<Utc>`.
95#[deprecated(since = "0.4.20", note = "Use DateTime::MAX_UTC instead")]
96pub const MAX_DATETIME: DateTime<Utc> = DateTime::<Utc>::MAX_UTC;
97
98impl<Tz: TimeZone> DateTime<Tz> {
99 /// Makes a new `DateTime` from its components: a `NaiveDateTime` in UTC and an `Offset`.
100 ///
101 /// This is a low-level method, intended for use cases such as deserializing a `DateTime` or
102 /// passing it through FFI.
103 ///
104 /// For regular use you will probably want to use a method such as
105 /// [`TimeZone::from_local_datetime`] or [`NaiveDateTime::and_local_timezone`] instead.
106 ///
107 /// # Example
108 ///
109 #[cfg_attr(not(feature = "clock"), doc = "```ignore")]
110 #[cfg_attr(feature = "clock", doc = "```rust")]
111 /// use chrono::{Local, DateTime};
112 ///
113 /// let dt = Local::now();
114 /// // Get components
115 /// let naive_utc = dt.naive_utc();
116 /// let offset = dt.offset().clone();
117 /// // Serialize, pass through FFI... and recreate the `DateTime`:
118 /// let dt_new = DateTime::<Local>::from_naive_utc_and_offset(naive_utc, offset);
119 /// assert_eq!(dt, dt_new);
120 /// ```
121 #[inline]
122 #[must_use]
123 pub fn from_naive_utc_and_offset(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime<Tz> {
124 DateTime { datetime, offset }
125 }
126
127 /// Makes a new `DateTime` from its components: a `NaiveDateTime` in UTC and an `Offset`.
128 #[inline]
129 #[must_use]
130 #[deprecated(
131 since = "0.4.27",
132 note = "Use TimeZone::from_utc_datetime() or DateTime::from_naive_utc_and_offset instead"
133 )]
134 pub fn from_utc(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime<Tz> {
135 DateTime { datetime, offset }
136 }
137
138 /// Makes a new `DateTime` from a `NaiveDateTime` in *local* time and an `Offset`.
139 ///
140 /// # Panics
141 ///
142 /// Panics if the local datetime can't be converted to UTC because it would be out of range.
143 ///
144 /// This can happen if `datetime` is near the end of the representable range of `NaiveDateTime`,
145 /// and the offset from UTC pushes it beyond that.
146 #[inline]
147 #[must_use]
148 #[deprecated(
149 since = "0.4.27",
150 note = "Use TimeZone::from_local_datetime() or NaiveDateTime::and_local_timezone instead"
151 )]
152 pub fn from_local(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime<Tz> {
153 let datetime_utc = datetime - offset.fix();
154
155 DateTime { datetime: datetime_utc, offset }
156 }
157
158 /// Retrieves the date component with an associated timezone.
159 ///
160 /// Unless you are immediately planning on turning this into a `DateTime`
161 /// with the same timezone you should use the [`date_naive`](DateTime::date_naive) method.
162 ///
163 /// [`NaiveDate`] is a more well-defined type, and has more traits implemented on it,
164 /// so should be preferred to [`Date`] any time you truly want to operate on dates.
165 ///
166 /// # Panics
167 ///
168 /// [`DateTime`] internally stores the date and time in UTC with a [`NaiveDateTime`]. This
169 /// method will panic if the offset from UTC would push the local date outside of the
170 /// representable range of a [`Date`].
171 #[inline]
172 #[deprecated(since = "0.4.23", note = "Use `date_naive()` instead")]
173 #[allow(deprecated)]
174 #[must_use]
175 pub fn date(&self) -> Date<Tz> {
176 Date::from_utc(self.naive_local().date(), self.offset.clone())
177 }
178
179 /// Retrieves the date component.
180 ///
181 /// # Panics
182 ///
183 /// [`DateTime`] internally stores the date and time in UTC with a [`NaiveDateTime`]. This
184 /// method will panic if the offset from UTC would push the local date outside of the
185 /// representable range of a [`NaiveDate`].
186 ///
187 /// # Example
188 ///
189 /// ```
190 /// use chrono::prelude::*;
191 ///
192 /// let date: DateTime<Utc> = Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap();
193 /// let other: DateTime<FixedOffset> = FixedOffset::east_opt(23).unwrap().with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap();
194 /// assert_eq!(date.date_naive(), other.date_naive());
195 /// ```
196 #[inline]
197 #[must_use]
198 pub fn date_naive(&self) -> NaiveDate {
199 let local = self.naive_local();
200 NaiveDate::from_ymd_opt(local.year(), local.month(), local.day()).unwrap()
201 }
202
203 /// Retrieves the time component.
204 #[inline]
205 #[must_use]
206 pub fn time(&self) -> NaiveTime {
207 self.datetime.time() + self.offset.fix()
208 }
209
210 /// Returns the number of non-leap seconds since January 1, 1970 0:00:00 UTC
211 /// (aka "UNIX timestamp").
212 #[inline]
213 #[must_use]
214 pub fn timestamp(&self) -> i64 {
215 self.datetime.timestamp()
216 }
217
218 /// Returns the number of non-leap-milliseconds since January 1, 1970 UTC.
219 ///
220 /// # Example
221 ///
222 /// ```
223 /// use chrono::{Utc, NaiveDate};
224 ///
225 /// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_milli_opt(0, 0, 1, 444).unwrap().and_local_timezone(Utc).unwrap();
226 /// assert_eq!(dt.timestamp_millis(), 1_444);
227 ///
228 /// let dt = NaiveDate::from_ymd_opt(2001, 9, 9).unwrap().and_hms_milli_opt(1, 46, 40, 555).unwrap().and_local_timezone(Utc).unwrap();
229 /// assert_eq!(dt.timestamp_millis(), 1_000_000_000_555);
230 /// ```
231 #[inline]
232 #[must_use]
233 pub fn timestamp_millis(&self) -> i64 {
234 self.datetime.timestamp_millis()
235 }
236
237 /// Returns the number of non-leap-microseconds since January 1, 1970 UTC.
238 ///
239 /// # Example
240 ///
241 /// ```
242 /// use chrono::{Utc, NaiveDate};
243 ///
244 /// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_micro_opt(0, 0, 1, 444).unwrap().and_local_timezone(Utc).unwrap();
245 /// assert_eq!(dt.timestamp_micros(), 1_000_444);
246 ///
247 /// let dt = NaiveDate::from_ymd_opt(2001, 9, 9).unwrap().and_hms_micro_opt(1, 46, 40, 555).unwrap().and_local_timezone(Utc).unwrap();
248 /// assert_eq!(dt.timestamp_micros(), 1_000_000_000_000_555);
249 /// ```
250 #[inline]
251 #[must_use]
252 pub fn timestamp_micros(&self) -> i64 {
253 self.datetime.timestamp_micros()
254 }
255
256 /// Returns the number of non-leap-nanoseconds since January 1, 1970 UTC.
257 ///
258 /// # Panics
259 ///
260 /// An `i64` with nanosecond precision can span a range of ~584 years. This function panics on
261 /// an out of range `DateTime`.
262 ///
263 /// The dates that can be represented as nanoseconds are between 1677-09-21T00:12:44.0 and
264 /// 2262-04-11T23:47:16.854775804.
265 ///
266 /// # Example
267 ///
268 /// ```
269 /// use chrono::{Utc, NaiveDate};
270 ///
271 /// let dt = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap().and_hms_nano_opt(0, 0, 1, 444).unwrap().and_local_timezone(Utc).unwrap();
272 /// assert_eq!(dt.timestamp_nanos(), 1_000_000_444);
273 ///
274 /// let dt = NaiveDate::from_ymd_opt(2001, 9, 9).unwrap().and_hms_nano_opt(1, 46, 40, 555).unwrap().and_local_timezone(Utc).unwrap();
275 /// assert_eq!(dt.timestamp_nanos(), 1_000_000_000_000_000_555);
276 /// ```
277 #[inline]
278 #[must_use]
279 pub fn timestamp_nanos(&self) -> i64 {
280 self.datetime.timestamp_nanos()
281 }
282
283 /// Returns the number of milliseconds since the last second boundary.
284 ///
285 /// In event of a leap second this may exceed 999.
286 #[inline]
287 #[must_use]
288 pub fn timestamp_subsec_millis(&self) -> u32 {
289 self.datetime.timestamp_subsec_millis()
290 }
291
292 /// Returns the number of microseconds since the last second boundary.
293 ///
294 /// In event of a leap second this may exceed 999,999.
295 #[inline]
296 #[must_use]
297 pub fn timestamp_subsec_micros(&self) -> u32 {
298 self.datetime.timestamp_subsec_micros()
299 }
300
301 /// Returns the number of nanoseconds since the last second boundary
302 ///
303 /// In event of a leap second this may exceed 999,999,999.
304 #[inline]
305 #[must_use]
306 pub fn timestamp_subsec_nanos(&self) -> u32 {
307 self.datetime.timestamp_subsec_nanos()
308 }
309
310 /// Retrieves an associated offset from UTC.
311 #[inline]
312 #[must_use]
313 pub fn offset(&self) -> &Tz::Offset {
314 &self.offset
315 }
316
317 /// Retrieves an associated time zone.
318 #[inline]
319 #[must_use]
320 pub fn timezone(&self) -> Tz {
321 TimeZone::from_offset(&self.offset)
322 }
323
324 /// Changes the associated time zone.
325 /// The returned `DateTime` references the same instant of time from the perspective of the
326 /// provided time zone.
327 #[inline]
328 #[must_use]
329 pub fn with_timezone<Tz2: TimeZone>(&self, tz: &Tz2) -> DateTime<Tz2> {
330 tz.from_utc_datetime(&self.datetime)
331 }
332
333 /// Fix the offset from UTC to its current value, dropping the associated timezone information.
334 /// This it useful for converting a generic `DateTime<Tz: Timezone>` to `DateTime<FixedOffset>`.
335 #[inline]
336 #[must_use]
337 pub fn fixed_offset(&self) -> DateTime<FixedOffset> {
338 self.with_timezone(&self.offset().fix())
339 }
340
341 /// Adds given `Duration` to the current date and time.
342 ///
343 /// # Errors
344 ///
345 /// Returns `None` if the resulting date would be out of range.
346 #[inline]
347 #[must_use]
348 pub fn checked_add_signed(self, rhs: OldDuration) -> Option<DateTime<Tz>> {
349 let datetime = self.datetime.checked_add_signed(rhs)?;
350 let tz = self.timezone();
351 Some(tz.from_utc_datetime(&datetime))
352 }
353
354 /// Adds given `Months` to the current date and time.
355 ///
356 /// Uses the last day of the month if the day does not exist in the resulting month.
357 ///
358 /// See [`NaiveDate::checked_add_months`] for more details on behavior.
359 ///
360 /// # Errors
361 ///
362 /// Returns `None` if:
363 /// - The resulting date would be out of range.
364 /// - The local time at the resulting date does not exist or is ambiguous, for example during a
365 /// daylight saving time transition.
366 #[must_use]
367 pub fn checked_add_months(self, rhs: Months) -> Option<DateTime<Tz>> {
368 self.naive_local()
369 .checked_add_months(rhs)?
370 .and_local_timezone(Tz::from_offset(&self.offset))
371 .single()
372 }
373
374 /// Subtracts given `Duration` from the current date and time.
375 ///
376 /// # Errors
377 ///
378 /// Returns `None` if the resulting date would be out of range.
379 #[inline]
380 #[must_use]
381 pub fn checked_sub_signed(self, rhs: OldDuration) -> Option<DateTime<Tz>> {
382 let datetime = self.datetime.checked_sub_signed(rhs)?;
383 let tz = self.timezone();
384 Some(tz.from_utc_datetime(&datetime))
385 }
386
387 /// Subtracts given `Months` from the current date and time.
388 ///
389 /// Uses the last day of the month if the day does not exist in the resulting month.
390 ///
391 /// See [`NaiveDate::checked_sub_months`] for more details on behavior.
392 ///
393 /// # Errors
394 ///
395 /// Returns `None` if:
396 /// - The resulting date would be out of range.
397 /// - The local time at the resulting date does not exist or is ambiguous, for example during a
398 /// daylight saving time transition.
399 #[must_use]
400 pub fn checked_sub_months(self, rhs: Months) -> Option<DateTime<Tz>> {
401 self.naive_local()
402 .checked_sub_months(rhs)?
403 .and_local_timezone(Tz::from_offset(&self.offset))
404 .single()
405 }
406
407 /// Add a duration in [`Days`] to the date part of the `DateTime`.
408 ///
409 /// # Errors
410 ///
411 /// Returns `None` if:
412 /// - The resulting date would be out of range.
413 /// - The local time at the resulting date does not exist or is ambiguous, for example during a
414 /// daylight saving time transition.
415 #[must_use]
416 pub fn checked_add_days(self, days: Days) -> Option<Self> {
417 self.naive_local()
418 .checked_add_days(days)?
419 .and_local_timezone(TimeZone::from_offset(&self.offset))
420 .single()
421 }
422
423 /// Subtract a duration in [`Days`] from the date part of the `DateTime`.
424 ///
425 /// # Errors
426 ///
427 /// Returns `None` if:
428 /// - The resulting date would be out of range.
429 /// - The local time at the resulting date does not exist or is ambiguous, for example during a
430 /// daylight saving time transition.
431 #[must_use]
432 pub fn checked_sub_days(self, days: Days) -> Option<Self> {
433 self.naive_local()
434 .checked_sub_days(days)?
435 .and_local_timezone(TimeZone::from_offset(&self.offset))
436 .single()
437 }
438
439 /// Subtracts another `DateTime` from the current date and time.
440 /// This does not overflow or underflow at all.
441 #[inline]
442 #[must_use]
443 pub fn signed_duration_since<Tz2: TimeZone>(
444 self,
445 rhs: impl Borrow<DateTime<Tz2>>,
446 ) -> OldDuration {
447 self.datetime.signed_duration_since(rhs.borrow().datetime)
448 }
449
450 /// Returns a view to the naive UTC datetime.
451 #[inline]
452 #[must_use]
453 pub fn naive_utc(&self) -> NaiveDateTime {
454 self.datetime
455 }
456
457 /// Returns a view to the naive local datetime.
458 ///
459 /// # Panics
460 ///
461 /// [`DateTime`] internally stores the date and time in UTC with a [`NaiveDateTime`]. This
462 /// method will panic if the offset from UTC would push the local datetime outside of the
463 /// representable range of a [`NaiveDateTime`].
464 #[inline]
465 #[must_use]
466 pub fn naive_local(&self) -> NaiveDateTime {
467 self.datetime + self.offset.fix()
468 }
469
470 /// Retrieve the elapsed years from now to the given [`DateTime`].
471 ///
472 /// # Errors
473 ///
474 /// Returns `None` if `base < self`.
475 #[must_use]
476 pub fn years_since(&self, base: Self) -> Option<u32> {
477 let mut years = self.year() - base.year();
478 let earlier_time =
479 (self.month(), self.day(), self.time()) < (base.month(), base.day(), base.time());
480
481 years -= match earlier_time {
482 true => 1,
483 false => 0,
484 };
485
486 match years >= 0 {
487 true => Some(years as u32),
488 false => None,
489 }
490 }
491
492 /// Returns an RFC 2822 date and time string such as `Tue, 1 Jul 2003 10:52:37 +0200`.
493 ///
494 /// # Panics
495 ///
496 /// Panics if the date can not be represented in this format: the year may not be negative and
497 /// can not have more than 4 digits.
498 #[cfg(any(feature = "alloc", feature = "std"))]
499 #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
500 #[must_use]
501 pub fn to_rfc2822(&self) -> String {
502 let mut result = String::with_capacity(32);
503 crate::format::write_rfc2822(&mut result, self.naive_local(), self.offset.fix())
504 .expect("writing rfc2822 datetime to string should never fail");
505 result
506 }
507
508 /// Returns an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`.
509 #[cfg(any(feature = "alloc", feature = "std"))]
510 #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
511 #[must_use]
512 pub fn to_rfc3339(&self) -> String {
513 // For some reason a string with a capacity less than 32 is ca 20% slower when benchmarking.
514 let mut result = String::with_capacity(32);
515 let naive = self.naive_local();
516 let offset = self.offset.fix();
517 write_rfc3339(&mut result, naive, offset, SecondsFormat::AutoSi, false)
518 .expect("writing rfc3339 datetime to string should never fail");
519 result
520 }
521
522 /// Return an RFC 3339 and ISO 8601 date and time string with subseconds
523 /// formatted as per `SecondsFormat`.
524 ///
525 /// If `use_z` is true and the timezone is UTC (offset 0), uses `Z` as
526 /// per [`Fixed::TimezoneOffsetColonZ`]. If `use_z` is false, uses
527 /// [`Fixed::TimezoneOffsetColon`]
528 ///
529 /// # Examples
530 ///
531 /// ```rust
532 /// # use chrono::{FixedOffset, SecondsFormat, TimeZone, Utc, NaiveDate};
533 /// let dt = NaiveDate::from_ymd_opt(2018, 1, 26).unwrap().and_hms_micro_opt(18, 30, 9, 453_829).unwrap().and_local_timezone(Utc).unwrap();
534 /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, false),
535 /// "2018-01-26T18:30:09.453+00:00");
536 /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, true),
537 /// "2018-01-26T18:30:09.453Z");
538 /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true),
539 /// "2018-01-26T18:30:09Z");
540 ///
541 /// let pst = FixedOffset::east_opt(8 * 60 * 60).unwrap();
542 /// let dt = pst.from_local_datetime(&NaiveDate::from_ymd_opt(2018, 1, 26).unwrap().and_hms_micro_opt(10, 30, 9, 453_829).unwrap()).unwrap();
543 /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true),
544 /// "2018-01-26T10:30:09+08:00");
545 /// ```
546 #[cfg(any(feature = "alloc", feature = "std"))]
547 #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
548 #[must_use]
549 pub fn to_rfc3339_opts(&self, secform: SecondsFormat, use_z: bool) -> String {
550 let mut result = String::with_capacity(38);
551 write_rfc3339(&mut result, self.naive_local(), self.offset.fix(), secform, use_z)
552 .expect("writing rfc3339 datetime to string should never fail");
553 result
554 }
555
556 /// The minimum possible `DateTime<Utc>`.
557 pub const MIN_UTC: DateTime<Utc> = DateTime { datetime: NaiveDateTime::MIN, offset: Utc };
558 /// The maximum possible `DateTime<Utc>`.
559 pub const MAX_UTC: DateTime<Utc> = DateTime { datetime: NaiveDateTime::MAX, offset: Utc };
560}
561
562impl Default for DateTime<Utc> {
563 fn default() -> Self {
564 Utc.from_utc_datetime(&NaiveDateTime::default())
565 }
566}
567
568#[cfg(feature = "clock")]
569#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
570impl Default for DateTime<Local> {
571 fn default() -> Self {
572 Local.from_utc_datetime(&NaiveDateTime::default())
573 }
574}
575
576impl Default for DateTime<FixedOffset> {
577 fn default() -> Self {
578 FixedOffset::west_opt(0).unwrap().from_utc_datetime(&NaiveDateTime::default())
579 }
580}
581
582/// Convert a `DateTime<Utc>` instance into a `DateTime<FixedOffset>` instance.
583impl From<DateTime<Utc>> for DateTime<FixedOffset> {
584 /// Convert this `DateTime<Utc>` instance into a `DateTime<FixedOffset>` instance.
585 ///
586 /// Conversion is done via [`DateTime::with_timezone`]. Note that the converted value returned by
587 /// this will be created with a fixed timezone offset of 0.
588 fn from(src: DateTime<Utc>) -> Self {
589 src.with_timezone(&FixedOffset::east_opt(0).unwrap())
590 }
591}
592
593/// Convert a `DateTime<Utc>` instance into a `DateTime<Local>` instance.
594#[cfg(feature = "clock")]
595#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
596impl From<DateTime<Utc>> for DateTime<Local> {
597 /// Convert this `DateTime<Utc>` instance into a `DateTime<Local>` instance.
598 ///
599 /// Conversion is performed via [`DateTime::with_timezone`], accounting for the difference in timezones.
600 fn from(src: DateTime<Utc>) -> Self {
601 src.with_timezone(&Local)
602 }
603}
604
605/// Convert a `DateTime<FixedOffset>` instance into a `DateTime<Utc>` instance.
606impl From<DateTime<FixedOffset>> for DateTime<Utc> {
607 /// Convert this `DateTime<FixedOffset>` instance into a `DateTime<Utc>` instance.
608 ///
609 /// Conversion is performed via [`DateTime::with_timezone`], accounting for the timezone
610 /// difference.
611 fn from(src: DateTime<FixedOffset>) -> Self {
612 src.with_timezone(&Utc)
613 }
614}
615
616/// Convert a `DateTime<FixedOffset>` instance into a `DateTime<Local>` instance.
617#[cfg(feature = "clock")]
618#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
619impl From<DateTime<FixedOffset>> for DateTime<Local> {
620 /// Convert this `DateTime<FixedOffset>` instance into a `DateTime<Local>` instance.
621 ///
622 /// Conversion is performed via [`DateTime::with_timezone`]. Returns the equivalent value in local
623 /// time.
624 fn from(src: DateTime<FixedOffset>) -> Self {
625 src.with_timezone(&Local)
626 }
627}
628
629/// Convert a `DateTime<Local>` instance into a `DateTime<Utc>` instance.
630#[cfg(feature = "clock")]
631#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
632impl From<DateTime<Local>> for DateTime<Utc> {
633 /// Convert this `DateTime<Local>` instance into a `DateTime<Utc>` instance.
634 ///
635 /// Conversion is performed via [`DateTime::with_timezone`], accounting for the difference in
636 /// timezones.
637 fn from(src: DateTime<Local>) -> Self {
638 src.with_timezone(&Utc)
639 }
640}
641
642/// Convert a `DateTime<Local>` instance into a `DateTime<FixedOffset>` instance.
643#[cfg(feature = "clock")]
644#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
645impl From<DateTime<Local>> for DateTime<FixedOffset> {
646 /// Convert this `DateTime<Local>` instance into a `DateTime<FixedOffset>` instance.
647 ///
648 /// Conversion is performed via [`DateTime::with_timezone`].
649 fn from(src: DateTime<Local>) -> Self {
650 src.with_timezone(&src.offset().fix())
651 }
652}
653
654/// Maps the local datetime to other datetime with given conversion function.
655fn map_local<Tz: TimeZone, F>(dt: &DateTime<Tz>, mut f: F) -> Option<DateTime<Tz>>
656where
657 F: FnMut(NaiveDateTime) -> Option<NaiveDateTime>,
658{
659 f(dt.naive_local()).and_then(|datetime| dt.timezone().from_local_datetime(&datetime).single())
660}
661
662impl DateTime<FixedOffset> {
663 /// Parses an RFC 2822 date-and-time string into a `DateTime<FixedOffset>` value.
664 ///
665 /// This parses valid RFC 2822 datetime strings (such as `Tue, 1 Jul 2003 10:52:37 +0200`)
666 /// and returns a new [`DateTime`] instance with the parsed timezone as the [`FixedOffset`].
667 ///
668 /// RFC 2822 is the internet message standard that specifies the representation of times in HTTP
669 /// and email headers.
670 ///
671 /// The RFC 2822 standard allows arbitrary intermixed whitespace.
672 /// See [RFC 2822 Appendix A.5]
673 ///
674 /// ```
675 /// # use chrono::{DateTime, FixedOffset, TimeZone};
676 /// assert_eq!(
677 /// DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 GMT").unwrap(),
678 /// FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap()
679 /// );
680 /// ```
681 ///
682 /// [RFC 2822 Appendix A.5]: https://www.rfc-editor.org/rfc/rfc2822#appendix-A.5
683 pub fn parse_from_rfc2822(s: &str) -> ParseResult<DateTime<FixedOffset>> {
684 const ITEMS: &[Item<'static>] = &[Item::Fixed(Fixed::RFC2822)];
685 let mut parsed = Parsed::new();
686 parse(&mut parsed, s, ITEMS.iter())?;
687 parsed.to_datetime()
688 }
689
690 /// Parses an RFC 3339 date-and-time string into a `DateTime<FixedOffset>` value.
691 ///
692 /// Parses all valid RFC 3339 values (as well as the subset of valid ISO 8601 values that are
693 /// also valid RFC 3339 date-and-time values) and returns a new [`DateTime`] with a
694 /// [`FixedOffset`] corresponding to the parsed timezone. While RFC 3339 values come in a wide
695 /// variety of shapes and sizes, `1996-12-19T16:39:57-08:00` is an example of the most commonly
696 /// encountered variety of RFC 3339 formats.
697 ///
698 /// Why isn't this named `parse_from_iso8601`? That's because ISO 8601 allows representing
699 /// values in a wide range of formats, only some of which represent actual date-and-time
700 /// instances (rather than periods, ranges, dates, or times). Some valid ISO 8601 values are
701 /// also simultaneously valid RFC 3339 values, but not all RFC 3339 values are valid ISO 8601
702 /// values (or the other way around).
703 pub fn parse_from_rfc3339(s: &str) -> ParseResult<DateTime<FixedOffset>> {
704 let mut parsed = Parsed::new();
705 let (s, _) = parse_rfc3339(&mut parsed, s)?;
706 if !s.is_empty() {
707 return Err(TOO_LONG);
708 }
709 parsed.to_datetime()
710 }
711
712 /// Parses a string from a user-specified format into a `DateTime<FixedOffset>` value.
713 ///
714 /// Note that this method *requires a timezone* in the input string. See
715 /// [`NaiveDateTime::parse_from_str`](./naive/struct.NaiveDateTime.html#method.parse_from_str)
716 /// for a version that does not require a timezone in the to-be-parsed str. The returned
717 /// [`DateTime`] value will have a [`FixedOffset`] reflecting the parsed timezone.
718 ///
719 /// See the [`format::strftime` module](./format/strftime/index.html) for supported format
720 /// sequences.
721 ///
722 /// # Example
723 ///
724 /// ```rust
725 /// use chrono::{DateTime, FixedOffset, TimeZone, NaiveDate};
726 ///
727 /// let dt = DateTime::parse_from_str(
728 /// "1983 Apr 13 12:09:14.274 +0000", "%Y %b %d %H:%M:%S%.3f %z");
729 /// assert_eq!(dt, Ok(FixedOffset::east_opt(0).unwrap().from_local_datetime(&NaiveDate::from_ymd_opt(1983, 4, 13).unwrap().and_hms_milli_opt(12, 9, 14, 274).unwrap()).unwrap()));
730 /// ```
731 pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult<DateTime<FixedOffset>> {
732 let mut parsed = Parsed::new();
733 parse(&mut parsed, s, StrftimeItems::new(fmt))?;
734 parsed.to_datetime()
735 }
736
737 /// Parses a string from a user-specified format into a `DateTime<FixedOffset>` value, and a
738 /// slice with the remaining portion of the string.
739 ///
740 /// Note that this method *requires a timezone* in the input string. See
741 /// [`NaiveDateTime::parse_and_remainder`] for a version that does not
742 /// require a timezone in `s`. The returned [`DateTime`] value will have a [`FixedOffset`]
743 /// reflecting the parsed timezone.
744 ///
745 /// See the [`format::strftime` module](./format/strftime/index.html) for supported format
746 /// sequences.
747 ///
748 /// Similar to [`parse_from_str`](#method.parse_from_str).
749 ///
750 /// # Example
751 ///
752 /// ```rust
753 /// # use chrono::{DateTime, FixedOffset, TimeZone};
754 /// let (datetime, remainder) = DateTime::parse_and_remainder(
755 /// "2015-02-18 23:16:09 +0200 trailing text", "%Y-%m-%d %H:%M:%S %z").unwrap();
756 /// assert_eq!(
757 /// datetime,
758 /// FixedOffset::east_opt(2*3600).unwrap().with_ymd_and_hms(2015, 2, 18, 23, 16, 9).unwrap()
759 /// );
760 /// assert_eq!(remainder, " trailing text");
761 /// ```
762 pub fn parse_and_remainder<'a>(
763 s: &'a str,
764 fmt: &str,
765 ) -> ParseResult<(DateTime<FixedOffset>, &'a str)> {
766 let mut parsed = Parsed::new();
767 let remainder = parse_and_remainder(&mut parsed, s, StrftimeItems::new(fmt))?;
768 parsed.to_datetime().map(|d| (d, remainder))
769 }
770}
771
772impl<Tz: TimeZone> DateTime<Tz>
773where
774 Tz::Offset: fmt::Display,
775{
776 /// Formats the combined date and time with the specified formatting items.
777 #[cfg(any(feature = "alloc", feature = "std"))]
778 #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
779 #[inline]
780 #[must_use]
781 pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
782 where
783 I: Iterator<Item = B> + Clone,
784 B: Borrow<Item<'a>>,
785 {
786 let local = self.naive_local();
787 DelayedFormat::new_with_offset(Some(local.date()), Some(local.time()), &self.offset, items)
788 }
789
790 /// Formats the combined date and time per the specified format string.
791 ///
792 /// See the [`crate::format::strftime`] module for the supported escape sequences.
793 ///
794 /// # Example
795 /// ```rust
796 /// use chrono::prelude::*;
797 ///
798 /// let date_time: DateTime<Utc> = Utc.with_ymd_and_hms(2017, 04, 02, 12, 50, 32).unwrap();
799 /// let formatted = format!("{}", date_time.format("%d/%m/%Y %H:%M"));
800 /// assert_eq!(formatted, "02/04/2017 12:50");
801 /// ```
802 #[cfg(any(feature = "alloc", feature = "std"))]
803 #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))]
804 #[inline]
805 #[must_use]
806 pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
807 self.format_with_items(StrftimeItems::new(fmt))
808 }
809
810 /// Formats the combined date and time with the specified formatting items and locale.
811 #[cfg(feature = "unstable-locales")]
812 #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
813 #[inline]
814 #[must_use]
815 pub fn format_localized_with_items<'a, I, B>(
816 &self,
817 items: I,
818 locale: Locale,
819 ) -> DelayedFormat<I>
820 where
821 I: Iterator<Item = B> + Clone,
822 B: Borrow<Item<'a>>,
823 {
824 let local = self.naive_local();
825 DelayedFormat::new_with_offset_and_locale(
826 Some(local.date()),
827 Some(local.time()),
828 &self.offset,
829 items,
830 locale,
831 )
832 }
833
834 /// Formats the combined date and time per the specified format string and
835 /// locale.
836 ///
837 /// See the [`crate::format::strftime`] module on the supported escape
838 /// sequences.
839 #[cfg(feature = "unstable-locales")]
840 #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))]
841 #[inline]
842 #[must_use]
843 pub fn format_localized<'a>(
844 &self,
845 fmt: &'a str,
846 locale: Locale,
847 ) -> DelayedFormat<StrftimeItems<'a>> {
848 self.format_localized_with_items(StrftimeItems::new_with_locale(fmt, locale), locale)
849 }
850}
851
852impl<Tz: TimeZone> Datelike for DateTime<Tz> {
853 #[inline]
854 fn year(&self) -> i32 {
855 self.naive_local().year()
856 }
857 #[inline]
858 fn month(&self) -> u32 {
859 self.naive_local().month()
860 }
861 #[inline]
862 fn month0(&self) -> u32 {
863 self.naive_local().month0()
864 }
865 #[inline]
866 fn day(&self) -> u32 {
867 self.naive_local().day()
868 }
869 #[inline]
870 fn day0(&self) -> u32 {
871 self.naive_local().day0()
872 }
873 #[inline]
874 fn ordinal(&self) -> u32 {
875 self.naive_local().ordinal()
876 }
877 #[inline]
878 fn ordinal0(&self) -> u32 {
879 self.naive_local().ordinal0()
880 }
881 #[inline]
882 fn weekday(&self) -> Weekday {
883 self.naive_local().weekday()
884 }
885 #[inline]
886 fn iso_week(&self) -> IsoWeek {
887 self.naive_local().iso_week()
888 }
889
890 #[inline]
891 /// Makes a new `DateTime` with the year number changed, while keeping the same month and day.
892 ///
893 /// See also the [`NaiveDate::with_year`] method.
894 ///
895 /// # Errors
896 ///
897 /// Returns `None` if:
898 /// - The resulting date does not exist.
899 /// - When the `NaiveDateTime` would be out of range.
900 /// - The local time at the resulting date does not exist or is ambiguous, for example during a
901 /// daylight saving time transition.
902 fn with_year(&self, year: i32) -> Option<DateTime<Tz>> {
903 map_local(self, |datetime| datetime.with_year(year))
904 }
905
906 /// Makes a new `DateTime` with the month number (starting from 1) changed.
907 ///
908 /// See also the [`NaiveDate::with_month`] method.
909 ///
910 /// # Errors
911 ///
912 /// Returns `None` if:
913 /// - The resulting date does not exist.
914 /// - The value for `month` is invalid.
915 /// - The local time at the resulting date does not exist or is ambiguous, for example during a
916 /// daylight saving time transition.
917 #[inline]
918 fn with_month(&self, month: u32) -> Option<DateTime<Tz>> {
919 map_local(self, |datetime| datetime.with_month(month))
920 }
921
922 /// Makes a new `DateTime` with the month number (starting from 0) changed.
923 ///
924 /// See also the [`NaiveDate::with_month0`] method.
925 ///
926 /// # Errors
927 ///
928 /// Returns `None` if:
929 /// - The resulting date does not exist.
930 /// - The value for `month0` is invalid.
931 /// - The local time at the resulting date does not exist or is ambiguous, for example during a
932 /// daylight saving time transition.
933 #[inline]
934 fn with_month0(&self, month0: u32) -> Option<DateTime<Tz>> {
935 map_local(self, |datetime| datetime.with_month0(month0))
936 }
937
938 /// Makes a new `DateTime` with the month number (starting from 0) changed.
939 ///
940 /// See also the [`NaiveDate::with_day`] method.
941 ///
942 /// # Errors
943 ///
944 /// Returns `None` if:
945 /// - The resulting date does not exist.
946 /// - The value for `day` is invalid.
947 /// - The local time at the resulting date does not exist or is ambiguous, for example during a
948 /// daylight saving time transition.
949 #[inline]
950 fn with_day(&self, day: u32) -> Option<DateTime<Tz>> {
951 map_local(self, |datetime| datetime.with_day(day))
952 }
953
954 /// Makes a new `DateTime` with the month number (starting from 0) changed.
955 ///
956 /// See also the [`NaiveDate::with_day0`] method.
957 ///
958 /// # Errors
959 ///
960 /// Returns `None` if:
961 /// - The resulting date does not exist.
962 /// - The value for `day0` is invalid.
963 /// - The local time at the resulting date does not exist or is ambiguous, for example during a
964 /// daylight saving time transition.
965 #[inline]
966 fn with_day0(&self, day0: u32) -> Option<DateTime<Tz>> {
967 map_local(self, |datetime| datetime.with_day0(day0))
968 }
969
970 /// Makes a new `DateTime` with the month number (starting from 0) changed.
971 ///
972 /// See also the [`NaiveDate::with_ordinal`] method.
973 ///
974 /// # Errors
975 ///
976 /// Returns `None` if:
977 /// - The resulting date does not exist.
978 /// - The value for `ordinal` is invalid.
979 /// - The local time at the resulting date does not exist or is ambiguous, for example during a
980 /// daylight saving time transition.
981 #[inline]
982 fn with_ordinal(&self, ordinal: u32) -> Option<DateTime<Tz>> {
983 map_local(self, |datetime| datetime.with_ordinal(ordinal))
984 }
985
986 /// Makes a new `DateTime` with the month number (starting from 0) changed.
987 ///
988 /// See also the [`NaiveDate::with_ordinal0`] method.
989 ///
990 /// # Errors
991 ///
992 /// Returns `None` if:
993 /// - The resulting date does not exist.
994 /// - The value for `ordinal0` is invalid.
995 /// - The local time at the resulting date does not exist or is ambiguous, for example during a
996 /// daylight saving time transition.
997 #[inline]
998 fn with_ordinal0(&self, ordinal0: u32) -> Option<DateTime<Tz>> {
999 map_local(self, |datetime| datetime.with_ordinal0(ordinal0))
1000 }
1001}
1002
1003impl<Tz: TimeZone> Timelike for DateTime<Tz> {
1004 #[inline]
1005 fn hour(&self) -> u32 {
1006 self.naive_local().hour()
1007 }
1008 #[inline]
1009 fn minute(&self) -> u32 {
1010 self.naive_local().minute()
1011 }
1012 #[inline]
1013 fn second(&self) -> u32 {
1014 self.naive_local().second()
1015 }
1016 #[inline]
1017 fn nanosecond(&self) -> u32 {
1018 self.naive_local().nanosecond()
1019 }
1020
1021 /// Makes a new `DateTime` with the hour number changed.
1022 ///
1023 /// See also the [`NaiveTime::with_hour`] method.
1024 ///
1025 /// # Errors
1026 ///
1027 /// Returns `None` if:
1028 /// - The value for `hour` is invalid.
1029 /// - The local time at the resulting date does not exist or is ambiguous, for example during a
1030 /// daylight saving time transition.
1031 #[inline]
1032 fn with_hour(&self, hour: u32) -> Option<DateTime<Tz>> {
1033 map_local(self, |datetime| datetime.with_hour(hour))
1034 }
1035
1036 /// Makes a new `DateTime` with the minute number changed.
1037 ///
1038 /// See also the [`NaiveTime::with_minute`] method.
1039 ///
1040 /// # Errors
1041 ///
1042 /// - The value for `minute` is invalid.
1043 /// - The local time at the resulting date does not exist or is ambiguous, for example during a
1044 /// daylight saving time transition.
1045 #[inline]
1046 fn with_minute(&self, min: u32) -> Option<DateTime<Tz>> {
1047 map_local(self, |datetime| datetime.with_minute(min))
1048 }
1049
1050 /// Makes a new `DateTime` with the second number changed.
1051 ///
1052 /// As with the [`second`](#method.second) method,
1053 /// the input range is restricted to 0 through 59.
1054 ///
1055 /// See also the [`NaiveTime::with_second`] method.
1056 ///
1057 /// # Errors
1058 ///
1059 /// Returns `None` if:
1060 /// - The value for `second` is invalid.
1061 /// - The local time at the resulting date does not exist or is ambiguous, for example during a
1062 /// daylight saving time transition.
1063 #[inline]
1064 fn with_second(&self, sec: u32) -> Option<DateTime<Tz>> {
1065 map_local(self, |datetime| datetime.with_second(sec))
1066 }
1067
1068 /// Makes a new `DateTime` with nanoseconds since the whole non-leap second changed.
1069 ///
1070 /// Returns `None` when the resulting `NaiveDateTime` would be invalid.
1071 /// As with the [`NaiveDateTime::nanosecond`] method,
1072 /// the input range can exceed 1,000,000,000 for leap seconds.
1073 ///
1074 /// See also the [`NaiveTime::with_nanosecond`] method.
1075 ///
1076 /// # Errors
1077 ///
1078 /// Returns `None` if `nanosecond >= 2,000,000,000`.
1079 #[inline]
1080 fn with_nanosecond(&self, nano: u32) -> Option<DateTime<Tz>> {
1081 map_local(self, |datetime| datetime.with_nanosecond(nano))
1082 }
1083}
1084
1085// we need them as automatic impls cannot handle associated types
1086impl<Tz: TimeZone> Copy for DateTime<Tz> where <Tz as TimeZone>::Offset: Copy {}
1087unsafe impl<Tz: TimeZone> Send for DateTime<Tz> where <Tz as TimeZone>::Offset: Send {}
1088
1089impl<Tz: TimeZone, Tz2: TimeZone> PartialEq<DateTime<Tz2>> for DateTime<Tz> {
1090 fn eq(&self, other: &DateTime<Tz2>) -> bool {
1091 self.datetime == other.datetime
1092 }
1093}
1094
1095impl<Tz: TimeZone> Eq for DateTime<Tz> {}
1096
1097impl<Tz: TimeZone, Tz2: TimeZone> PartialOrd<DateTime<Tz2>> for DateTime<Tz> {
1098 /// Compare two DateTimes based on their true time, ignoring time zones
1099 ///
1100 /// # Example
1101 ///
1102 /// ```
1103 /// use chrono::prelude::*;
1104 ///
1105 /// let earlier = Utc.with_ymd_and_hms(2015, 5, 15, 2, 0, 0).unwrap().with_timezone(&FixedOffset::west_opt(1 * 3600).unwrap());
1106 /// let later = Utc.with_ymd_and_hms(2015, 5, 15, 3, 0, 0).unwrap().with_timezone(&FixedOffset::west_opt(5 * 3600).unwrap());
1107 ///
1108 /// assert_eq!(earlier.to_string(), "2015-05-15 01:00:00 -01:00");
1109 /// assert_eq!(later.to_string(), "2015-05-14 22:00:00 -05:00");
1110 ///
1111 /// assert!(later > earlier);
1112 /// ```
1113 fn partial_cmp(&self, other: &DateTime<Tz2>) -> Option<Ordering> {
1114 self.datetime.partial_cmp(&other.datetime)
1115 }
1116}
1117
1118impl<Tz: TimeZone> Ord for DateTime<Tz> {
1119 fn cmp(&self, other: &DateTime<Tz>) -> Ordering {
1120 self.datetime.cmp(&other.datetime)
1121 }
1122}
1123
1124impl<Tz: TimeZone> hash::Hash for DateTime<Tz> {
1125 fn hash<H: hash::Hasher>(&self, state: &mut H) {
1126 self.datetime.hash(state)
1127 }
1128}
1129
1130impl<Tz: TimeZone> Add<OldDuration> for DateTime<Tz> {
1131 type Output = DateTime<Tz>;
1132
1133 #[inline]
1134 fn add(self, rhs: OldDuration) -> DateTime<Tz> {
1135 self.checked_add_signed(rhs).expect("`DateTime + Duration` overflowed")
1136 }
1137}
1138
1139impl<Tz: TimeZone> Add<Duration> for DateTime<Tz> {
1140 type Output = DateTime<Tz>;
1141
1142 #[inline]
1143 fn add(self, rhs: Duration) -> DateTime<Tz> {
1144 let rhs = OldDuration::from_std(rhs)
1145 .expect("overflow converting from core::time::Duration to chrono::Duration");
1146 self.checked_add_signed(rhs).expect("`DateTime + Duration` overflowed")
1147 }
1148}
1149
1150impl<Tz: TimeZone> AddAssign<OldDuration> for DateTime<Tz> {
1151 #[inline]
1152 fn add_assign(&mut self, rhs: OldDuration) {
1153 let datetime =
1154 self.datetime.checked_add_signed(rhs).expect("`DateTime + Duration` overflowed");
1155 let tz = self.timezone();
1156 *self = tz.from_utc_datetime(&datetime);
1157 }
1158}
1159
1160impl<Tz: TimeZone> AddAssign<Duration> for DateTime<Tz> {
1161 #[inline]
1162 fn add_assign(&mut self, rhs: Duration) {
1163 let rhs = OldDuration::from_std(rhs)
1164 .expect("overflow converting from core::time::Duration to chrono::Duration");
1165 *self += rhs;
1166 }
1167}
1168
1169impl<Tz: TimeZone> Add<Months> for DateTime<Tz> {
1170 type Output = DateTime<Tz>;
1171
1172 fn add(self, rhs: Months) -> Self::Output {
1173 self.checked_add_months(rhs).unwrap()
1174 }
1175}
1176
1177impl<Tz: TimeZone> Sub<OldDuration> for DateTime<Tz> {
1178 type Output = DateTime<Tz>;
1179
1180 #[inline]
1181 fn sub(self, rhs: OldDuration) -> DateTime<Tz> {
1182 self.checked_sub_signed(rhs).expect("`DateTime - Duration` overflowed")
1183 }
1184}
1185
1186impl<Tz: TimeZone> Sub<Duration> for DateTime<Tz> {
1187 type Output = DateTime<Tz>;
1188
1189 #[inline]
1190 fn sub(self, rhs: Duration) -> DateTime<Tz> {
1191 let rhs = OldDuration::from_std(rhs)
1192 .expect("overflow converting from core::time::Duration to chrono::Duration");
1193 self.checked_sub_signed(rhs).expect("`DateTime - Duration` overflowed")
1194 }
1195}
1196
1197impl<Tz: TimeZone> SubAssign<OldDuration> for DateTime<Tz> {
1198 #[inline]
1199 fn sub_assign(&mut self, rhs: OldDuration) {
1200 let datetime =
1201 self.datetime.checked_sub_signed(rhs).expect("`DateTime - Duration` overflowed");
1202 let tz = self.timezone();
1203 *self = tz.from_utc_datetime(&datetime)
1204 }
1205}
1206
1207impl<Tz: TimeZone> SubAssign<Duration> for DateTime<Tz> {
1208 #[inline]
1209 fn sub_assign(&mut self, rhs: Duration) {
1210 let rhs = OldDuration::from_std(rhs)
1211 .expect("overflow converting from core::time::Duration to chrono::Duration");
1212 *self -= rhs;
1213 }
1214}
1215
1216impl<Tz: TimeZone> Sub<Months> for DateTime<Tz> {
1217 type Output = DateTime<Tz>;
1218
1219 fn sub(self, rhs: Months) -> Self::Output {
1220 self.checked_sub_months(rhs).unwrap()
1221 }
1222}
1223
1224impl<Tz: TimeZone> Sub<DateTime<Tz>> for DateTime<Tz> {
1225 type Output = OldDuration;
1226
1227 #[inline]
1228 fn sub(self, rhs: DateTime<Tz>) -> OldDuration {
1229 self.signed_duration_since(rhs)
1230 }
1231}
1232
1233impl<Tz: TimeZone> Sub<&DateTime<Tz>> for DateTime<Tz> {
1234 type Output = OldDuration;
1235
1236 #[inline]
1237 fn sub(self, rhs: &DateTime<Tz>) -> OldDuration {
1238 self.signed_duration_since(rhs)
1239 }
1240}
1241
1242impl<Tz: TimeZone> Add<Days> for DateTime<Tz> {
1243 type Output = DateTime<Tz>;
1244
1245 fn add(self, days: Days) -> Self::Output {
1246 self.checked_add_days(days).unwrap()
1247 }
1248}
1249
1250impl<Tz: TimeZone> Sub<Days> for DateTime<Tz> {
1251 type Output = DateTime<Tz>;
1252
1253 fn sub(self, days: Days) -> Self::Output {
1254 self.checked_sub_days(days).unwrap()
1255 }
1256}
1257
1258impl<Tz: TimeZone> fmt::Debug for DateTime<Tz> {
1259 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1260 self.naive_local().fmt(f)?;
1261 self.offset.fmt(f)
1262 }
1263}
1264
1265impl<Tz: TimeZone> fmt::Display for DateTime<Tz>
1266where
1267 Tz::Offset: fmt::Display,
1268{
1269 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1270 self.naive_local().fmt(f)?;
1271 f.write_char(' ')?;
1272 self.offset.fmt(f)
1273 }
1274}
1275
1276/// Accepts a relaxed form of RFC3339.
1277/// A space or a 'T' are accepted as the separator between the date and time
1278/// parts.
1279///
1280/// All of these examples are equivalent:
1281/// ```
1282/// # use chrono::{DateTime, Utc};
1283/// "2012-12-12T12:12:12Z".parse::<DateTime<Utc>>()?;
1284/// "2012-12-12 12:12:12Z".parse::<DateTime<Utc>>()?;
1285/// "2012-12-12 12:12:12+0000".parse::<DateTime<Utc>>()?;
1286/// "2012-12-12 12:12:12+00:00".parse::<DateTime<Utc>>()?;
1287/// # Ok::<(), chrono::ParseError>(())
1288/// ```
1289impl str::FromStr for DateTime<Utc> {
1290 type Err = ParseError;
1291
1292 fn from_str(s: &str) -> ParseResult<DateTime<Utc>> {
1293 s.parse::<DateTime<FixedOffset>>().map(|dt| dt.with_timezone(&Utc))
1294 }
1295}
1296
1297/// Accepts a relaxed form of RFC3339.
1298/// A space or a 'T' are accepted as the separator between the date and time
1299/// parts.
1300///
1301/// All of these examples are equivalent:
1302/// ```
1303/// # use chrono::{DateTime, Local};
1304/// "2012-12-12T12:12:12Z".parse::<DateTime<Local>>()?;
1305/// "2012-12-12 12:12:12Z".parse::<DateTime<Local>>()?;
1306/// "2012-12-12 12:12:12+0000".parse::<DateTime<Local>>()?;
1307/// "2012-12-12 12:12:12+00:00".parse::<DateTime<Local>>()?;
1308/// # Ok::<(), chrono::ParseError>(())
1309/// ```
1310#[cfg(feature = "clock")]
1311#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
1312impl str::FromStr for DateTime<Local> {
1313 type Err = ParseError;
1314
1315 fn from_str(s: &str) -> ParseResult<DateTime<Local>> {
1316 s.parse::<DateTime<FixedOffset>>().map(|dt| dt.with_timezone(&Local))
1317 }
1318}
1319
1320#[cfg(feature = "std")]
1321#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
1322impl From<SystemTime> for DateTime<Utc> {
1323 fn from(t: SystemTime) -> DateTime<Utc> {
1324 let (sec, nsec) = match t.duration_since(UNIX_EPOCH) {
1325 Ok(dur) => (dur.as_secs() as i64, dur.subsec_nanos()),
1326 Err(e) => {
1327 // unlikely but should be handled
1328 let dur = e.duration();
1329 let (sec, nsec) = (dur.as_secs() as i64, dur.subsec_nanos());
1330 if nsec == 0 {
1331 (-sec, 0)
1332 } else {
1333 (-sec - 1, 1_000_000_000 - nsec)
1334 }
1335 }
1336 };
1337 Utc.timestamp_opt(sec, nsec).unwrap()
1338 }
1339}
1340
1341#[cfg(feature = "clock")]
1342#[cfg_attr(docsrs, doc(cfg(feature = "clock")))]
1343impl From<SystemTime> for DateTime<Local> {
1344 fn from(t: SystemTime) -> DateTime<Local> {
1345 DateTime::<Utc>::from(t).with_timezone(&Local)
1346 }
1347}
1348
1349#[cfg(feature = "std")]
1350#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
1351impl<Tz: TimeZone> From<DateTime<Tz>> for SystemTime {
1352 fn from(dt: DateTime<Tz>) -> SystemTime {
1353 let sec = dt.timestamp();
1354 let nsec = dt.timestamp_subsec_nanos();
1355 if sec < 0 {
1356 // unlikely but should be handled
1357 UNIX_EPOCH - Duration::new(-sec as u64, 0) + Duration::new(0, nsec)
1358 } else {
1359 UNIX_EPOCH + Duration::new(sec as u64, nsec)
1360 }
1361 }
1362}
1363
1364#[cfg(all(
1365 target_arch = "wasm32",
1366 feature = "wasmbind",
1367 not(any(target_os = "emscripten", target_os = "wasi"))
1368))]
1369#[cfg_attr(
1370 docsrs,
1371 doc(cfg(all(
1372 target_arch = "wasm32",
1373 feature = "wasmbind",
1374 not(any(target_os = "emscripten", target_os = "wasi"))
1375 )))
1376)]
1377impl From<js_sys::Date> for DateTime<Utc> {
1378 fn from(date: js_sys::Date) -> DateTime<Utc> {
1379 DateTime::<Utc>::from(&date)
1380 }
1381}
1382
1383#[cfg(all(
1384 target_arch = "wasm32",
1385 feature = "wasmbind",
1386 not(any(target_os = "emscripten", target_os = "wasi"))
1387))]
1388#[cfg_attr(
1389 docsrs,
1390 doc(cfg(all(
1391 target_arch = "wasm32",
1392 feature = "wasmbind",
1393 not(any(target_os = "emscripten", target_os = "wasi"))
1394 )))
1395)]
1396impl From<&js_sys::Date> for DateTime<Utc> {
1397 fn from(date: &js_sys::Date) -> DateTime<Utc> {
1398 Utc.timestamp_millis_opt(date.get_time() as i64).unwrap()
1399 }
1400}
1401
1402#[cfg(all(
1403 target_arch = "wasm32",
1404 feature = "wasmbind",
1405 not(any(target_os = "emscripten", target_os = "wasi"))
1406))]
1407#[cfg_attr(
1408 docsrs,
1409 doc(cfg(all(
1410 target_arch = "wasm32",
1411 feature = "wasmbind",
1412 not(any(target_os = "emscripten", target_os = "wasi"))
1413 )))
1414)]
1415impl From<DateTime<Utc>> for js_sys::Date {
1416 /// Converts a `DateTime<Utc>` to a JS `Date`. The resulting value may be lossy,
1417 /// any values that have a millisecond timestamp value greater/less than ±8,640,000,000,000,000
1418 /// (April 20, 271821 BCE ~ September 13, 275760 CE) will become invalid dates in JS.
1419 fn from(date: DateTime<Utc>) -> js_sys::Date {
1420 let js_millis = wasm_bindgen::JsValue::from_f64(date.timestamp_millis() as f64);
1421 js_sys::Date::new(&js_millis)
1422 }
1423}
1424
1425// Note that implementation of Arbitrary cannot be simply derived for DateTime<Tz>, due to
1426// the nontrivial bound <Tz as TimeZone>::Offset: Arbitrary.
1427#[cfg(feature = "arbitrary")]
1428impl<'a, Tz> arbitrary::Arbitrary<'a> for DateTime<Tz>
1429where
1430 Tz: TimeZone,
1431 <Tz as TimeZone>::Offset: arbitrary::Arbitrary<'a>,
1432{
1433 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<DateTime<Tz>> {
1434 let datetime = NaiveDateTime::arbitrary(u)?;
1435 let offset = <Tz as TimeZone>::Offset::arbitrary(u)?;
1436 Ok(DateTime::from_utc(datetime, offset))
1437 }
1438}
1439
1440#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
1441fn test_encodable_json<FUtc, FFixed, E>(to_string_utc: FUtc, to_string_fixed: FFixed)
1442where
1443 FUtc: Fn(&DateTime<Utc>) -> Result<String, E>,
1444 FFixed: Fn(&DateTime<FixedOffset>) -> Result<String, E>,
1445 E: ::core::fmt::Debug,
1446{
1447 assert_eq!(
1448 to_string_utc(&Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()).ok(),
1449 Some(r#""2014-07-24T12:34:06Z""#.into())
1450 );
1451
1452 assert_eq!(
1453 to_string_fixed(
1454 &FixedOffset::east_opt(3660).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()
1455 )
1456 .ok(),
1457 Some(r#""2014-07-24T12:34:06+01:01""#.into())
1458 );
1459 assert_eq!(
1460 to_string_fixed(
1461 &FixedOffset::east_opt(3650).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()
1462 )
1463 .ok(),
1464 // An offset with seconds is not allowed by RFC 3339, so we round it to the nearest minute.
1465 // In this case `+01:00:50` becomes `+01:01`
1466 Some(r#""2014-07-24T12:34:06+01:01""#.into())
1467 );
1468}
1469
1470#[cfg(all(test, feature = "clock", any(feature = "rustc-serialize", feature = "serde")))]
1471fn test_decodable_json<FUtc, FFixed, FLocal, E>(
1472 utc_from_str: FUtc,
1473 fixed_from_str: FFixed,
1474 local_from_str: FLocal,
1475) where
1476 FUtc: Fn(&str) -> Result<DateTime<Utc>, E>,
1477 FFixed: Fn(&str) -> Result<DateTime<FixedOffset>, E>,
1478 FLocal: Fn(&str) -> Result<DateTime<Local>, E>,
1479 E: ::core::fmt::Debug,
1480{
1481 // should check against the offset as well (the normal DateTime comparison will ignore them)
1482 fn norm<Tz: TimeZone>(dt: &Option<DateTime<Tz>>) -> Option<(&DateTime<Tz>, &Tz::Offset)> {
1483 dt.as_ref().map(|dt| (dt, dt.offset()))
1484 }
1485
1486 assert_eq!(
1487 norm(&utc_from_str(r#""2014-07-24T12:34:06Z""#).ok()),
1488 norm(&Some(Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()))
1489 );
1490 assert_eq!(
1491 norm(&utc_from_str(r#""2014-07-24T13:57:06+01:23""#).ok()),
1492 norm(&Some(Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()))
1493 );
1494
1495 assert_eq!(
1496 norm(&fixed_from_str(r#""2014-07-24T12:34:06Z""#).ok()),
1497 norm(&Some(
1498 FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()
1499 ))
1500 );
1501 assert_eq!(
1502 norm(&fixed_from_str(r#""2014-07-24T13:57:06+01:23""#).ok()),
1503 norm(&Some(
1504 FixedOffset::east_opt(60 * 60 + 23 * 60)
1505 .unwrap()
1506 .with_ymd_and_hms(2014, 7, 24, 13, 57, 6)
1507 .unwrap()
1508 ))
1509 );
1510
1511 // we don't know the exact local offset but we can check that
1512 // the conversion didn't change the instant itself
1513 assert_eq!(
1514 local_from_str(r#""2014-07-24T12:34:06Z""#).expect("local should parse"),
1515 Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()
1516 );
1517 assert_eq!(
1518 local_from_str(r#""2014-07-24T13:57:06+01:23""#).expect("local should parse with offset"),
1519 Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()
1520 );
1521
1522 assert!(utc_from_str(r#""2014-07-32T12:34:06Z""#).is_err());
1523 assert!(fixed_from_str(r#""2014-07-32T12:34:06Z""#).is_err());
1524}
1525
1526#[cfg(all(test, feature = "clock", feature = "rustc-serialize"))]
1527fn test_decodable_json_timestamps<FUtc, FFixed, FLocal, E>(
1528 utc_from_str: FUtc,
1529 fixed_from_str: FFixed,
1530 local_from_str: FLocal,
1531) where
1532 FUtc: Fn(&str) -> Result<rustc_serialize::TsSeconds<Utc>, E>,
1533 FFixed: Fn(&str) -> Result<rustc_serialize::TsSeconds<FixedOffset>, E>,
1534 FLocal: Fn(&str) -> Result<rustc_serialize::TsSeconds<Local>, E>,
1535 E: ::core::fmt::Debug,
1536{
1537 fn norm<Tz: TimeZone>(dt: &Option<DateTime<Tz>>) -> Option<(&DateTime<Tz>, &Tz::Offset)> {
1538 dt.as_ref().map(|dt| (dt, dt.offset()))
1539 }
1540
1541 assert_eq!(
1542 norm(&utc_from_str("0").ok().map(DateTime::from)),
1543 norm(&Some(Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap()))
1544 );
1545 assert_eq!(
1546 norm(&utc_from_str("-1").ok().map(DateTime::from)),
1547 norm(&Some(Utc.with_ymd_and_hms(1969, 12, 31, 23, 59, 59).unwrap()))
1548 );
1549
1550 assert_eq!(
1551 norm(&fixed_from_str("0").ok().map(DateTime::from)),
1552 norm(&Some(
1553 FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap()
1554 ))
1555 );
1556 assert_eq!(
1557 norm(&fixed_from_str("-1").ok().map(DateTime::from)),
1558 norm(&Some(
1559 FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(1969, 12, 31, 23, 59, 59).unwrap()
1560 ))
1561 );
1562
1563 assert_eq!(
1564 *fixed_from_str("0").expect("0 timestamp should parse"),
1565 Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap()
1566 );
1567 assert_eq!(
1568 *local_from_str("-1").expect("-1 timestamp should parse"),
1569 Utc.with_ymd_and_hms(1969, 12, 31, 23, 59, 59).unwrap()
1570 );
1571}