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