chrono/datetime.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
6use core::{str, fmt, hash};
7use core::cmp::Ordering;
8use core::ops::{Add, Sub};
9#[cfg(any(feature = "std", test))]
10use std::time::{SystemTime, UNIX_EPOCH};
11use oldtime::Duration as OldDuration;
12
13#[cfg(all(not(feature = "std"), feature = "alloc"))]
14use alloc::string::{String, ToString};
15#[cfg(feature = "std")]
16use std::string::ToString;
17
18use {Weekday, Timelike, Datelike};
19#[cfg(feature="clock")]
20use offset::Local;
21use offset::{TimeZone, Offset, Utc, FixedOffset};
22use naive::{NaiveTime, NaiveDateTime, IsoWeek};
23use Date;
24use format::{Item, Numeric, Pad, Fixed};
25use format::{parse, Parsed, ParseError, ParseResult, StrftimeItems};
26#[cfg(any(feature = "alloc", feature = "std", test))]
27use format::DelayedFormat;
28use core::borrow::Borrow;
29
30/// Specific formatting options for seconds. This may be extended in the
31/// future, so exhaustive matching in external code is not recommended.
32///
33/// See the `TimeZone::to_rfc3339_opts` function for usage.
34#[derive(Clone, Copy, Debug, Eq, PartialEq)]
35pub enum SecondsFormat {
36 /// Format whole seconds only, with no decimal point nor subseconds.
37 Secs,
38
39 /// Use fixed 3 subsecond digits. This corresponds to
40 /// [Fixed::Nanosecond3](format/enum.Fixed.html#variant.Nanosecond3).
41 Millis,
42
43 /// Use fixed 6 subsecond digits. This corresponds to
44 /// [Fixed::Nanosecond6](format/enum.Fixed.html#variant.Nanosecond6).
45 Micros,
46
47 /// Use fixed 9 subsecond digits. This corresponds to
48 /// [Fixed::Nanosecond9](format/enum.Fixed.html#variant.Nanosecond9).
49 Nanos,
50
51 /// Automatically select one of `Secs`, `Millis`, `Micros`, or `Nanos` to
52 /// display all available non-zero sub-second digits. This corresponds to
53 /// [Fixed::Nanosecond](format/enum.Fixed.html#variant.Nanosecond).
54 AutoSi,
55
56 // Do not match against this.
57 #[doc(hidden)]
58 __NonExhaustive,
59}
60
61/// ISO 8601 combined date and time with time zone.
62///
63/// There are some constructors implemented here (the `from_*` methods), but
64/// the general-purpose constructors are all via the methods on the
65/// [`TimeZone`](./offset/trait.TimeZone.html) implementations.
66#[derive(Clone)]
67pub struct DateTime<Tz: TimeZone> {
68 datetime: NaiveDateTime,
69 offset: Tz::Offset,
70}
71
72impl<Tz: TimeZone> DateTime<Tz> {
73 /// Makes a new `DateTime` with given *UTC* datetime and offset.
74 /// The local datetime should be constructed via the `TimeZone` trait.
75 ///
76 /// # Example
77 ///
78 /// ~~~~
79 /// use chrono::{DateTime, TimeZone, NaiveDateTime, Utc};
80 ///
81 /// let dt = DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(61, 0), Utc);
82 /// assert_eq!(Utc.timestamp(61, 0), dt);
83 /// ~~~~
84 //
85 // note: this constructor is purposedly not named to `new` to discourage the direct usage.
86 #[inline]
87 pub fn from_utc(datetime: NaiveDateTime, offset: Tz::Offset) -> DateTime<Tz> {
88 DateTime { datetime: datetime, offset: offset }
89 }
90
91 /// Retrieves a date component.
92 #[inline]
93 pub fn date(&self) -> Date<Tz> {
94 Date::from_utc(self.naive_local().date(), self.offset.clone())
95 }
96
97 /// Retrieves a time component.
98 /// Unlike `date`, this is not associated to the time zone.
99 #[inline]
100 pub fn time(&self) -> NaiveTime {
101 self.datetime.time() + self.offset.fix()
102 }
103
104 /// Returns the number of non-leap seconds since January 1, 1970 0:00:00 UTC
105 /// (aka "UNIX timestamp").
106 #[inline]
107 pub fn timestamp(&self) -> i64 {
108 self.datetime.timestamp()
109 }
110
111 /// Returns the number of non-leap-milliseconds since January 1, 1970 UTC
112 ///
113 /// Note that this does reduce the number of years that can be represented
114 /// from ~584 Billion to ~584 Million. (If this is a problem, please file
115 /// an issue to let me know what domain needs millisecond precision over
116 /// billions of years, I'm curious.)
117 ///
118 /// # Example
119 ///
120 /// ~~~~
121 /// use chrono::Utc;
122 /// use chrono::TimeZone;
123 ///
124 /// let dt = Utc.ymd(1970, 1, 1).and_hms_milli(0, 0, 1, 444);
125 /// assert_eq!(dt.timestamp_millis(), 1_444);
126 ///
127 /// let dt = Utc.ymd(2001, 9, 9).and_hms_milli(1, 46, 40, 555);
128 /// assert_eq!(dt.timestamp_millis(), 1_000_000_000_555);
129 /// ~~~~
130 #[inline]
131 pub fn timestamp_millis(&self) -> i64 {
132 self.datetime.timestamp_millis()
133 }
134
135 /// Returns the number of non-leap-nanoseconds since January 1, 1970 UTC
136 ///
137 /// Note that this does reduce the number of years that can be represented
138 /// from ~584 Billion to ~584. (If this is a problem, please file
139 /// an issue to let me know what domain needs nanosecond precision over
140 /// millenia, I'm curious.)
141 ///
142 /// # Example
143 ///
144 /// ~~~~
145 /// use chrono::Utc;
146 /// use chrono::TimeZone;
147 ///
148 /// let dt = Utc.ymd(1970, 1, 1).and_hms_nano(0, 0, 1, 444);
149 /// assert_eq!(dt.timestamp_nanos(), 1_000_000_444);
150 ///
151 /// let dt = Utc.ymd(2001, 9, 9).and_hms_nano(1, 46, 40, 555);
152 /// assert_eq!(dt.timestamp_nanos(), 1_000_000_000_000_000_555);
153 /// ~~~~
154 #[inline]
155 pub fn timestamp_nanos(&self) -> i64 {
156 self.datetime.timestamp_nanos()
157 }
158
159 /// Returns the number of milliseconds since the last second boundary
160 ///
161 /// warning: in event of a leap second, this may exceed 999
162 ///
163 /// note: this is not the number of milliseconds since January 1, 1970 0:00:00 UTC
164 #[inline]
165 pub fn timestamp_subsec_millis(&self) -> u32 {
166 self.datetime.timestamp_subsec_millis()
167 }
168
169 /// Returns the number of microseconds since the last second boundary
170 ///
171 /// warning: in event of a leap second, this may exceed 999_999
172 ///
173 /// note: this is not the number of microseconds since January 1, 1970 0:00:00 UTC
174 #[inline]
175 pub fn timestamp_subsec_micros(&self) -> u32 {
176 self.datetime.timestamp_subsec_micros()
177 }
178
179 /// Returns the number of nanoseconds since the last second boundary
180 ///
181 /// warning: in event of a leap second, this may exceed 999_999_999
182 ///
183 /// note: this is not the number of nanoseconds since January 1, 1970 0:00:00 UTC
184 #[inline]
185 pub fn timestamp_subsec_nanos(&self) -> u32 {
186 self.datetime.timestamp_subsec_nanos()
187 }
188
189 /// Retrieves an associated offset from UTC.
190 #[inline]
191 pub fn offset(&self) -> &Tz::Offset {
192 &self.offset
193 }
194
195 /// Retrieves an associated time zone.
196 #[inline]
197 pub fn timezone(&self) -> Tz {
198 TimeZone::from_offset(&self.offset)
199 }
200
201 /// Changes the associated time zone.
202 /// This does not change the actual `DateTime` (but will change the string representation).
203 #[inline]
204 pub fn with_timezone<Tz2: TimeZone>(&self, tz: &Tz2) -> DateTime<Tz2> {
205 tz.from_utc_datetime(&self.datetime)
206 }
207
208 /// Adds given `Duration` to the current date and time.
209 ///
210 /// Returns `None` when it will result in overflow.
211 #[inline]
212 pub fn checked_add_signed(self, rhs: OldDuration) -> Option<DateTime<Tz>> {
213 let datetime = try_opt!(self.datetime.checked_add_signed(rhs));
214 let tz = self.timezone();
215 Some(tz.from_utc_datetime(&datetime))
216 }
217
218 /// Subtracts given `Duration` from the current date and time.
219 ///
220 /// Returns `None` when it will result in overflow.
221 #[inline]
222 pub fn checked_sub_signed(self, rhs: OldDuration) -> Option<DateTime<Tz>> {
223 let datetime = try_opt!(self.datetime.checked_sub_signed(rhs));
224 let tz = self.timezone();
225 Some(tz.from_utc_datetime(&datetime))
226 }
227
228 /// Subtracts another `DateTime` from the current date and time.
229 /// This does not overflow or underflow at all.
230 #[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
231 #[inline]
232 pub fn signed_duration_since<Tz2: TimeZone>(self, rhs: DateTime<Tz2>) -> OldDuration {
233 self.datetime.signed_duration_since(rhs.datetime)
234 }
235
236 /// Returns a view to the naive UTC datetime.
237 #[inline]
238 pub fn naive_utc(&self) -> NaiveDateTime {
239 self.datetime
240 }
241
242 /// Returns a view to the naive local datetime.
243 #[inline]
244 pub fn naive_local(&self) -> NaiveDateTime {
245 self.datetime + self.offset.fix()
246 }
247}
248
249/// Convert a `DateTime<Utc>` instance into a `DateTime<FixedOffset>` instance.
250impl From<DateTime<Utc>> for DateTime<FixedOffset> {
251 /// Convert this `DateTime<Utc>` instance into a `DateTime<FixedOffset>` instance.
252 ///
253 /// Conversion is done via [`DateTime::with_timezone`]. Note that the converted value returned by
254 /// this will be created with a fixed timezone offset of 0.
255 fn from(src: DateTime<Utc>) -> Self {
256 src.with_timezone(&FixedOffset::east(0))
257 }
258}
259
260/// Convert a `DateTime<Utc>` instance into a `DateTime<Local>` instance.
261#[cfg(feature="clock")]
262impl From<DateTime<Utc>> for DateTime<Local> {
263 /// Convert this `DateTime<Utc>` instance into a `DateTime<Local>` instance.
264 ///
265 /// Conversion is performed via [`DateTime::with_timezone`], accounting for the difference in timezones.
266 fn from(src: DateTime<Utc>) -> Self {
267 src.with_timezone(&Local)
268 }
269}
270
271/// Convert a `DateTime<FixedOffset>` instance into a `DateTime<Utc>` instance.
272impl From<DateTime<FixedOffset>> for DateTime<Utc> {
273 /// Convert this `DateTime<FixedOffset>` instance into a `DateTime<Utc>` instance.
274 ///
275 /// Conversion is performed via [`DateTime::with_timezone`], accounting for the timezone
276 /// difference.
277 fn from(src: DateTime<FixedOffset>) -> Self {
278 src.with_timezone(&Utc)
279 }
280}
281
282/// Convert a `DateTime<FixedOffset>` instance into a `DateTime<Local>` instance.
283#[cfg(feature="clock")]
284impl From<DateTime<FixedOffset>> for DateTime<Local> {
285 /// Convert this `DateTime<FixedOffset>` instance into a `DateTime<Local>` instance.
286 ///
287 /// Conversion is performed via [`DateTime::with_timezone`]. Returns the equivalent value in local
288 /// time.
289 fn from(src: DateTime<FixedOffset>) -> Self {
290 src.with_timezone(&Local)
291 }
292}
293
294/// Convert a `DateTime<Local>` instance into a `DateTime<Utc>` instance.
295#[cfg(feature="clock")]
296impl From<DateTime<Local>> for DateTime<Utc> {
297 /// Convert this `DateTime<Local>` instance into a `DateTime<Utc>` instance.
298 ///
299 /// Conversion is performed via [`DateTime::with_timezone`], accounting for the difference in
300 /// timezones.
301 fn from(src: DateTime<Local>) -> Self {
302 src.with_timezone(&Utc)
303 }
304}
305
306/// Convert a `DateTime<Local>` instance into a `DateTime<FixedOffset>` instance.
307#[cfg(feature="clock")]
308impl From<DateTime<Local>> for DateTime<FixedOffset> {
309 /// Convert this `DateTime<Local>` instance into a `DateTime<FixedOffset>` instance.
310 ///
311 /// Conversion is performed via [`DateTime::with_timezone`]. Note that the converted value returned
312 /// by this will be created with a fixed timezone offset of 0.
313 fn from(src: DateTime<Local>) -> Self {
314 src.with_timezone(&FixedOffset::east(0))
315 }
316}
317
318/// Maps the local datetime to other datetime with given conversion function.
319fn map_local<Tz: TimeZone, F>(dt: &DateTime<Tz>, mut f: F) -> Option<DateTime<Tz>>
320 where F: FnMut(NaiveDateTime) -> Option<NaiveDateTime> {
321 f(dt.naive_local()).and_then(|datetime| dt.timezone().from_local_datetime(&datetime).single())
322}
323
324impl DateTime<FixedOffset> {
325 /// Parses an RFC 2822 date and time string such as `Tue, 1 Jul 2003 10:52:37 +0200`,
326 /// then returns a new `DateTime` with a parsed `FixedOffset`.
327 ///
328 /// RFC 2822 is the internet message standard that specifices the
329 /// representation of times in HTTP and email headers.
330 ///
331 /// ```
332 /// # use chrono::{DateTime, FixedOffset, TimeZone};
333 /// assert_eq!(
334 /// DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 GMT").unwrap(),
335 /// FixedOffset::east(0).ymd(2015, 2, 18).and_hms(23, 16, 9)
336 /// );
337 /// ```
338 pub fn parse_from_rfc2822(s: &str) -> ParseResult<DateTime<FixedOffset>> {
339 const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC2822)];
340 let mut parsed = Parsed::new();
341 parse(&mut parsed, s, ITEMS.iter())?;
342 parsed.to_datetime()
343 }
344
345 /// Parses an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`,
346 /// then returns a new `DateTime` with a parsed `FixedOffset`.
347 ///
348 /// Why isn't this named `parse_from_iso8601`? That's because ISO 8601 allows some freedom
349 /// over the syntax and RFC 3339 exercises that freedom to rigidly define a fixed format.
350 pub fn parse_from_rfc3339(s: &str) -> ParseResult<DateTime<FixedOffset>> {
351 const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC3339)];
352 let mut parsed = Parsed::new();
353 parse(&mut parsed, s, ITEMS.iter())?;
354 parsed.to_datetime()
355 }
356
357 /// Parses a string with the specified format string and
358 /// returns a new `DateTime` with a parsed `FixedOffset`.
359 /// See the [`format::strftime` module](./format/strftime/index.html)
360 /// on the supported escape sequences.
361 ///
362 /// See also `Offset::datetime_from_str` which gives a local `DateTime` on specific time zone.
363 ///
364 /// Note that this method *requires a timezone* in the string. See
365 /// [`NaiveDateTime::parse_from_str`](./naive/struct.NaiveDateTime.html#method.parse_from_str)
366 /// for a version that does not require a timezone in the to-be-parsed str.
367 ///
368 /// # Example
369 ///
370 /// ```rust
371 /// use chrono::{DateTime, FixedOffset, TimeZone};
372 ///
373 /// let dt = DateTime::parse_from_str(
374 /// "1983 Apr 13 12:09:14.274 +0000", "%Y %b %d %H:%M:%S%.3f %z");
375 /// assert_eq!(dt, Ok(FixedOffset::east(0).ymd(1983, 4, 13).and_hms_milli(12, 9, 14, 274)));
376 /// ```
377 pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult<DateTime<FixedOffset>> {
378 let mut parsed = Parsed::new();
379 parse(&mut parsed, s, StrftimeItems::new(fmt))?;
380 parsed.to_datetime()
381 }
382}
383
384impl<Tz: TimeZone> DateTime<Tz> where Tz::Offset: fmt::Display {
385 /// Returns an RFC 2822 date and time string such as `Tue, 1 Jul 2003 10:52:37 +0200`.
386 #[cfg(any(feature = "alloc", feature = "std", test))]
387 pub fn to_rfc2822(&self) -> String {
388 const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC2822)];
389 self.format_with_items(ITEMS.iter()).to_string()
390 }
391
392 /// Returns an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`.
393 #[cfg(any(feature = "alloc", feature = "std", test))]
394 pub fn to_rfc3339(&self) -> String {
395 const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC3339)];
396 self.format_with_items(ITEMS.iter()).to_string()
397 }
398
399 /// Return an RFC 3339 and ISO 8601 date and time string with subseconds
400 /// formatted as per a `SecondsFormat`. If passed `use_z` true and the
401 /// timezone is UTC (offset 0), use 'Z', as per
402 /// [Fixed::TimezoneOffsetColonZ](format/enum.Fixed.html#variant.TimezoneOffsetColonZ).
403 /// If passed `use_z` false, use
404 /// [Fixed::TimezoneOffsetColon](format/enum.Fixed.html#variant.TimezoneOffsetColon).
405 ///
406 /// # Examples
407 ///
408 /// ```rust
409 /// # use chrono::{DateTime, FixedOffset, SecondsFormat, TimeZone, Utc};
410 /// let dt = Utc.ymd(2018, 1, 26).and_hms_micro(18, 30, 9, 453_829);
411 /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, false),
412 /// "2018-01-26T18:30:09.453+00:00");
413 /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, true),
414 /// "2018-01-26T18:30:09.453Z");
415 /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true),
416 /// "2018-01-26T18:30:09Z");
417 ///
418 /// let pst = FixedOffset::east(8 * 60 * 60);
419 /// let dt = pst.ymd(2018, 1, 26).and_hms_micro(10, 30, 9, 453_829);
420 /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true),
421 /// "2018-01-26T10:30:09+08:00");
422 /// ```
423 #[cfg(any(feature = "alloc", feature = "std", test))]
424 pub fn to_rfc3339_opts(&self, secform: SecondsFormat, use_z: bool) -> String {
425 use format::Numeric::*;
426 use format::Pad::Zero;
427 use SecondsFormat::*;
428
429 debug_assert!(secform != __NonExhaustive, "Do not use __NonExhaustive!");
430
431 const PREFIX: &'static [Item<'static>] = &[
432 Item::Numeric(Year, Zero),
433 Item::Literal("-"),
434 Item::Numeric(Month, Zero),
435 Item::Literal("-"),
436 Item::Numeric(Day, Zero),
437 Item::Literal("T"),
438 Item::Numeric(Hour, Zero),
439 Item::Literal(":"),
440 Item::Numeric(Minute, Zero),
441 Item::Literal(":"),
442 Item::Numeric(Second, Zero),
443 ];
444
445 let ssitem = match secform {
446 Secs => None,
447 Millis => Some(Item::Fixed(Fixed::Nanosecond3)),
448 Micros => Some(Item::Fixed(Fixed::Nanosecond6)),
449 Nanos => Some(Item::Fixed(Fixed::Nanosecond9)),
450 AutoSi => Some(Item::Fixed(Fixed::Nanosecond)),
451 __NonExhaustive => unreachable!(),
452 };
453
454 let tzitem = Item::Fixed(
455 if use_z {
456 Fixed::TimezoneOffsetColonZ
457 } else {
458 Fixed::TimezoneOffsetColon
459 }
460 );
461
462 match ssitem {
463 None =>
464 self.format_with_items(
465 PREFIX.iter().chain([tzitem].iter())
466 ).to_string(),
467 Some(s) =>
468 self.format_with_items(
469 PREFIX.iter().chain([s, tzitem].iter())
470 ).to_string(),
471 }
472 }
473
474 /// Formats the combined date and time with the specified formatting items.
475 #[cfg(any(feature = "alloc", feature = "std", test))]
476 #[inline]
477 pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
478 where I: Iterator<Item=B> + Clone, B: Borrow<Item<'a>> {
479 let local = self.naive_local();
480 DelayedFormat::new_with_offset(Some(local.date()), Some(local.time()), &self.offset, items)
481 }
482
483 /// Formats the combined date and time with the specified format string.
484 /// See the [`format::strftime` module](./format/strftime/index.html)
485 /// on the supported escape sequences.
486 #[cfg(any(feature = "alloc", feature = "std", test))]
487 #[inline]
488 pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
489 self.format_with_items(StrftimeItems::new(fmt))
490 }
491}
492
493impl<Tz: TimeZone> Datelike for DateTime<Tz> {
494 #[inline] fn year(&self) -> i32 { self.naive_local().year() }
495 #[inline] fn month(&self) -> u32 { self.naive_local().month() }
496 #[inline] fn month0(&self) -> u32 { self.naive_local().month0() }
497 #[inline] fn day(&self) -> u32 { self.naive_local().day() }
498 #[inline] fn day0(&self) -> u32 { self.naive_local().day0() }
499 #[inline] fn ordinal(&self) -> u32 { self.naive_local().ordinal() }
500 #[inline] fn ordinal0(&self) -> u32 { self.naive_local().ordinal0() }
501 #[inline] fn weekday(&self) -> Weekday { self.naive_local().weekday() }
502 #[inline] fn iso_week(&self) -> IsoWeek { self.naive_local().iso_week() }
503
504 #[inline]
505 fn with_year(&self, year: i32) -> Option<DateTime<Tz>> {
506 map_local(self, |datetime| datetime.with_year(year))
507 }
508
509 #[inline]
510 fn with_month(&self, month: u32) -> Option<DateTime<Tz>> {
511 map_local(self, |datetime| datetime.with_month(month))
512 }
513
514 #[inline]
515 fn with_month0(&self, month0: u32) -> Option<DateTime<Tz>> {
516 map_local(self, |datetime| datetime.with_month0(month0))
517 }
518
519 #[inline]
520 fn with_day(&self, day: u32) -> Option<DateTime<Tz>> {
521 map_local(self, |datetime| datetime.with_day(day))
522 }
523
524 #[inline]
525 fn with_day0(&self, day0: u32) -> Option<DateTime<Tz>> {
526 map_local(self, |datetime| datetime.with_day0(day0))
527 }
528
529 #[inline]
530 fn with_ordinal(&self, ordinal: u32) -> Option<DateTime<Tz>> {
531 map_local(self, |datetime| datetime.with_ordinal(ordinal))
532 }
533
534 #[inline]
535 fn with_ordinal0(&self, ordinal0: u32) -> Option<DateTime<Tz>> {
536 map_local(self, |datetime| datetime.with_ordinal0(ordinal0))
537 }
538}
539
540impl<Tz: TimeZone> Timelike for DateTime<Tz> {
541 #[inline] fn hour(&self) -> u32 { self.naive_local().hour() }
542 #[inline] fn minute(&self) -> u32 { self.naive_local().minute() }
543 #[inline] fn second(&self) -> u32 { self.naive_local().second() }
544 #[inline] fn nanosecond(&self) -> u32 { self.naive_local().nanosecond() }
545
546 #[inline]
547 fn with_hour(&self, hour: u32) -> Option<DateTime<Tz>> {
548 map_local(self, |datetime| datetime.with_hour(hour))
549 }
550
551 #[inline]
552 fn with_minute(&self, min: u32) -> Option<DateTime<Tz>> {
553 map_local(self, |datetime| datetime.with_minute(min))
554 }
555
556 #[inline]
557 fn with_second(&self, sec: u32) -> Option<DateTime<Tz>> {
558 map_local(self, |datetime| datetime.with_second(sec))
559 }
560
561 #[inline]
562 fn with_nanosecond(&self, nano: u32) -> Option<DateTime<Tz>> {
563 map_local(self, |datetime| datetime.with_nanosecond(nano))
564 }
565}
566
567// we need them as automatic impls cannot handle associated types
568impl<Tz: TimeZone> Copy for DateTime<Tz> where <Tz as TimeZone>::Offset: Copy {}
569unsafe impl<Tz: TimeZone> Send for DateTime<Tz> where <Tz as TimeZone>::Offset: Send {}
570
571impl<Tz: TimeZone, Tz2: TimeZone> PartialEq<DateTime<Tz2>> for DateTime<Tz> {
572 fn eq(&self, other: &DateTime<Tz2>) -> bool { self.datetime == other.datetime }
573}
574
575impl<Tz: TimeZone> Eq for DateTime<Tz> {
576}
577
578impl<Tz: TimeZone> PartialOrd for DateTime<Tz> {
579 fn partial_cmp(&self, other: &DateTime<Tz>) -> Option<Ordering> {
580 self.datetime.partial_cmp(&other.datetime)
581 }
582}
583
584impl<Tz: TimeZone> Ord for DateTime<Tz> {
585 fn cmp(&self, other: &DateTime<Tz>) -> Ordering { self.datetime.cmp(&other.datetime) }
586}
587
588impl<Tz: TimeZone> hash::Hash for DateTime<Tz> {
589 fn hash<H: hash::Hasher>(&self, state: &mut H) { self.datetime.hash(state) }
590}
591
592impl<Tz: TimeZone> Add<OldDuration> for DateTime<Tz> {
593 type Output = DateTime<Tz>;
594
595 #[inline]
596 fn add(self, rhs: OldDuration) -> DateTime<Tz> {
597 self.checked_add_signed(rhs).expect("`DateTime + Duration` overflowed")
598 }
599}
600
601impl<Tz: TimeZone> Sub<OldDuration> for DateTime<Tz> {
602 type Output = DateTime<Tz>;
603
604 #[inline]
605 fn sub(self, rhs: OldDuration) -> DateTime<Tz> {
606 self.checked_sub_signed(rhs).expect("`DateTime - Duration` overflowed")
607 }
608}
609
610impl<Tz: TimeZone> Sub<DateTime<Tz>> for DateTime<Tz> {
611 type Output = OldDuration;
612
613 #[inline]
614 fn sub(self, rhs: DateTime<Tz>) -> OldDuration {
615 self.signed_duration_since(rhs)
616 }
617}
618
619impl<Tz: TimeZone> fmt::Debug for DateTime<Tz> {
620 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
621 write!(f, "{:?}{:?}", self.naive_local(), self.offset)
622 }
623}
624
625impl<Tz: TimeZone> fmt::Display for DateTime<Tz> where Tz::Offset: fmt::Display {
626 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
627 write!(f, "{} {}", self.naive_local(), self.offset)
628 }
629}
630
631impl str::FromStr for DateTime<FixedOffset> {
632 type Err = ParseError;
633
634 fn from_str(s: &str) -> ParseResult<DateTime<FixedOffset>> {
635 const ITEMS: &'static [Item<'static>] = &[
636 Item::Numeric(Numeric::Year, Pad::Zero),
637 Item::Space(""), Item::Literal("-"),
638 Item::Numeric(Numeric::Month, Pad::Zero),
639 Item::Space(""), Item::Literal("-"),
640 Item::Numeric(Numeric::Day, Pad::Zero),
641 Item::Space(""), Item::Literal("T"), // XXX shouldn't this be case-insensitive?
642 Item::Numeric(Numeric::Hour, Pad::Zero),
643 Item::Space(""), Item::Literal(":"),
644 Item::Numeric(Numeric::Minute, Pad::Zero),
645 Item::Space(""), Item::Literal(":"),
646 Item::Numeric(Numeric::Second, Pad::Zero),
647 Item::Fixed(Fixed::Nanosecond),
648 Item::Space(""), Item::Fixed(Fixed::TimezoneOffsetZ),
649 Item::Space(""),
650 ];
651
652 let mut parsed = Parsed::new();
653 parse(&mut parsed, s, ITEMS.iter())?;
654 parsed.to_datetime()
655 }
656}
657
658impl str::FromStr for DateTime<Utc> {
659 type Err = ParseError;
660
661 fn from_str(s: &str) -> ParseResult<DateTime<Utc>> {
662 s.parse::<DateTime<FixedOffset>>().map(|dt| dt.with_timezone(&Utc))
663 }
664}
665
666#[cfg(feature="clock")]
667impl str::FromStr for DateTime<Local> {
668 type Err = ParseError;
669
670 fn from_str(s: &str) -> ParseResult<DateTime<Local>> {
671 s.parse::<DateTime<FixedOffset>>().map(|dt| dt.with_timezone(&Local))
672 }
673}
674
675#[cfg(any(feature = "std", test))]
676impl From<SystemTime> for DateTime<Utc> {
677 fn from(t: SystemTime) -> DateTime<Utc> {
678 let (sec, nsec) = match t.duration_since(UNIX_EPOCH) {
679 Ok(dur) => (dur.as_secs() as i64, dur.subsec_nanos()),
680 Err(e) => { // unlikely but should be handled
681 let dur = e.duration();
682 let (sec, nsec) = (dur.as_secs() as i64, dur.subsec_nanos());
683 if nsec == 0 {
684 (-sec, 0)
685 } else {
686 (-sec - 1, 1_000_000_000 - nsec)
687 }
688 },
689 };
690 Utc.timestamp(sec, nsec)
691 }
692}
693
694#[cfg(feature="clock")]
695impl From<SystemTime> for DateTime<Local> {
696 fn from(t: SystemTime) -> DateTime<Local> {
697 DateTime::<Utc>::from(t).with_timezone(&Local)
698 }
699}
700
701#[cfg(any(feature = "std", test))]
702impl<Tz: TimeZone> From<DateTime<Tz>> for SystemTime {
703 fn from(dt: DateTime<Tz>) -> SystemTime {
704 use std::time::Duration;
705
706 let sec = dt.timestamp();
707 let nsec = dt.timestamp_subsec_nanos();
708 if sec < 0 {
709 // unlikely but should be handled
710 UNIX_EPOCH - Duration::new(-sec as u64, 0) + Duration::new(0, nsec)
711 } else {
712 UNIX_EPOCH + Duration::new(sec as u64, nsec)
713 }
714 }
715}
716
717#[test]
718fn test_auto_conversion() {
719 let utc_dt = Utc.ymd(2018, 9, 5).and_hms(23, 58, 0);
720 let cdt_dt = FixedOffset::west(5 * 60 * 60).ymd(2018, 9, 5).and_hms(18, 58, 0);
721 let utc_dt2: DateTime<Utc> = cdt_dt.into();
722 assert_eq!(utc_dt, utc_dt2);
723}
724
725#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
726fn test_encodable_json<FUtc, FFixed, E>(to_string_utc: FUtc, to_string_fixed: FFixed)
727 where FUtc: Fn(&DateTime<Utc>) -> Result<String, E>,
728 FFixed: Fn(&DateTime<FixedOffset>) -> Result<String, E>,
729 E: ::core::fmt::Debug
730{
731 assert_eq!(to_string_utc(&Utc.ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(),
732 Some(r#""2014-07-24T12:34:06Z""#.into()));
733
734 assert_eq!(to_string_fixed(&FixedOffset::east(3660).ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(),
735 Some(r#""2014-07-24T12:34:06+01:01""#.into()));
736 assert_eq!(to_string_fixed(&FixedOffset::east(3650).ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(),
737 Some(r#""2014-07-24T12:34:06+01:00:50""#.into()));
738}
739
740#[cfg(all(test, feature="clock", any(feature = "rustc-serialize", feature = "serde")))]
741fn test_decodable_json<FUtc, FFixed, FLocal, E>(utc_from_str: FUtc,
742 fixed_from_str: FFixed,
743 local_from_str: FLocal)
744 where FUtc: Fn(&str) -> Result<DateTime<Utc>, E>,
745 FFixed: Fn(&str) -> Result<DateTime<FixedOffset>, E>,
746 FLocal: Fn(&str) -> Result<DateTime<Local>, E>,
747 E: ::core::fmt::Debug
748{
749 // should check against the offset as well (the normal DateTime comparison will ignore them)
750 fn norm<Tz: TimeZone>(dt: &Option<DateTime<Tz>>) -> Option<(&DateTime<Tz>, &Tz::Offset)> {
751 dt.as_ref().map(|dt| (dt, dt.offset()))
752 }
753
754 assert_eq!(norm(&utc_from_str(r#""2014-07-24T12:34:06Z""#).ok()),
755 norm(&Some(Utc.ymd(2014, 7, 24).and_hms(12, 34, 6))));
756 assert_eq!(norm(&utc_from_str(r#""2014-07-24T13:57:06+01:23""#).ok()),
757 norm(&Some(Utc.ymd(2014, 7, 24).and_hms(12, 34, 6))));
758
759 assert_eq!(norm(&fixed_from_str(r#""2014-07-24T12:34:06Z""#).ok()),
760 norm(&Some(FixedOffset::east(0).ymd(2014, 7, 24).and_hms(12, 34, 6))));
761 assert_eq!(norm(&fixed_from_str(r#""2014-07-24T13:57:06+01:23""#).ok()),
762 norm(&Some(FixedOffset::east(60*60 + 23*60).ymd(2014, 7, 24).and_hms(13, 57, 6))));
763
764 // we don't know the exact local offset but we can check that
765 // the conversion didn't change the instant itself
766 assert_eq!(local_from_str(r#""2014-07-24T12:34:06Z""#)
767 .expect("local shouuld parse"),
768 Utc.ymd(2014, 7, 24).and_hms(12, 34, 6));
769 assert_eq!(local_from_str(r#""2014-07-24T13:57:06+01:23""#)
770 .expect("local should parse with offset"),
771 Utc.ymd(2014, 7, 24).and_hms(12, 34, 6));
772
773 assert!(utc_from_str(r#""2014-07-32T12:34:06Z""#).is_err());
774 assert!(fixed_from_str(r#""2014-07-32T12:34:06Z""#).is_err());
775}
776
777#[cfg(all(test, feature="clock", feature = "rustc-serialize"))]
778fn test_decodable_json_timestamps<FUtc, FFixed, FLocal, E>(utc_from_str: FUtc,
779 fixed_from_str: FFixed,
780 local_from_str: FLocal)
781 where FUtc: Fn(&str) -> Result<rustc_serialize::TsSeconds<Utc>, E>,
782 FFixed: Fn(&str) -> Result<rustc_serialize::TsSeconds<FixedOffset>, E>,
783 FLocal: Fn(&str) -> Result<rustc_serialize::TsSeconds<Local>, E>,
784 E: ::core::fmt::Debug
785{
786 fn norm<Tz: TimeZone>(dt: &Option<DateTime<Tz>>) -> Option<(&DateTime<Tz>, &Tz::Offset)> {
787 dt.as_ref().map(|dt| (dt, dt.offset()))
788 }
789
790 assert_eq!(norm(&utc_from_str("0").ok().map(DateTime::from)),
791 norm(&Some(Utc.ymd(1970, 1, 1).and_hms(0, 0, 0))));
792 assert_eq!(norm(&utc_from_str("-1").ok().map(DateTime::from)),
793 norm(&Some(Utc.ymd(1969, 12, 31).and_hms(23, 59, 59))));
794
795 assert_eq!(norm(&fixed_from_str("0").ok().map(DateTime::from)),
796 norm(&Some(FixedOffset::east(0).ymd(1970, 1, 1).and_hms(0, 0, 0))));
797 assert_eq!(norm(&fixed_from_str("-1").ok().map(DateTime::from)),
798 norm(&Some(FixedOffset::east(0).ymd(1969, 12, 31).and_hms(23, 59, 59))));
799
800 assert_eq!(*fixed_from_str("0").expect("0 timestamp should parse"),
801 Utc.ymd(1970, 1, 1).and_hms(0, 0, 0));
802 assert_eq!(*local_from_str("-1").expect("-1 timestamp should parse"),
803 Utc.ymd(1969, 12, 31).and_hms(23, 59, 59));
804}
805
806#[cfg(feature = "rustc-serialize")]
807pub mod rustc_serialize {
808 use core::fmt;
809 use core::ops::Deref;
810 use super::DateTime;
811 #[cfg(feature="clock")]
812 use offset::Local;
813 use offset::{TimeZone, LocalResult, Utc, FixedOffset};
814 use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
815
816 impl<Tz: TimeZone> Encodable for DateTime<Tz> {
817 fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
818 format!("{:?}", self).encode(s)
819 }
820 }
821
822 // lik? function to convert a LocalResult into a serde-ish Result
823 fn from<T, D>(me: LocalResult<T>, d: &mut D) -> Result<T, D::Error>
824 where D: Decoder,
825 T: fmt::Display,
826 {
827 match me {
828 LocalResult::None => Err(d.error(
829 "value is not a legal timestamp")),
830 LocalResult::Ambiguous(..) => Err(d.error(
831 "value is an ambiguous timestamp")),
832 LocalResult::Single(val) => Ok(val)
833 }
834 }
835
836 impl Decodable for DateTime<FixedOffset> {
837 fn decode<D: Decoder>(d: &mut D) -> Result<DateTime<FixedOffset>, D::Error> {
838 d.read_str()?.parse::<DateTime<FixedOffset>>()
839 .map_err(|_| d.error("invalid date and time"))
840 }
841 }
842
843 #[allow(deprecated)]
844 impl Decodable for TsSeconds<FixedOffset> {
845 #[allow(deprecated)]
846 fn decode<D: Decoder>(d: &mut D) -> Result<TsSeconds<FixedOffset>, D::Error> {
847 from(FixedOffset::east(0).timestamp_opt(d.read_i64()?, 0), d)
848 .map(TsSeconds)
849 }
850 }
851
852 impl Decodable for DateTime<Utc> {
853 fn decode<D: Decoder>(d: &mut D) -> Result<DateTime<Utc>, D::Error> {
854 d.read_str()?
855 .parse::<DateTime<FixedOffset>>()
856 .map(|dt| dt.with_timezone(&Utc))
857 .map_err(|_| d.error("invalid date and time"))
858 }
859 }
860
861 /// A `DateTime` that can be deserialized from a timestamp
862 ///
863 /// A timestamp here is seconds since the epoch
864 #[derive(Debug)]
865 pub struct TsSeconds<Tz: TimeZone>(DateTime<Tz>);
866
867 #[allow(deprecated)]
868 impl<Tz: TimeZone> From<TsSeconds<Tz>> for DateTime<Tz> {
869 /// Pull the inner DateTime<Tz> out
870 #[allow(deprecated)]
871 fn from(obj: TsSeconds<Tz>) -> DateTime<Tz> {
872 obj.0
873 }
874 }
875
876 #[allow(deprecated)]
877 impl<Tz: TimeZone> Deref for TsSeconds<Tz> {
878 type Target = DateTime<Tz>;
879
880 fn deref(&self) -> &Self::Target {
881 &self.0
882 }
883 }
884
885 #[allow(deprecated)]
886 impl Decodable for TsSeconds<Utc> {
887 fn decode<D: Decoder>(d: &mut D) -> Result<TsSeconds<Utc>, D::Error> {
888 from(Utc.timestamp_opt(d.read_i64()?, 0), d)
889 .map(TsSeconds)
890 }
891 }
892
893 #[cfg(feature="clock")]
894 impl Decodable for DateTime<Local> {
895 fn decode<D: Decoder>(d: &mut D) -> Result<DateTime<Local>, D::Error> {
896 match d.read_str()?.parse::<DateTime<FixedOffset>>() {
897 Ok(dt) => Ok(dt.with_timezone(&Local)),
898 Err(_) => Err(d.error("invalid date and time")),
899 }
900 }
901 }
902
903 #[cfg(feature="clock")]
904 #[allow(deprecated)]
905 impl Decodable for TsSeconds<Local> {
906 #[allow(deprecated)]
907 fn decode<D: Decoder>(d: &mut D) -> Result<TsSeconds<Local>, D::Error> {
908 from(Utc.timestamp_opt(d.read_i64()?, 0), d)
909 .map(|dt| TsSeconds(dt.with_timezone(&Local)))
910 }
911 }
912
913 #[cfg(test)] use rustc_serialize::json;
914
915 #[test]
916 fn test_encodable() {
917 super::test_encodable_json(json::encode, json::encode);
918 }
919
920 #[cfg(feature="clock")]
921 #[test]
922 fn test_decodable() {
923 super::test_decodable_json(json::decode, json::decode, json::decode);
924 }
925
926 #[cfg(feature="clock")]
927 #[test]
928 fn test_decodable_timestamps() {
929 super::test_decodable_json_timestamps(json::decode, json::decode, json::decode);
930 }
931
932}
933
934/// documented at re-export site
935#[cfg(feature = "serde")]
936pub mod serde {
937 use core::fmt;
938 use super::DateTime;
939 #[cfg(feature="clock")]
940 use offset::Local;
941 use offset::{LocalResult, TimeZone, Utc, FixedOffset};
942 use serdelib::{ser, de};
943 use {SerdeError, ne_timestamp};
944
945 #[doc(hidden)]
946 #[derive(Debug)]
947 pub struct SecondsTimestampVisitor;
948
949 #[doc(hidden)]
950 #[derive(Debug)]
951 pub struct NanoSecondsTimestampVisitor;
952
953 #[doc(hidden)]
954 #[derive(Debug)]
955 pub struct MilliSecondsTimestampVisitor;
956
957 // lik? function to convert a LocalResult into a serde-ish Result
958 fn serde_from<T, E, V>(me: LocalResult<T>, ts: &V) -> Result<T, E>
959 where
960 E: de::Error,
961 V: fmt::Display,
962 T: fmt::Display,
963 {
964 match me {
965 LocalResult::None => Err(E::custom(
966 ne_timestamp(ts))),
967 LocalResult::Ambiguous(min, max) => Err(E::custom(
968 SerdeError::Ambiguous { timestamp: ts, min: min, max: max })),
969 LocalResult::Single(val) => Ok(val)
970 }
971 }
972
973 /// Ser/de to/from timestamps in nanoseconds
974 ///
975 /// Intended for use with `serde`'s `with` attribute.
976 ///
977 /// # Example:
978 ///
979 /// ```rust
980 /// # // We mark this ignored so that we can test on 1.13 (which does not
981 /// # // support custom derive), and run tests with --ignored on beta and
982 /// # // nightly to actually trigger these.
983 /// #
984 /// # #[macro_use] extern crate serde_derive;
985 /// # #[macro_use] extern crate serde_json;
986 /// # extern crate chrono;
987 /// # use chrono::{TimeZone, DateTime, Utc};
988 /// use chrono::serde::ts_nanoseconds;
989 /// #[derive(Deserialize, Serialize)]
990 /// struct S {
991 /// #[serde(with = "ts_nanoseconds")]
992 /// time: DateTime<Utc>
993 /// }
994 ///
995 /// # fn example() -> Result<S, serde_json::Error> {
996 /// let time = Utc.ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733);
997 /// let my_s = S {
998 /// time: time.clone(),
999 /// };
1000 ///
1001 /// let as_string = serde_json::to_string(&my_s)?;
1002 /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
1003 /// let my_s: S = serde_json::from_str(&as_string)?;
1004 /// assert_eq!(my_s.time, time);
1005 /// # Ok(my_s)
1006 /// # }
1007 /// # fn main() { example().unwrap(); }
1008 /// ```
1009 pub mod ts_nanoseconds {
1010 use core::fmt;
1011 use serdelib::{ser, de};
1012
1013 use {DateTime, Utc};
1014 use offset::TimeZone;
1015
1016 use super::{serde_from, NanoSecondsTimestampVisitor};
1017
1018 /// Serialize a UTC datetime into an integer number of nanoseconds since the epoch
1019 ///
1020 /// Intended for use with `serde`s `serialize_with` attribute.
1021 ///
1022 /// # Example:
1023 ///
1024 /// ```rust
1025 /// # // We mark this ignored so that we can test on 1.13 (which does not
1026 /// # // support custom derive), and run tests with --ignored on beta and
1027 /// # // nightly to actually trigger these.
1028 /// #
1029 /// # #[macro_use] extern crate serde_derive;
1030 /// # #[macro_use] extern crate serde_json;
1031 /// # extern crate chrono;
1032 /// # use chrono::{TimeZone, DateTime, Utc};
1033 /// use chrono::serde::ts_nanoseconds::serialize as to_nano_ts;
1034 /// #[derive(Serialize)]
1035 /// struct S {
1036 /// #[serde(serialize_with = "to_nano_ts")]
1037 /// time: DateTime<Utc>
1038 /// }
1039 ///
1040 /// # fn example() -> Result<String, serde_json::Error> {
1041 /// let my_s = S {
1042 /// time: Utc.ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733),
1043 /// };
1044 /// let as_string = serde_json::to_string(&my_s)?;
1045 /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
1046 /// # Ok(as_string)
1047 /// # }
1048 /// # fn main() { example().unwrap(); }
1049 /// ```
1050 pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
1051 where S: ser::Serializer
1052 {
1053 serializer.serialize_i64(dt.timestamp_nanos())
1054 }
1055
1056 /// Deserialize a `DateTime` from a nanosecond timestamp
1057 ///
1058 /// Intended for use with `serde`s `deserialize_with` attribute.
1059 ///
1060 /// # Example:
1061 ///
1062 /// ```rust
1063 /// # // We mark this ignored so that we can test on 1.13 (which does not
1064 /// # // support custom derive), and run tests with --ignored on beta and
1065 /// # // nightly to actually trigger these.
1066 /// #
1067 /// # #[macro_use] extern crate serde_derive;
1068 /// # #[macro_use] extern crate serde_json;
1069 /// # extern crate chrono;
1070 /// # use chrono::{DateTime, Utc};
1071 /// use chrono::serde::ts_nanoseconds::deserialize as from_nano_ts;
1072 /// #[derive(Deserialize)]
1073 /// struct S {
1074 /// #[serde(deserialize_with = "from_nano_ts")]
1075 /// time: DateTime<Utc>
1076 /// }
1077 ///
1078 /// # fn example() -> Result<S, serde_json::Error> {
1079 /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?;
1080 /// # Ok(my_s)
1081 /// # }
1082 /// # fn main() { example().unwrap(); }
1083 /// ```
1084 pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error>
1085 where D: de::Deserializer<'de>
1086 {
1087 Ok(d.deserialize_i64(NanoSecondsTimestampVisitor)?)
1088 }
1089
1090 impl<'de> de::Visitor<'de> for NanoSecondsTimestampVisitor {
1091 type Value = DateTime<Utc>;
1092
1093 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result
1094 {
1095 write!(formatter, "a unix timestamp in nanoseconds")
1096 }
1097
1098 /// Deserialize a timestamp in nanoseconds since the epoch
1099 fn visit_i64<E>(self, value: i64) -> Result<DateTime<Utc>, E>
1100 where E: de::Error
1101 {
1102 serde_from(Utc.timestamp_opt(value / 1_000_000_000,
1103 (value % 1_000_000_000) as u32),
1104 &value)
1105 }
1106
1107 /// Deserialize a timestamp in nanoseconds since the epoch
1108 fn visit_u64<E>(self, value: u64) -> Result<DateTime<Utc>, E>
1109 where E: de::Error
1110 {
1111 serde_from(Utc.timestamp_opt((value / 1_000_000_000) as i64,
1112 (value % 1_000_000_000) as u32),
1113 &value)
1114 }
1115 }
1116 }
1117
1118 /// Ser/de to/from optional timestamps in nanoseconds
1119 ///
1120 /// Intended for use with `serde`'s `with` attribute.
1121 ///
1122 /// # Example:
1123 ///
1124 /// ```rust
1125 /// # // We mark this ignored so that we can test on 1.13 (which does not
1126 /// # // support custom derive), and run tests with --ignored on beta and
1127 /// # // nightly to actually trigger these.
1128 /// #
1129 /// # #[macro_use] extern crate serde_derive;
1130 /// # #[macro_use] extern crate serde_json;
1131 /// # extern crate chrono;
1132 /// # use chrono::{TimeZone, DateTime, Utc};
1133 /// use chrono::serde::ts_nanoseconds_option;
1134 /// #[derive(Deserialize, Serialize)]
1135 /// struct S {
1136 /// #[serde(with = "ts_nanoseconds_option")]
1137 /// time: Option<DateTime<Utc>>
1138 /// }
1139 ///
1140 /// # fn example() -> Result<S, serde_json::Error> {
1141 /// let time = Some(Utc.ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733));
1142 /// let my_s = S {
1143 /// time: time.clone(),
1144 /// };
1145 ///
1146 /// let as_string = serde_json::to_string(&my_s)?;
1147 /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
1148 /// let my_s: S = serde_json::from_str(&as_string)?;
1149 /// assert_eq!(my_s.time, time);
1150 /// # Ok(my_s)
1151 /// # }
1152 /// # fn main() { example().unwrap(); }
1153 /// ```
1154 pub mod ts_nanoseconds_option {
1155 use core::fmt;
1156 use serdelib::{ser, de};
1157
1158 use {DateTime, Utc};
1159
1160 use super::{ts_nanoseconds, NanoSecondsTimestampVisitor};
1161
1162 /// Serialize a UTC datetime into an integer number of nanoseconds since the epoch or none
1163 ///
1164 /// Intended for use with `serde`s `serialize_with` attribute.
1165 ///
1166 /// # Example:
1167 ///
1168 /// ```rust
1169 /// # // We mark this ignored so that we can test on 1.13 (which does not
1170 /// # // support custom derive), and run tests with --ignored on beta and
1171 /// # // nightly to actually trigger these.
1172 /// #
1173 /// # #[macro_use] extern crate serde_derive;
1174 /// # #[macro_use] extern crate serde_json;
1175 /// # extern crate chrono;
1176 /// # use chrono::{TimeZone, DateTime, Utc};
1177 /// use chrono::serde::ts_nanoseconds_option::serialize as to_nano_tsopt;
1178 /// #[derive(Serialize)]
1179 /// struct S {
1180 /// #[serde(serialize_with = "to_nano_tsopt")]
1181 /// time: Option<DateTime<Utc>>
1182 /// }
1183 ///
1184 /// # fn example() -> Result<String, serde_json::Error> {
1185 /// let my_s = S {
1186 /// time: Some(Utc.ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733)),
1187 /// };
1188 /// let as_string = serde_json::to_string(&my_s)?;
1189 /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
1190 /// # Ok(as_string)
1191 /// # }
1192 /// # fn main() { example().unwrap(); }
1193 /// ```
1194 pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
1195 where S: ser::Serializer
1196 {
1197 match *opt {
1198 Some(ref dt) => ts_nanoseconds::serialize(dt, serializer),
1199 None => serializer.serialize_none(),
1200 }
1201 }
1202
1203 /// Deserialize a `DateTime` from a nanosecond timestamp or none
1204 ///
1205 /// Intended for use with `serde`s `deserialize_with` attribute.
1206 ///
1207 /// # Example:
1208 ///
1209 /// ```rust
1210 /// # // We mark this ignored so that we can test on 1.13 (which does not
1211 /// # // support custom derive), and run tests with --ignored on beta and
1212 /// # // nightly to actually trigger these.
1213 /// #
1214 /// # #[macro_use] extern crate serde_derive;
1215 /// # #[macro_use] extern crate serde_json;
1216 /// # extern crate chrono;
1217 /// # use chrono::{DateTime, Utc};
1218 /// use chrono::serde::ts_nanoseconds_option::deserialize as from_nano_tsopt;
1219 /// #[derive(Deserialize)]
1220 /// struct S {
1221 /// #[serde(deserialize_with = "from_nano_tsopt")]
1222 /// time: Option<DateTime<Utc>>
1223 /// }
1224 ///
1225 /// # fn example() -> Result<S, serde_json::Error> {
1226 /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?;
1227 /// # Ok(my_s)
1228 /// # }
1229 /// # fn main() { example().unwrap(); }
1230 /// ```
1231 pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error>
1232 where D: de::Deserializer<'de>
1233 {
1234 Ok(d.deserialize_option(OptionNanoSecondsTimestampVisitor)?)
1235 }
1236
1237 struct OptionNanoSecondsTimestampVisitor;
1238
1239 impl<'de> de::Visitor<'de> for OptionNanoSecondsTimestampVisitor {
1240 type Value = Option<DateTime<Utc>>;
1241
1242 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result
1243 {
1244 formatter.write_str("a unix timestamp in nanoseconds or none")
1245 }
1246
1247 /// Deserialize a timestamp in seconds since the epoch
1248 fn visit_some<D>(self, d: D) -> Result<Option<DateTime<Utc>>, D::Error>
1249 where
1250 D: de::Deserializer<'de>,
1251 {
1252 d.deserialize_i64(NanoSecondsTimestampVisitor).map(|val| Some(val))
1253 }
1254
1255 /// Deserialize a timestamp in seconds since the epoch
1256 fn visit_none<E>(self) -> Result<Option<DateTime<Utc>>, E>
1257 where E: de::Error
1258 {
1259 Ok(None)
1260 }
1261 }
1262 }
1263
1264 /// Ser/de to/from timestamps in milliseconds
1265 ///
1266 /// Intended for use with `serde`s `with` attribute.
1267 ///
1268 /// # Example
1269 ///
1270 /// ```rust
1271 /// # // We mark this ignored so that we can test on 1.13 (which does not
1272 /// # // support custom derive), and run tests with --ignored on beta and
1273 /// # // nightly to actually trigger these.
1274 /// #
1275 /// # #[macro_use] extern crate serde_derive;
1276 /// # #[macro_use] extern crate serde_json;
1277 /// # extern crate chrono;
1278 /// # use chrono::{TimeZone, DateTime, Utc};
1279 /// use chrono::serde::ts_milliseconds;
1280 /// #[derive(Deserialize, Serialize)]
1281 /// struct S {
1282 /// #[serde(with = "ts_milliseconds")]
1283 /// time: DateTime<Utc>
1284 /// }
1285 ///
1286 /// # fn example() -> Result<S, serde_json::Error> {
1287 /// let time = Utc.ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918);
1288 /// let my_s = S {
1289 /// time: time.clone(),
1290 /// };
1291 ///
1292 /// let as_string = serde_json::to_string(&my_s)?;
1293 /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
1294 /// let my_s: S = serde_json::from_str(&as_string)?;
1295 /// assert_eq!(my_s.time, time);
1296 /// # Ok(my_s)
1297 /// # }
1298 /// # fn main() { example().unwrap(); }
1299 /// ```
1300 pub mod ts_milliseconds {
1301 use core::fmt;
1302 use serdelib::{ser, de};
1303
1304 use {DateTime, Utc};
1305 use offset::TimeZone;
1306
1307 use super::{serde_from, MilliSecondsTimestampVisitor};
1308
1309 /// Serialize a UTC datetime into an integer number of milliseconds since the epoch
1310 ///
1311 /// Intended for use with `serde`s `serialize_with` attribute.
1312 ///
1313 /// # Example:
1314 ///
1315 /// ```rust
1316 /// # // We mark this ignored so that we can test on 1.13 (which does not
1317 /// # // support custom derive), and run tests with --ignored on beta and
1318 /// # // nightly to actually trigger these.
1319 /// #
1320 /// # #[macro_use] extern crate serde_derive;
1321 /// # #[macro_use] extern crate serde_json;
1322 /// # extern crate chrono;
1323 /// # use chrono::{TimeZone, DateTime, Utc};
1324 /// use chrono::serde::ts_milliseconds::serialize as to_milli_ts;
1325 /// #[derive(Serialize)]
1326 /// struct S {
1327 /// #[serde(serialize_with = "to_milli_ts")]
1328 /// time: DateTime<Utc>
1329 /// }
1330 ///
1331 /// # fn example() -> Result<String, serde_json::Error> {
1332 /// let my_s = S {
1333 /// time: Utc.ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918),
1334 /// };
1335 /// let as_string = serde_json::to_string(&my_s)?;
1336 /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
1337 /// # Ok(as_string)
1338 /// # }
1339 /// # fn main() { example().unwrap(); }
1340 /// ```
1341 pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
1342 where S: ser::Serializer
1343 {
1344 serializer.serialize_i64(dt.timestamp_millis())
1345 }
1346
1347 /// Deserialize a `DateTime` from a millisecond timestamp
1348 ///
1349 /// Intended for use with `serde`s `deserialize_with` attribute.
1350 ///
1351 /// # Example:
1352 ///
1353 /// ```rust
1354 /// # // We mark this ignored so that we can test on 1.13 (which does not
1355 /// # // support custom derive), and run tests with --ignored on beta and
1356 /// # // nightly to actually trigger these.
1357 /// #
1358 /// # #[macro_use] extern crate serde_derive;
1359 /// # #[macro_use] extern crate serde_json;
1360 /// # extern crate chrono;
1361 /// # use chrono::{DateTime, Utc};
1362 /// use chrono::serde::ts_milliseconds::deserialize as from_milli_ts;
1363 /// #[derive(Deserialize)]
1364 /// struct S {
1365 /// #[serde(deserialize_with = "from_milli_ts")]
1366 /// time: DateTime<Utc>
1367 /// }
1368 ///
1369 /// # fn example() -> Result<S, serde_json::Error> {
1370 /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?;
1371 /// # Ok(my_s)
1372 /// # }
1373 /// # fn main() { example().unwrap(); }
1374 /// ```
1375 pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error>
1376 where D: de::Deserializer<'de>
1377 {
1378 Ok(d.deserialize_i64(MilliSecondsTimestampVisitor).map(|dt| dt.with_timezone(&Utc))?)
1379 }
1380
1381 impl<'de> de::Visitor<'de> for MilliSecondsTimestampVisitor {
1382 type Value = DateTime<Utc>;
1383
1384 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result
1385 {
1386 formatter.write_str("a unix timestamp in milliseconds")
1387 }
1388
1389 /// Deserialize a timestamp in milliseconds since the epoch
1390 fn visit_i64<E>(self, value: i64) -> Result<DateTime<Utc>, E>
1391 where E: de::Error
1392 {
1393 serde_from(Utc.timestamp_opt(value / 1000,
1394 ((value % 1000) * 1_000_000) as u32),
1395 &value)
1396 }
1397
1398 /// Deserialize a timestamp in milliseconds since the epoch
1399 fn visit_u64<E>(self, value: u64) -> Result<DateTime<Utc>, E>
1400 where E: de::Error
1401 {
1402 serde_from(Utc.timestamp_opt((value / 1000) as i64,
1403 ((value % 1000) * 1_000_000) as u32),
1404 &value)
1405 }
1406 }
1407 }
1408
1409 /// Ser/de to/from optional timestamps in milliseconds
1410 ///
1411 /// Intended for use with `serde`s `with` attribute.
1412 ///
1413 /// # Example
1414 ///
1415 /// ```rust
1416 /// # // We mark this ignored so that we can test on 1.13 (which does not
1417 /// # // support custom derive), and run tests with --ignored on beta and
1418 /// # // nightly to actually trigger these.
1419 /// #
1420 /// # #[macro_use] extern crate serde_derive;
1421 /// # #[macro_use] extern crate serde_json;
1422 /// # extern crate chrono;
1423 /// # use chrono::{TimeZone, DateTime, Utc};
1424 /// use chrono::serde::ts_milliseconds_option;
1425 /// #[derive(Deserialize, Serialize)]
1426 /// struct S {
1427 /// #[serde(with = "ts_milliseconds_option")]
1428 /// time: Option<DateTime<Utc>>
1429 /// }
1430 ///
1431 /// # fn example() -> Result<S, serde_json::Error> {
1432 /// let time = Some(Utc.ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918));
1433 /// let my_s = S {
1434 /// time: time.clone(),
1435 /// };
1436 ///
1437 /// let as_string = serde_json::to_string(&my_s)?;
1438 /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
1439 /// let my_s: S = serde_json::from_str(&as_string)?;
1440 /// assert_eq!(my_s.time, time);
1441 /// # Ok(my_s)
1442 /// # }
1443 /// # fn main() { example().unwrap(); }
1444 /// ```
1445 pub mod ts_milliseconds_option {
1446 use core::fmt;
1447 use serdelib::{ser, de};
1448
1449 use {DateTime, Utc};
1450
1451 use super::{ts_milliseconds, MilliSecondsTimestampVisitor};
1452
1453 /// Serialize a UTC datetime into an integer number of milliseconds since the epoch or none
1454 ///
1455 /// Intended for use with `serde`s `serialize_with` attribute.
1456 ///
1457 /// # Example:
1458 ///
1459 /// ```rust
1460 /// # // We mark this ignored so that we can test on 1.13 (which does not
1461 /// # // support custom derive), and run tests with --ignored on beta and
1462 /// # // nightly to actually trigger these.
1463 /// #
1464 /// # #[macro_use] extern crate serde_derive;
1465 /// # #[macro_use] extern crate serde_json;
1466 /// # extern crate chrono;
1467 /// # use chrono::{TimeZone, DateTime, Utc};
1468 /// use chrono::serde::ts_milliseconds_option::serialize as to_milli_tsopt;
1469 /// #[derive(Serialize)]
1470 /// struct S {
1471 /// #[serde(serialize_with = "to_milli_tsopt")]
1472 /// time: Option<DateTime<Utc>>
1473 /// }
1474 ///
1475 /// # fn example() -> Result<String, serde_json::Error> {
1476 /// let my_s = S {
1477 /// time: Some(Utc.ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918)),
1478 /// };
1479 /// let as_string = serde_json::to_string(&my_s)?;
1480 /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
1481 /// # Ok(as_string)
1482 /// # }
1483 /// # fn main() { example().unwrap(); }
1484 /// ```
1485 pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
1486 where S: ser::Serializer
1487 {
1488 match *opt {
1489 Some(ref dt) => ts_milliseconds::serialize(dt, serializer),
1490 None => serializer.serialize_none(),
1491 }
1492 }
1493
1494 /// Deserialize a `DateTime` from a millisecond timestamp or none
1495 ///
1496 /// Intended for use with `serde`s `deserialize_with` attribute.
1497 ///
1498 /// # Example:
1499 ///
1500 /// ```rust
1501 /// # // We mark this ignored so that we can test on 1.13 (which does not
1502 /// # // support custom derive), and run tests with --ignored on beta and
1503 /// # // nightly to actually trigger these.
1504 /// #
1505 /// # #[macro_use] extern crate serde_derive;
1506 /// # #[macro_use] extern crate serde_json;
1507 /// # extern crate chrono;
1508 /// # use chrono::{DateTime, Utc};
1509 /// use chrono::serde::ts_milliseconds_option::deserialize as from_milli_tsopt;
1510 /// #[derive(Deserialize)]
1511 /// struct S {
1512 /// #[serde(deserialize_with = "from_milli_tsopt")]
1513 /// time: Option<DateTime<Utc>>
1514 /// }
1515 ///
1516 /// # fn example() -> Result<S, serde_json::Error> {
1517 /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?;
1518 /// # Ok(my_s)
1519 /// # }
1520 /// # fn main() { example().unwrap(); }
1521 /// ```
1522 pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error>
1523 where D: de::Deserializer<'de>
1524 {
1525 Ok(d.deserialize_option(OptionMilliSecondsTimestampVisitor).map(|opt| opt.map(|dt| dt.with_timezone(&Utc)))?)
1526 }
1527
1528 struct OptionMilliSecondsTimestampVisitor;
1529
1530 impl<'de> de::Visitor<'de> for OptionMilliSecondsTimestampVisitor {
1531 type Value = Option<DateTime<Utc>>;
1532
1533 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result
1534 {
1535 formatter.write_str("a unix timestamp in milliseconds or none")
1536 }
1537
1538 /// Deserialize a timestamp in seconds since the epoch
1539 fn visit_some<D>(self, d: D) -> Result<Option<DateTime<Utc>>, D::Error>
1540 where
1541 D: de::Deserializer<'de>,
1542 {
1543 d.deserialize_i64(MilliSecondsTimestampVisitor).map(|val| Some(val))
1544 }
1545
1546 /// Deserialize a timestamp in seconds since the epoch
1547 fn visit_none<E>(self) -> Result<Option<DateTime<Utc>>, E>
1548 where E: de::Error
1549 {
1550 Ok(None)
1551 }
1552 }
1553 }
1554
1555 /// Ser/de to/from timestamps in seconds
1556 ///
1557 /// Intended for use with `serde`'s `with` attribute.
1558 ///
1559 /// # Example:
1560 ///
1561 /// ```rust
1562 /// # // We mark this ignored so that we can test on 1.13 (which does not
1563 /// # // support custom derive), and run tests with --ignored on beta and
1564 /// # // nightly to actually trigger these.
1565 /// #
1566 /// # #[macro_use] extern crate serde_derive;
1567 /// # #[macro_use] extern crate serde_json;
1568 /// # extern crate chrono;
1569 /// # use chrono::{TimeZone, DateTime, Utc};
1570 /// use chrono::serde::ts_seconds;
1571 /// #[derive(Deserialize, Serialize)]
1572 /// struct S {
1573 /// #[serde(with = "ts_seconds")]
1574 /// time: DateTime<Utc>
1575 /// }
1576 ///
1577 /// # fn example() -> Result<S, serde_json::Error> {
1578 /// let time = Utc.ymd(2015, 5, 15).and_hms(10, 0, 0);
1579 /// let my_s = S {
1580 /// time: time.clone(),
1581 /// };
1582 ///
1583 /// let as_string = serde_json::to_string(&my_s)?;
1584 /// assert_eq!(as_string, r#"{"time":1431684000}"#);
1585 /// let my_s: S = serde_json::from_str(&as_string)?;
1586 /// assert_eq!(my_s.time, time);
1587 /// # Ok(my_s)
1588 /// # }
1589 /// # fn main() { example().unwrap(); }
1590 /// ```
1591 pub mod ts_seconds {
1592 use core::fmt;
1593 use serdelib::{ser, de};
1594
1595 use {DateTime, Utc};
1596 use offset::TimeZone;
1597
1598 use super::{serde_from, SecondsTimestampVisitor};
1599
1600 /// Serialize a UTC datetime into an integer number of seconds since the epoch
1601 ///
1602 /// Intended for use with `serde`s `serialize_with` attribute.
1603 ///
1604 /// # Example:
1605 ///
1606 /// ```rust
1607 /// # // We mark this ignored so that we can test on 1.13 (which does not
1608 /// # // support custom derive), and run tests with --ignored on beta and
1609 /// # // nightly to actually trigger these.
1610 /// #
1611 /// # #[macro_use] extern crate serde_derive;
1612 /// # #[macro_use] extern crate serde_json;
1613 /// # extern crate chrono;
1614 /// # use chrono::{TimeZone, DateTime, Utc};
1615 /// use chrono::serde::ts_seconds::serialize as to_ts;
1616 /// #[derive(Serialize)]
1617 /// struct S {
1618 /// #[serde(serialize_with = "to_ts")]
1619 /// time: DateTime<Utc>
1620 /// }
1621 ///
1622 /// # fn example() -> Result<String, serde_json::Error> {
1623 /// let my_s = S {
1624 /// time: Utc.ymd(2015, 5, 15).and_hms(10, 0, 0),
1625 /// };
1626 /// let as_string = serde_json::to_string(&my_s)?;
1627 /// assert_eq!(as_string, r#"{"time":1431684000}"#);
1628 /// # Ok(as_string)
1629 /// # }
1630 /// # fn main() { example().unwrap(); }
1631 /// ```
1632 pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
1633 where S: ser::Serializer
1634 {
1635 serializer.serialize_i64(dt.timestamp())
1636 }
1637
1638 /// Deserialize a `DateTime` from a seconds timestamp
1639 ///
1640 /// Intended for use with `serde`s `deserialize_with` attribute.
1641 ///
1642 /// # Example:
1643 ///
1644 /// ```rust
1645 /// # // We mark this ignored so that we can test on 1.13 (which does not
1646 /// # // support custom derive), and run tests with --ignored on beta and
1647 /// # // nightly to actually trigger these.
1648 /// #
1649 /// # #[macro_use] extern crate serde_derive;
1650 /// # #[macro_use] extern crate serde_json;
1651 /// # extern crate chrono;
1652 /// # use chrono::{DateTime, Utc};
1653 /// use chrono::serde::ts_seconds::deserialize as from_ts;
1654 /// #[derive(Deserialize)]
1655 /// struct S {
1656 /// #[serde(deserialize_with = "from_ts")]
1657 /// time: DateTime<Utc>
1658 /// }
1659 ///
1660 /// # fn example() -> Result<S, serde_json::Error> {
1661 /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?;
1662 /// # Ok(my_s)
1663 /// # }
1664 /// # fn main() { example().unwrap(); }
1665 /// ```
1666 pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error>
1667 where D: de::Deserializer<'de>
1668 {
1669 Ok(d.deserialize_i64(SecondsTimestampVisitor)?)
1670 }
1671
1672 impl<'de> de::Visitor<'de> for SecondsTimestampVisitor {
1673 type Value = DateTime<Utc>;
1674
1675 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result
1676 {
1677 formatter.write_str("a unix timestamp in seconds")
1678 }
1679
1680 /// Deserialize a timestamp in seconds since the epoch
1681 fn visit_i64<E>(self, value: i64) -> Result<DateTime<Utc>, E>
1682 where E: de::Error
1683 {
1684 serde_from(Utc.timestamp_opt(value, 0), &value)
1685 }
1686
1687 /// Deserialize a timestamp in seconds since the epoch
1688 fn visit_u64<E>(self, value: u64) -> Result<DateTime<Utc>, E>
1689 where E: de::Error
1690 {
1691 serde_from(Utc.timestamp_opt(value as i64, 0), &value)
1692 }
1693 }
1694 }
1695
1696 /// Ser/de to/from optional timestamps in seconds
1697 ///
1698 /// Intended for use with `serde`'s `with` attribute.
1699 ///
1700 /// # Example:
1701 ///
1702 /// ```rust
1703 /// # // We mark this ignored so that we can test on 1.13 (which does not
1704 /// # // support custom derive), and run tests with --ignored on beta and
1705 /// # // nightly to actually trigger these.
1706 /// #
1707 /// # #[macro_use] extern crate serde_derive;
1708 /// # #[macro_use] extern crate serde_json;
1709 /// # extern crate chrono;
1710 /// # use chrono::{TimeZone, DateTime, Utc};
1711 /// use chrono::serde::ts_seconds_option;
1712 /// #[derive(Deserialize, Serialize)]
1713 /// struct S {
1714 /// #[serde(with = "ts_seconds_option")]
1715 /// time: Option<DateTime<Utc>>
1716 /// }
1717 ///
1718 /// # fn example() -> Result<S, serde_json::Error> {
1719 /// let time = Some(Utc.ymd(2015, 5, 15).and_hms(10, 0, 0));
1720 /// let my_s = S {
1721 /// time: time.clone(),
1722 /// };
1723 ///
1724 /// let as_string = serde_json::to_string(&my_s)?;
1725 /// assert_eq!(as_string, r#"{"time":1431684000}"#);
1726 /// let my_s: S = serde_json::from_str(&as_string)?;
1727 /// assert_eq!(my_s.time, time);
1728 /// # Ok(my_s)
1729 /// # }
1730 /// # fn main() { example().unwrap(); }
1731 /// ```
1732 pub mod ts_seconds_option {
1733 use core::fmt;
1734 use serdelib::{ser, de};
1735
1736 use {DateTime, Utc};
1737
1738 use super::{ts_seconds, SecondsTimestampVisitor};
1739
1740 /// Serialize a UTC datetime into an integer number of seconds since the epoch or none
1741 ///
1742 /// Intended for use with `serde`s `serialize_with` attribute.
1743 ///
1744 /// # Example:
1745 ///
1746 /// ```rust
1747 /// # // We mark this ignored so that we can test on 1.13 (which does not
1748 /// # // support custom derive), and run tests with --ignored on beta and
1749 /// # // nightly to actually trigger these.
1750 /// #
1751 /// # #[macro_use] extern crate serde_derive;
1752 /// # #[macro_use] extern crate serde_json;
1753 /// # extern crate chrono;
1754 /// # use chrono::{TimeZone, DateTime, Utc};
1755 /// use chrono::serde::ts_seconds_option::serialize as to_tsopt;
1756 /// #[derive(Serialize)]
1757 /// struct S {
1758 /// #[serde(serialize_with = "to_tsopt")]
1759 /// time: Option<DateTime<Utc>>
1760 /// }
1761 ///
1762 /// # fn example() -> Result<String, serde_json::Error> {
1763 /// let my_s = S {
1764 /// time: Some(Utc.ymd(2015, 5, 15).and_hms(10, 0, 0)),
1765 /// };
1766 /// let as_string = serde_json::to_string(&my_s)?;
1767 /// assert_eq!(as_string, r#"{"time":1431684000}"#);
1768 /// # Ok(as_string)
1769 /// # }
1770 /// # fn main() { example().unwrap(); }
1771 /// ```
1772 pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
1773 where S: ser::Serializer
1774 {
1775 match *opt {
1776 Some(ref dt) => ts_seconds::serialize(dt, serializer),
1777 None => serializer.serialize_none(),
1778 }
1779 }
1780
1781 /// Deserialize a `DateTime` from a seconds timestamp or none
1782 ///
1783 /// Intended for use with `serde`s `deserialize_with` attribute.
1784 ///
1785 /// # Example:
1786 ///
1787 /// ```rust
1788 /// # // We mark this ignored so that we can test on 1.13 (which does not
1789 /// # // support custom derive), and run tests with --ignored on beta and
1790 /// # // nightly to actually trigger these.
1791 /// #
1792 /// # #[macro_use] extern crate serde_derive;
1793 /// # #[macro_use] extern crate serde_json;
1794 /// # extern crate chrono;
1795 /// # use chrono::{DateTime, Utc};
1796 /// use chrono::serde::ts_seconds_option::deserialize as from_tsopt;
1797 /// #[derive(Deserialize)]
1798 /// struct S {
1799 /// #[serde(deserialize_with = "from_tsopt")]
1800 /// time: Option<DateTime<Utc>>
1801 /// }
1802 ///
1803 /// # fn example() -> Result<S, serde_json::Error> {
1804 /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?;
1805 /// # Ok(my_s)
1806 /// # }
1807 /// # fn main() { example().unwrap(); }
1808 /// ```
1809 pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error>
1810 where D: de::Deserializer<'de>
1811 {
1812 Ok(d.deserialize_option(OptionSecondsTimestampVisitor)?)
1813 }
1814
1815 struct OptionSecondsTimestampVisitor;
1816
1817 impl<'de> de::Visitor<'de> for OptionSecondsTimestampVisitor {
1818 type Value = Option<DateTime<Utc>>;
1819
1820 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result
1821 {
1822 formatter.write_str("a unix timestamp in seconds or none")
1823 }
1824
1825 /// Deserialize a timestamp in seconds since the epoch
1826 fn visit_some<D>(self, d: D) -> Result<Option<DateTime<Utc>>, D::Error>
1827 where
1828 D: de::Deserializer<'de>,
1829 {
1830 d.deserialize_i64(SecondsTimestampVisitor).map(|val| Some(val))
1831 }
1832
1833 /// Deserialize a timestamp in seconds since the epoch
1834 fn visit_none<E>(self) -> Result<Option<DateTime<Utc>>, E>
1835 where E: de::Error
1836 {
1837 Ok(None)
1838 }
1839 }
1840 }
1841
1842 impl<Tz: TimeZone> ser::Serialize for DateTime<Tz> {
1843 /// Serialize into a rfc3339 time string
1844 ///
1845 /// See [the `serde` module](./serde/index.html) for alternate
1846 /// serializations.
1847 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1848 where S: ser::Serializer
1849 {
1850 struct FormatWrapped<'a, D: 'a> {
1851 inner: &'a D
1852 }
1853
1854 impl<'a, D: fmt::Debug> fmt::Display for FormatWrapped<'a, D> {
1855 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1856 self.inner.fmt(f)
1857 }
1858 }
1859
1860 // Debug formatting is correct RFC3339, and it allows Zulu.
1861 serializer.collect_str(&FormatWrapped { inner: &self })
1862 }
1863 }
1864
1865 struct DateTimeVisitor;
1866
1867 impl<'de> de::Visitor<'de> for DateTimeVisitor {
1868 type Value = DateTime<FixedOffset>;
1869
1870 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result
1871 {
1872 write!(formatter, "a formatted date and time string or a unix timestamp")
1873 }
1874
1875 fn visit_str<E>(self, value: &str) -> Result<DateTime<FixedOffset>, E>
1876 where E: de::Error
1877 {
1878 value.parse().map_err(|err: ::format::ParseError| E::custom(err))
1879 }
1880 }
1881
1882 /// Deserialize a value that optionally includes a timezone offset in its
1883 /// string representation
1884 ///
1885 /// The value to be deserialized must be an rfc3339 string.
1886 ///
1887 /// See [the `serde` module](./serde/index.html) for alternate
1888 /// deserialization formats.
1889 impl<'de> de::Deserialize<'de> for DateTime<FixedOffset> {
1890 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1891 where D: de::Deserializer<'de>
1892 {
1893 deserializer.deserialize_str(DateTimeVisitor)
1894 }
1895 }
1896
1897 /// Deserialize into a UTC value
1898 ///
1899 /// The value to be deserialized must be an rfc3339 string.
1900 ///
1901 /// See [the `serde` module](./serde/index.html) for alternate
1902 /// deserialization formats.
1903 impl<'de> de::Deserialize<'de> for DateTime<Utc> {
1904 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1905 where D: de::Deserializer<'de>
1906 {
1907 deserializer.deserialize_str(DateTimeVisitor).map(|dt| dt.with_timezone(&Utc))
1908 }
1909 }
1910
1911 /// Deserialize a value that includes no timezone in its string
1912 /// representation
1913 ///
1914 /// The value to be deserialized must be an rfc3339 string.
1915 ///
1916 /// See [the `serde` module](./serde/index.html) for alternate
1917 /// serialization formats.
1918 #[cfg(feature="clock")]
1919 impl<'de> de::Deserialize<'de> for DateTime<Local> {
1920 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1921 where D: de::Deserializer<'de>
1922 {
1923 deserializer.deserialize_str(DateTimeVisitor).map(|dt| dt.with_timezone(&Local))
1924 }
1925 }
1926
1927 #[cfg(test)] extern crate serde_json;
1928 #[cfg(test)] extern crate bincode;
1929
1930 #[test]
1931 fn test_serde_serialize() {
1932 super::test_encodable_json(self::serde_json::to_string, self::serde_json::to_string);
1933 }
1934
1935 #[cfg(feature="clock")]
1936 #[test]
1937 fn test_serde_deserialize() {
1938 super::test_decodable_json(|input| self::serde_json::from_str(&input), |input| self::serde_json::from_str(&input),
1939 |input| self::serde_json::from_str(&input));
1940 }
1941
1942 #[test]
1943 fn test_serde_bincode() {
1944 // Bincode is relevant to test separately from JSON because
1945 // it is not self-describing.
1946 use self::bincode::{Infinite, serialize, deserialize};
1947
1948 let dt = Utc.ymd(2014, 7, 24).and_hms(12, 34, 6);
1949 let encoded = serialize(&dt, Infinite).unwrap();
1950 let decoded: DateTime<Utc> = deserialize(&encoded).unwrap();
1951 assert_eq!(dt, decoded);
1952 assert_eq!(dt.offset(), decoded.offset());
1953 }
1954}
1955
1956#[cfg(test)]
1957mod tests {
1958 use super::DateTime;
1959 #[cfg(feature="clock")]
1960 use Datelike;
1961 use naive::{NaiveTime, NaiveDate};
1962 #[cfg(feature="clock")]
1963 use offset::Local;
1964 use offset::{TimeZone, Utc, FixedOffset};
1965 use oldtime::Duration;
1966 use std::time::{SystemTime, UNIX_EPOCH};
1967
1968 #[test]
1969 #[allow(non_snake_case)]
1970 fn test_datetime_offset() {
1971 let Est = FixedOffset::west(5*60*60);
1972 let Edt = FixedOffset::west(4*60*60);
1973 let Kst = FixedOffset::east(9*60*60);
1974
1975 assert_eq!(format!("{}", Utc.ymd(2014, 5, 6).and_hms(7, 8, 9)),
1976 "2014-05-06 07:08:09 UTC");
1977 assert_eq!(format!("{}", Edt.ymd(2014, 5, 6).and_hms(7, 8, 9)),
1978 "2014-05-06 07:08:09 -04:00");
1979 assert_eq!(format!("{}", Kst.ymd(2014, 5, 6).and_hms(7, 8, 9)),
1980 "2014-05-06 07:08:09 +09:00");
1981 assert_eq!(format!("{:?}", Utc.ymd(2014, 5, 6).and_hms(7, 8, 9)),
1982 "2014-05-06T07:08:09Z");
1983 assert_eq!(format!("{:?}", Edt.ymd(2014, 5, 6).and_hms(7, 8, 9)),
1984 "2014-05-06T07:08:09-04:00");
1985 assert_eq!(format!("{:?}", Kst.ymd(2014, 5, 6).and_hms(7, 8, 9)),
1986 "2014-05-06T07:08:09+09:00");
1987
1988 // edge cases
1989 assert_eq!(format!("{:?}", Utc.ymd(2014, 5, 6).and_hms(0, 0, 0)),
1990 "2014-05-06T00:00:00Z");
1991 assert_eq!(format!("{:?}", Edt.ymd(2014, 5, 6).and_hms(0, 0, 0)),
1992 "2014-05-06T00:00:00-04:00");
1993 assert_eq!(format!("{:?}", Kst.ymd(2014, 5, 6).and_hms(0, 0, 0)),
1994 "2014-05-06T00:00:00+09:00");
1995 assert_eq!(format!("{:?}", Utc.ymd(2014, 5, 6).and_hms(23, 59, 59)),
1996 "2014-05-06T23:59:59Z");
1997 assert_eq!(format!("{:?}", Edt.ymd(2014, 5, 6).and_hms(23, 59, 59)),
1998 "2014-05-06T23:59:59-04:00");
1999 assert_eq!(format!("{:?}", Kst.ymd(2014, 5, 6).and_hms(23, 59, 59)),
2000 "2014-05-06T23:59:59+09:00");
2001
2002 let dt = Utc.ymd(2014, 5, 6).and_hms(7, 8, 9);
2003 assert_eq!(dt, Edt.ymd(2014, 5, 6).and_hms(3, 8, 9));
2004 assert_eq!(dt + Duration::seconds(3600 + 60 + 1), Utc.ymd(2014, 5, 6).and_hms(8, 9, 10));
2005 assert_eq!(dt.signed_duration_since(Edt.ymd(2014, 5, 6).and_hms(10, 11, 12)),
2006 Duration::seconds(-7*3600 - 3*60 - 3));
2007
2008 assert_eq!(*Utc.ymd(2014, 5, 6).and_hms(7, 8, 9).offset(), Utc);
2009 assert_eq!(*Edt.ymd(2014, 5, 6).and_hms(7, 8, 9).offset(), Edt);
2010 assert!(*Edt.ymd(2014, 5, 6).and_hms(7, 8, 9).offset() != Est);
2011 }
2012
2013 #[test]
2014 fn test_datetime_date_and_time() {
2015 let tz = FixedOffset::east(5*60*60);
2016 let d = tz.ymd(2014, 5, 6).and_hms(7, 8, 9);
2017 assert_eq!(d.time(), NaiveTime::from_hms(7, 8, 9));
2018 assert_eq!(d.date(), tz.ymd(2014, 5, 6));
2019 assert_eq!(d.date().naive_local(), NaiveDate::from_ymd(2014, 5, 6));
2020 assert_eq!(d.date().and_time(d.time()), Some(d));
2021
2022 let tz = FixedOffset::east(4*60*60);
2023 let d = tz.ymd(2016, 5, 4).and_hms(3, 2, 1);
2024 assert_eq!(d.time(), NaiveTime::from_hms(3, 2, 1));
2025 assert_eq!(d.date(), tz.ymd(2016, 5, 4));
2026 assert_eq!(d.date().naive_local(), NaiveDate::from_ymd(2016, 5, 4));
2027 assert_eq!(d.date().and_time(d.time()), Some(d));
2028
2029 let tz = FixedOffset::west(13*60*60);
2030 let d = tz.ymd(2017, 8, 9).and_hms(12, 34, 56);
2031 assert_eq!(d.time(), NaiveTime::from_hms(12, 34, 56));
2032 assert_eq!(d.date(), tz.ymd(2017, 8, 9));
2033 assert_eq!(d.date().naive_local(), NaiveDate::from_ymd(2017, 8, 9));
2034 assert_eq!(d.date().and_time(d.time()), Some(d));
2035 }
2036
2037 #[test]
2038 #[cfg(feature="clock")]
2039 fn test_datetime_with_timezone() {
2040 let local_now = Local::now();
2041 let utc_now = local_now.with_timezone(&Utc);
2042 let local_now2 = utc_now.with_timezone(&Local);
2043 assert_eq!(local_now, local_now2);
2044 }
2045
2046 #[test]
2047 #[allow(non_snake_case)]
2048 fn test_datetime_rfc2822_and_rfc3339() {
2049 let EDT = FixedOffset::east(5*60*60);
2050 assert_eq!(Utc.ymd(2015, 2, 18).and_hms(23, 16, 9).to_rfc2822(),
2051 "Wed, 18 Feb 2015 23:16:09 +0000");
2052 assert_eq!(Utc.ymd(2015, 2, 18).and_hms(23, 16, 9).to_rfc3339(),
2053 "2015-02-18T23:16:09+00:00");
2054 assert_eq!(EDT.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150).to_rfc2822(),
2055 "Wed, 18 Feb 2015 23:16:09 +0500");
2056 assert_eq!(EDT.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150).to_rfc3339(),
2057 "2015-02-18T23:16:09.150+05:00");
2058 assert_eq!(EDT.ymd(2015, 2, 18).and_hms_micro(23, 59, 59, 1_234_567).to_rfc2822(),
2059 "Wed, 18 Feb 2015 23:59:60 +0500");
2060 assert_eq!(EDT.ymd(2015, 2, 18).and_hms_micro(23, 59, 59, 1_234_567).to_rfc3339(),
2061 "2015-02-18T23:59:60.234567+05:00");
2062
2063 assert_eq!(DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 +0000"),
2064 Ok(FixedOffset::east(0).ymd(2015, 2, 18).and_hms(23, 16, 9)));
2065 assert_eq!(DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 -0000"),
2066 Ok(FixedOffset::east(0).ymd(2015, 2, 18).and_hms(23, 16, 9)));
2067 assert_eq!(DateTime::parse_from_rfc3339("2015-02-18T23:16:09Z"),
2068 Ok(FixedOffset::east(0).ymd(2015, 2, 18).and_hms(23, 16, 9)));
2069 assert_eq!(DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:59:60 +0500"),
2070 Ok(EDT.ymd(2015, 2, 18).and_hms_milli(23, 59, 59, 1_000)));
2071 assert_eq!(DateTime::parse_from_rfc3339("2015-02-18T23:59:60.234567+05:00"),
2072 Ok(EDT.ymd(2015, 2, 18).and_hms_micro(23, 59, 59, 1_234_567)));
2073 }
2074
2075 #[test]
2076 fn test_rfc3339_opts() {
2077 use SecondsFormat::*;
2078 let pst = FixedOffset::east(8 * 60 * 60);
2079 let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_000);
2080 assert_eq!(dt.to_rfc3339_opts(Secs, false), "2018-01-11T10:05:13+08:00");
2081 assert_eq!(dt.to_rfc3339_opts(Secs, true), "2018-01-11T10:05:13+08:00");
2082 assert_eq!(dt.to_rfc3339_opts(Millis, false), "2018-01-11T10:05:13.084+08:00");
2083 assert_eq!(dt.to_rfc3339_opts(Micros, false), "2018-01-11T10:05:13.084660+08:00");
2084 assert_eq!(dt.to_rfc3339_opts(Nanos, false), "2018-01-11T10:05:13.084660000+08:00");
2085 assert_eq!(dt.to_rfc3339_opts(AutoSi, false), "2018-01-11T10:05:13.084660+08:00");
2086
2087 let ut = DateTime::<Utc>::from_utc(dt.naive_utc(), Utc);
2088 assert_eq!(ut.to_rfc3339_opts(Secs, false), "2018-01-11T02:05:13+00:00");
2089 assert_eq!(ut.to_rfc3339_opts(Secs, true), "2018-01-11T02:05:13Z");
2090 assert_eq!(ut.to_rfc3339_opts(Millis, false), "2018-01-11T02:05:13.084+00:00");
2091 assert_eq!(ut.to_rfc3339_opts(Millis, true), "2018-01-11T02:05:13.084Z");
2092 assert_eq!(ut.to_rfc3339_opts(Micros, true), "2018-01-11T02:05:13.084660Z");
2093 assert_eq!(ut.to_rfc3339_opts(Nanos, true), "2018-01-11T02:05:13.084660000Z");
2094 assert_eq!(ut.to_rfc3339_opts(AutoSi, true), "2018-01-11T02:05:13.084660Z");
2095 }
2096
2097 #[test]
2098 #[should_panic]
2099 fn test_rfc3339_opts_nonexhaustive() {
2100 use SecondsFormat;
2101 let dt = Utc.ymd(1999, 10, 9).and_hms(1, 2, 3);
2102 dt.to_rfc3339_opts(SecondsFormat::__NonExhaustive, true);
2103 }
2104
2105 #[test]
2106 fn test_datetime_from_str() {
2107 assert_eq!("2015-2-18T23:16:9.15Z".parse::<DateTime<FixedOffset>>(),
2108 Ok(FixedOffset::east(0).ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150)));
2109 assert_eq!("2015-2-18T13:16:9.15-10:00".parse::<DateTime<FixedOffset>>(),
2110 Ok(FixedOffset::west(10 * 3600).ymd(2015, 2, 18).and_hms_milli(13, 16, 9, 150)));
2111 assert!("2015-2-18T23:16:9.15".parse::<DateTime<FixedOffset>>().is_err());
2112
2113 assert_eq!("2015-2-18T23:16:9.15Z".parse::<DateTime<Utc>>(),
2114 Ok(Utc.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150)));
2115 assert_eq!("2015-2-18T13:16:9.15-10:00".parse::<DateTime<Utc>>(),
2116 Ok(Utc.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150)));
2117 assert!("2015-2-18T23:16:9.15".parse::<DateTime<Utc>>().is_err());
2118
2119 // no test for `DateTime<Local>`, we cannot verify that much.
2120 }
2121
2122 #[test]
2123 fn test_datetime_parse_from_str() {
2124 let ymdhms = |y,m,d,h,n,s,off| FixedOffset::east(off).ymd(y,m,d).and_hms(h,n,s);
2125 assert_eq!(DateTime::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
2126 Ok(ymdhms(2014, 5, 7, 12, 34, 56, 570*60))); // ignore offset
2127 assert!(DateTime::parse_from_str("20140507000000", "%Y%m%d%H%M%S").is_err()); // no offset
2128 assert!(DateTime::parse_from_str("Fri, 09 Aug 2013 23:54:35 GMT",
2129 "%a, %d %b %Y %H:%M:%S GMT").is_err());
2130 assert_eq!(Utc.datetime_from_str("Fri, 09 Aug 2013 23:54:35 GMT",
2131 "%a, %d %b %Y %H:%M:%S GMT"),
2132 Ok(Utc.ymd(2013, 8, 9).and_hms(23, 54, 35)));
2133 }
2134
2135 #[test]
2136 #[cfg(feature="clock")]
2137 fn test_datetime_format_with_local() {
2138 // if we are not around the year boundary, local and UTC date should have the same year
2139 let dt = Local::now().with_month(5).unwrap();
2140 assert_eq!(dt.format("%Y").to_string(), dt.with_timezone(&Utc).format("%Y").to_string());
2141 }
2142
2143 #[test]
2144 #[cfg(feature="clock")]
2145 fn test_datetime_is_copy() {
2146 // UTC is known to be `Copy`.
2147 let a = Utc::now();
2148 let b = a;
2149 assert_eq!(a, b);
2150 }
2151
2152 #[test]
2153 #[cfg(feature="clock")]
2154 fn test_datetime_is_send() {
2155 use std::thread;
2156
2157 // UTC is known to be `Send`.
2158 let a = Utc::now();
2159 thread::spawn(move || {
2160 let _ = a;
2161 }).join().unwrap();
2162 }
2163
2164 #[test]
2165 fn test_subsecond_part() {
2166 let datetime = Utc.ymd(2014, 7, 8).and_hms_nano(9, 10, 11, 1234567);
2167
2168 assert_eq!(1, datetime.timestamp_subsec_millis());
2169 assert_eq!(1234, datetime.timestamp_subsec_micros());
2170 assert_eq!(1234567, datetime.timestamp_subsec_nanos());
2171 }
2172
2173 #[test]
2174 fn test_from_system_time() {
2175 use std::time::Duration;
2176
2177 let epoch = Utc.ymd(1970, 1, 1).and_hms(0, 0, 0);
2178
2179 // SystemTime -> DateTime<Utc>
2180 assert_eq!(DateTime::<Utc>::from(UNIX_EPOCH), epoch);
2181 assert_eq!(DateTime::<Utc>::from(UNIX_EPOCH + Duration::new(999_999_999, 999_999_999)),
2182 Utc.ymd(2001, 9, 9).and_hms_nano(1, 46, 39, 999_999_999));
2183 assert_eq!(DateTime::<Utc>::from(UNIX_EPOCH - Duration::new(999_999_999, 999_999_999)),
2184 Utc.ymd(1938, 4, 24).and_hms_nano(22, 13, 20, 1));
2185
2186 // DateTime<Utc> -> SystemTime
2187 assert_eq!(SystemTime::from(epoch), UNIX_EPOCH);
2188 assert_eq!(SystemTime::from(Utc.ymd(2001, 9, 9).and_hms_nano(1, 46, 39, 999_999_999)),
2189 UNIX_EPOCH + Duration::new(999_999_999, 999_999_999));
2190 assert_eq!(SystemTime::from(Utc.ymd(1938, 4, 24).and_hms_nano(22, 13, 20, 1)),
2191 UNIX_EPOCH - Duration::new(999_999_999, 999_999_999));
2192
2193 // DateTime<any tz> -> SystemTime (via `with_timezone`)
2194 #[cfg(feature="clock")] {
2195 assert_eq!(SystemTime::from(epoch.with_timezone(&Local)), UNIX_EPOCH);
2196 }
2197 assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::east(32400))), UNIX_EPOCH);
2198 assert_eq!(SystemTime::from(epoch.with_timezone(&FixedOffset::west(28800))), UNIX_EPOCH);
2199 }
2200
2201 #[test]
2202 fn test_datetime_format_alignment() {
2203 let datetime = Utc.ymd(2007, 01, 02);
2204
2205 // Item::Literal
2206 let percent = datetime.format("%%");
2207 assert_eq!(" %", format!("{:>3}", percent));
2208 assert_eq!("% ", format!("{:<3}", percent));
2209 assert_eq!(" % ", format!("{:^3}", percent));
2210
2211 // Item::Numeric
2212 let year = datetime.format("%Y");
2213 assert_eq!(" 2007", format!("{:>6}", year));
2214 assert_eq!("2007 ", format!("{:<6}", year));
2215 assert_eq!(" 2007 ", format!("{:^6}", year));
2216
2217 // Item::Fixed
2218 let tz = datetime.format("%Z");
2219 assert_eq!(" UTC", format!("{:>5}", tz));
2220 assert_eq!("UTC ", format!("{:<5}", tz));
2221 assert_eq!(" UTC ", format!("{:^5}", tz));
2222
2223 // [Item::Numeric, Item::Space, Item::Literal, Item::Space, Item::Numeric]
2224 let ymd = datetime.format("%Y %B %d");
2225 let ymd_formatted = "2007 January 02";
2226 assert_eq!(format!(" {}", ymd_formatted), format!("{:>17}", ymd));
2227 assert_eq!(format!("{} ", ymd_formatted), format!("{:<17}", ymd));
2228 assert_eq!(format!(" {} ", ymd_formatted), format!("{:^17}", ymd));
2229 }
2230
2231}