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