1 // This is a part of Chrono.
2 // See README.md and LICENSE.txt for details.
4 //! ISO 8601 date and time with time zone.
6 use std
::{str, fmt, hash}
;
7 use std
::cmp
::Ordering
;
8 use std
::ops
::{Add, Sub}
;
9 use std
::time
::{SystemTime, UNIX_EPOCH}
;
10 use oldtime
::Duration
as OldDuration
;
12 use {Weekday, Timelike, Datelike}
;
13 #[cfg(feature="clock")]
15 use offset
::{TimeZone, Offset, Utc, FixedOffset}
;
16 use naive
::{NaiveTime, NaiveDateTime, IsoWeek}
;
18 use format
::{Item, Numeric, Pad, Fixed}
;
19 use format
::{parse, Parsed, ParseError, ParseResult, DelayedFormat, StrftimeItems}
;
21 /// Specific formatting options for seconds. This may be extended in the
22 /// future, so exhaustive matching in external code is not recommended.
24 /// See the `TimeZone::to_rfc3339_opts` function for usage.
25 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
26 pub enum SecondsFormat
{
27 /// Format whole seconds only, with no decimal point nor subseconds.
30 /// Use fixed 3 subsecond digits. This corresponds to
31 /// [Fixed::Nanosecond3](format/enum.Fixed.html#variant.Nanosecond3).
34 /// Use fixed 6 subsecond digits. This corresponds to
35 /// [Fixed::Nanosecond6](format/enum.Fixed.html#variant.Nanosecond6).
38 /// Use fixed 9 subsecond digits. This corresponds to
39 /// [Fixed::Nanosecond9](format/enum.Fixed.html#variant.Nanosecond9).
42 /// Automatically select one of `Secs`, `Millis`, `Micros`, or `Nanos` to
43 /// display all available non-zero sub-second digits. This corresponds to
44 /// [Fixed::Nanosecond](format/enum.Fixed.html#variant.Nanosecond).
47 // Do not match against this.
52 /// ISO 8601 combined date and time with time zone.
54 /// There are some constructors implemented here (the `from_*` methods), but
55 /// the general-purpose constructors are all via the methods on the
56 /// [`TimeZone`](./offset/trait.TimeZone.html) implementations.
58 pub struct DateTime
<Tz
: TimeZone
> {
59 datetime
: NaiveDateTime
,
63 impl<Tz
: TimeZone
> DateTime
<Tz
> {
64 /// Makes a new `DateTime` with given *UTC* datetime and offset.
65 /// The local datetime should be constructed via the `TimeZone` trait.
70 /// use chrono::{DateTime, TimeZone, NaiveDateTime, Utc};
72 /// let dt = DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(61, 0), Utc);
73 /// assert_eq!(Utc.timestamp(61, 0), dt);
76 // note: this constructor is purposedly not named to `new` to discourage the direct usage.
78 pub fn from_utc(datetime
: NaiveDateTime
, offset
: Tz
::Offset
) -> DateTime
<Tz
> {
79 DateTime { datetime: datetime, offset: offset }
82 /// Retrieves a date component.
84 pub fn date(&self) -> Date
<Tz
> {
85 Date
::from_utc(self.naive_local().date(), self.offset
.clone())
88 /// Retrieves a time component.
89 /// Unlike `date`, this is not associated to the time zone.
91 pub fn time(&self) -> NaiveTime
{
92 self.datetime
.time() + self.offset
.fix()
95 /// Returns the number of non-leap seconds since January 1, 1970 0:00:00 UTC
96 /// (aka "UNIX timestamp").
98 pub fn timestamp(&self) -> i64 {
99 self.datetime
.timestamp()
102 /// Returns the number of non-leap-milliseconds since January 1, 1970 UTC
104 /// Note that this does reduce the number of years that can be represented
105 /// from ~584 Billion to ~584 Million. (If this is a problem, please file
106 /// an issue to let me know what domain needs millisecond precision over
107 /// billions of years, I'm curious.)
113 /// use chrono::TimeZone;
115 /// let dt = Utc.ymd(1970, 1, 1).and_hms_milli(0, 0, 1, 444);
116 /// assert_eq!(dt.timestamp_millis(), 1_444);
118 /// let dt = Utc.ymd(2001, 9, 9).and_hms_milli(1, 46, 40, 555);
119 /// assert_eq!(dt.timestamp_millis(), 1_000_000_000_555);
122 pub fn timestamp_millis(&self) -> i64 {
123 self.datetime
.timestamp_millis()
126 /// Returns the number of non-leap-nanoseconds since January 1, 1970 UTC
128 /// Note that this does reduce the number of years that can be represented
129 /// from ~584 Billion to ~584. (If this is a problem, please file
130 /// an issue to let me know what domain needs nanosecond precision over
131 /// millenia, I'm curious.)
137 /// use chrono::TimeZone;
139 /// let dt = Utc.ymd(1970, 1, 1).and_hms_nano(0, 0, 1, 444);
140 /// assert_eq!(dt.timestamp_nanos(), 1_000_000_444);
142 /// let dt = Utc.ymd(2001, 9, 9).and_hms_nano(1, 46, 40, 555);
143 /// assert_eq!(dt.timestamp_nanos(), 1_000_000_000_000_000_555);
146 pub fn timestamp_nanos(&self) -> i64 {
147 self.datetime
.timestamp_nanos()
150 /// Returns the number of milliseconds since the last second boundary
152 /// warning: in event of a leap second, this may exceed 999
154 /// note: this is not the number of milliseconds since January 1, 1970 0:00:00 UTC
156 pub fn timestamp_subsec_millis(&self) -> u32 {
157 self.datetime
.timestamp_subsec_millis()
160 /// Returns the number of microseconds since the last second boundary
162 /// warning: in event of a leap second, this may exceed 999_999
164 /// note: this is not the number of microseconds since January 1, 1970 0:00:00 UTC
166 pub fn timestamp_subsec_micros(&self) -> u32 {
167 self.datetime
.timestamp_subsec_micros()
170 /// Returns the number of nanoseconds since the last second boundary
172 /// warning: in event of a leap second, this may exceed 999_999_999
174 /// note: this is not the number of nanoseconds since January 1, 1970 0:00:00 UTC
176 pub fn timestamp_subsec_nanos(&self) -> u32 {
177 self.datetime
.timestamp_subsec_nanos()
180 /// Retrieves an associated offset from UTC.
182 pub fn offset(&self) -> &Tz
::Offset
{
186 /// Retrieves an associated time zone.
188 pub fn timezone(&self) -> Tz
{
189 TimeZone
::from_offset(&self.offset
)
192 /// Changes the associated time zone.
193 /// This does not change the actual `DateTime` (but will change the string representation).
195 pub fn with_timezone
<Tz2
: TimeZone
>(&self, tz
: &Tz2
) -> DateTime
<Tz2
> {
196 tz
.from_utc_datetime(&self.datetime
)
199 /// Adds given `Duration` to the current date and time.
201 /// Returns `None` when it will result in overflow.
203 pub fn checked_add_signed(self, rhs
: OldDuration
) -> Option
<DateTime
<Tz
>> {
204 let datetime
= try_opt
!(self.datetime
.checked_add_signed(rhs
));
205 Some(DateTime { datetime: datetime, offset: self.offset }
)
208 /// Subtracts given `Duration` from the current date and time.
210 /// Returns `None` when it will result in overflow.
212 pub fn checked_sub_signed(self, rhs
: OldDuration
) -> Option
<DateTime
<Tz
>> {
213 let datetime
= try_opt
!(self.datetime
.checked_sub_signed(rhs
));
214 Some(DateTime { datetime: datetime, offset: self.offset }
)
217 /// Subtracts another `DateTime` from the current date and time.
218 /// This does not overflow or underflow at all.
219 #[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
221 pub fn signed_duration_since
<Tz2
: TimeZone
>(self, rhs
: DateTime
<Tz2
>) -> OldDuration
{
222 self.datetime
.signed_duration_since(rhs
.datetime
)
225 /// Returns a view to the naive UTC datetime.
227 pub fn naive_utc(&self) -> NaiveDateTime
{
231 /// Returns a view to the naive local datetime.
233 pub fn naive_local(&self) -> NaiveDateTime
{
234 self.datetime
+ self.offset
.fix()
238 /// Maps the local datetime to other datetime with given conversion function.
239 fn map_local
<Tz
: TimeZone
, F
>(dt
: &DateTime
<Tz
>, mut f
: F
) -> Option
<DateTime
<Tz
>>
240 where F
: FnMut(NaiveDateTime
) -> Option
<NaiveDateTime
> {
241 f(dt
.naive_local()).and_then(|datetime
| dt
.timezone().from_local_datetime(&datetime
).single())
244 impl DateTime
<FixedOffset
> {
245 /// Parses an RFC 2822 date and time string such as `Tue, 1 Jul 2003 10:52:37 +0200`,
246 /// then returns a new `DateTime` with a parsed `FixedOffset`.
247 pub fn parse_from_rfc2822(s
: &str) -> ParseResult
<DateTime
<FixedOffset
>> {
248 const ITEMS
: &'
static [Item
<'
static>] = &[Item
::Fixed(Fixed
::RFC2822
)];
249 let mut parsed
= Parsed
::new();
250 try
!(parse(&mut parsed
, s
, ITEMS
.iter().cloned()));
254 /// Parses an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`,
255 /// then returns a new `DateTime` with a parsed `FixedOffset`.
257 /// Why isn't this named `parse_from_iso8601`? That's because ISO 8601 allows some freedom
258 /// over the syntax and RFC 3339 exercises that freedom to rigidly define a fixed format.
259 pub fn parse_from_rfc3339(s
: &str) -> ParseResult
<DateTime
<FixedOffset
>> {
260 const ITEMS
: &'
static [Item
<'
static>] = &[Item
::Fixed(Fixed
::RFC3339
)];
261 let mut parsed
= Parsed
::new();
262 try
!(parse(&mut parsed
, s
, ITEMS
.iter().cloned()));
266 /// Parses a string with the specified format string and
267 /// returns a new `DateTime` with a parsed `FixedOffset`.
268 /// See the [`format::strftime` module](./format/strftime/index.html)
269 /// on the supported escape sequences.
271 /// See also `Offset::datetime_from_str` which gives a local `DateTime` on specific time zone.
273 /// Note that this method *requires a timezone* in the string. See
274 /// [`NaiveDateTime::parse_from_str`](./naive/struct.NaiveDateTime.html#method.parse_from_str)
275 /// for a version that does not require a timezone in the to-be-parsed str.
280 /// use chrono::{DateTime, FixedOffset, TimeZone};
282 /// let dt = DateTime::parse_from_str(
283 /// "1983 Apr 13 12:09:14.274 +0000", "%Y %b %d %H:%M:%S%.3f %z");
284 /// assert_eq!(dt, Ok(FixedOffset::east(0).ymd(1983, 4, 13).and_hms_milli(12, 9, 14, 274)));
286 pub fn parse_from_str(s
: &str, fmt
: &str) -> ParseResult
<DateTime
<FixedOffset
>> {
287 let mut parsed
= Parsed
::new();
288 try
!(parse(&mut parsed
, s
, StrftimeItems
::new(fmt
)));
293 impl<Tz
: TimeZone
> DateTime
<Tz
> where Tz
::Offset
: fmt
::Display
{
294 /// Returns an RFC 2822 date and time string such as `Tue, 1 Jul 2003 10:52:37 +0200`.
295 pub fn to_rfc2822(&self) -> String
{
296 const ITEMS
: &'
static [Item
<'
static>] = &[Item
::Fixed(Fixed
::RFC2822
)];
297 self.format_with_items(ITEMS
.iter().cloned()).to_string()
300 /// Returns an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`.
301 pub fn to_rfc3339(&self) -> String
{
302 const ITEMS
: &'
static [Item
<'
static>] = &[Item
::Fixed(Fixed
::RFC3339
)];
303 self.format_with_items(ITEMS
.iter().cloned()).to_string()
306 /// Return an RFC 3339 and ISO 8601 date and time string with subseconds
307 /// formatted as per a `SecondsFormat`. If passed `use_z` true and the
308 /// timezone is UTC (offset 0), use 'Z', as per
309 /// [Fixed::TimezoneOffsetColonZ](format/enum.Fixed.html#variant.TimezoneOffsetColonZ).
310 /// If passed `use_z` false, use
311 /// [Fixed::TimezoneOffsetColon](format/enum.Fixed.html#variant.TimezoneOffsetColon).
316 /// # use chrono::{DateTime, FixedOffset, SecondsFormat, TimeZone, Utc};
317 /// let dt = Utc.ymd(2018, 1, 26).and_hms_micro(18, 30, 9, 453_829);
318 /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, false),
319 /// "2018-01-26T18:30:09.453+00:00");
320 /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Millis, true),
321 /// "2018-01-26T18:30:09.453Z");
322 /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true),
323 /// "2018-01-26T18:30:09Z");
325 /// let pst = FixedOffset::east(8 * 60 * 60);
326 /// let dt = pst.ymd(2018, 1, 26).and_hms_micro(10, 30, 9, 453_829);
327 /// assert_eq!(dt.to_rfc3339_opts(SecondsFormat::Secs, true),
328 /// "2018-01-26T10:30:09+08:00");
330 pub fn to_rfc3339_opts(&self, secform
: SecondsFormat
, use_z
: bool
) -> String
{
331 use format
::Numeric
::*;
332 use format
::Pad
::Zero
;
333 use SecondsFormat
::*;
335 debug_assert
!(secform
!= __NonExhaustive
, "Do not use __NonExhaustive!");
337 const PREFIX
: &'
static [Item
<'
static>] = &[
338 Item
::Numeric(Year
, Zero
),
340 Item
::Numeric(Month
, Zero
),
342 Item
::Numeric(Day
, Zero
),
344 Item
::Numeric(Hour
, Zero
),
346 Item
::Numeric(Minute
, Zero
),
348 Item
::Numeric(Second
, Zero
),
351 let ssitem
= match secform
{
353 Millis
=> Some(Item
::Fixed(Fixed
::Nanosecond3
)),
354 Micros
=> Some(Item
::Fixed(Fixed
::Nanosecond6
)),
355 Nanos
=> Some(Item
::Fixed(Fixed
::Nanosecond9
)),
356 AutoSi
=> Some(Item
::Fixed(Fixed
::Nanosecond
)),
357 __NonExhaustive
=> unreachable
!(),
360 let tzitem
= Item
::Fixed(
362 Fixed
::TimezoneOffsetColonZ
364 Fixed
::TimezoneOffsetColon
370 self.format_with_items(
371 PREFIX
.iter().chain([tzitem
].iter()).cloned()
374 self.format_with_items(
375 PREFIX
.iter().chain([s
, tzitem
].iter()).cloned()
380 /// Formats the combined date and time with the specified formatting items.
382 pub fn format_with_items
<'a
, I
>(&self, items
: I
) -> DelayedFormat
<I
>
383 where I
: Iterator
<Item
=Item
<'a
>> + Clone
{
384 let local
= self.naive_local();
385 DelayedFormat
::new_with_offset(Some(local
.date()), Some(local
.time()), &self.offset
, items
)
388 /// Formats the combined date and time with the specified format string.
389 /// See the [`format::strftime` module](./format/strftime/index.html)
390 /// on the supported escape sequences.
392 pub fn format
<'a
>(&self, fmt
: &'a
str) -> DelayedFormat
<StrftimeItems
<'a
>> {
393 self.format_with_items(StrftimeItems
::new(fmt
))
397 impl<Tz
: TimeZone
> Datelike
for DateTime
<Tz
> {
398 #[inline] fn year(&self) -> i32 { self.naive_local().year() }
399 #[inline] fn month(&self) -> u32 { self.naive_local().month() }
400 #[inline] fn month0(&self) -> u32 { self.naive_local().month0() }
401 #[inline] fn day(&self) -> u32 { self.naive_local().day() }
402 #[inline] fn day0(&self) -> u32 { self.naive_local().day0() }
403 #[inline] fn ordinal(&self) -> u32 { self.naive_local().ordinal() }
404 #[inline] fn ordinal0(&self) -> u32 { self.naive_local().ordinal0() }
405 #[inline] fn weekday(&self) -> Weekday { self.naive_local().weekday() }
406 #[inline] fn iso_week(&self) -> IsoWeek { self.naive_local().iso_week() }
409 fn with_year(&self, year
: i32) -> Option
<DateTime
<Tz
>> {
410 map_local(self, |datetime
| datetime
.with_year(year
))
414 fn with_month(&self, month
: u32) -> Option
<DateTime
<Tz
>> {
415 map_local(self, |datetime
| datetime
.with_month(month
))
419 fn with_month0(&self, month0
: u32) -> Option
<DateTime
<Tz
>> {
420 map_local(self, |datetime
| datetime
.with_month0(month0
))
424 fn with_day(&self, day
: u32) -> Option
<DateTime
<Tz
>> {
425 map_local(self, |datetime
| datetime
.with_day(day
))
429 fn with_day0(&self, day0
: u32) -> Option
<DateTime
<Tz
>> {
430 map_local(self, |datetime
| datetime
.with_day0(day0
))
434 fn with_ordinal(&self, ordinal
: u32) -> Option
<DateTime
<Tz
>> {
435 map_local(self, |datetime
| datetime
.with_ordinal(ordinal
))
439 fn with_ordinal0(&self, ordinal0
: u32) -> Option
<DateTime
<Tz
>> {
440 map_local(self, |datetime
| datetime
.with_ordinal0(ordinal0
))
444 impl<Tz
: TimeZone
> Timelike
for DateTime
<Tz
> {
445 #[inline] fn hour(&self) -> u32 { self.naive_local().hour() }
446 #[inline] fn minute(&self) -> u32 { self.naive_local().minute() }
447 #[inline] fn second(&self) -> u32 { self.naive_local().second() }
448 #[inline] fn nanosecond(&self) -> u32 { self.naive_local().nanosecond() }
451 fn with_hour(&self, hour
: u32) -> Option
<DateTime
<Tz
>> {
452 map_local(self, |datetime
| datetime
.with_hour(hour
))
456 fn with_minute(&self, min
: u32) -> Option
<DateTime
<Tz
>> {
457 map_local(self, |datetime
| datetime
.with_minute(min
))
461 fn with_second(&self, sec
: u32) -> Option
<DateTime
<Tz
>> {
462 map_local(self, |datetime
| datetime
.with_second(sec
))
466 fn with_nanosecond(&self, nano
: u32) -> Option
<DateTime
<Tz
>> {
467 map_local(self, |datetime
| datetime
.with_nanosecond(nano
))
471 // we need them as automatic impls cannot handle associated types
472 impl<Tz
: TimeZone
> Copy
for DateTime
<Tz
> where <Tz
as TimeZone
>::Offset
: Copy {}
473 unsafe impl<Tz
: TimeZone
> Send
for DateTime
<Tz
> where <Tz
as TimeZone
>::Offset
: Send {}
475 impl<Tz
: TimeZone
, Tz2
: TimeZone
> PartialEq
<DateTime
<Tz2
>> for DateTime
<Tz
> {
476 fn eq(&self, other
: &DateTime
<Tz2
>) -> bool { self.datetime == other.datetime }
479 impl<Tz
: TimeZone
> Eq
for DateTime
<Tz
> {
482 impl<Tz
: TimeZone
> PartialOrd
for DateTime
<Tz
> {
483 fn partial_cmp(&self, other
: &DateTime
<Tz
>) -> Option
<Ordering
> {
484 self.datetime
.partial_cmp(&other
.datetime
)
488 impl<Tz
: TimeZone
> Ord
for DateTime
<Tz
> {
489 fn cmp(&self, other
: &DateTime
<Tz
>) -> Ordering { self.datetime.cmp(&other.datetime) }
492 impl<Tz
: TimeZone
> hash
::Hash
for DateTime
<Tz
> {
493 fn hash
<H
: hash
::Hasher
>(&self, state
: &mut H
) { self.datetime.hash(state) }
496 impl<Tz
: TimeZone
> Add
<OldDuration
> for DateTime
<Tz
> {
497 type Output
= DateTime
<Tz
>;
500 fn add(self, rhs
: OldDuration
) -> DateTime
<Tz
> {
501 self.checked_add_signed(rhs
).expect("`DateTime + Duration` overflowed")
505 impl<Tz
: TimeZone
> Sub
<OldDuration
> for DateTime
<Tz
> {
506 type Output
= DateTime
<Tz
>;
509 fn sub(self, rhs
: OldDuration
) -> DateTime
<Tz
> {
510 self.checked_sub_signed(rhs
).expect("`DateTime - Duration` overflowed")
514 impl<Tz
: TimeZone
> Sub
<DateTime
<Tz
>> for DateTime
<Tz
> {
515 type Output
= OldDuration
;
518 fn sub(self, rhs
: DateTime
<Tz
>) -> OldDuration
{
519 self.signed_duration_since(rhs
)
523 impl<Tz
: TimeZone
> fmt
::Debug
for DateTime
<Tz
> {
524 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
525 write
!(f
, "{:?}{:?}", self.naive_local(), self.offset
)
529 impl<Tz
: TimeZone
> fmt
::Display
for DateTime
<Tz
> where Tz
::Offset
: fmt
::Display
{
530 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
531 write
!(f
, "{} {}", self.naive_local(), self.offset
)
535 impl str::FromStr
for DateTime
<FixedOffset
> {
536 type Err
= ParseError
;
538 fn from_str(s
: &str) -> ParseResult
<DateTime
<FixedOffset
>> {
539 const ITEMS
: &'
static [Item
<'
static>] = &[
540 Item
::Space(""), Item
::Numeric(Numeric
::Year
, Pad
::Zero
),
541 Item
::Space(""), Item
::Literal("-"),
542 Item
::Space(""), Item
::Numeric(Numeric
::Month
, Pad
::Zero
),
543 Item
::Space(""), Item
::Literal("-"),
544 Item
::Space(""), Item
::Numeric(Numeric
::Day
, Pad
::Zero
),
545 Item
::Space(""), Item
::Literal("T"), // XXX shouldn't this be case-insensitive?
546 Item
::Space(""), Item
::Numeric(Numeric
::Hour
, Pad
::Zero
),
547 Item
::Space(""), Item
::Literal(":"),
548 Item
::Space(""), Item
::Numeric(Numeric
::Minute
, Pad
::Zero
),
549 Item
::Space(""), Item
::Literal(":"),
550 Item
::Space(""), Item
::Numeric(Numeric
::Second
, Pad
::Zero
),
551 Item
::Fixed(Fixed
::Nanosecond
),
552 Item
::Space(""), Item
::Fixed(Fixed
::TimezoneOffsetZ
),
556 let mut parsed
= Parsed
::new();
557 try
!(parse(&mut parsed
, s
, ITEMS
.iter().cloned()));
562 impl str::FromStr
for DateTime
<Utc
> {
563 type Err
= ParseError
;
565 fn from_str(s
: &str) -> ParseResult
<DateTime
<Utc
>> {
566 s
.parse
::<DateTime
<FixedOffset
>>().map(|dt
| dt
.with_timezone(&Utc
))
570 #[cfg(feature="clock")]
571 impl str::FromStr
for DateTime
<Local
> {
572 type Err
= ParseError
;
574 fn from_str(s
: &str) -> ParseResult
<DateTime
<Local
>> {
575 s
.parse
::<DateTime
<FixedOffset
>>().map(|dt
| dt
.with_timezone(&Local
))
579 impl From
<SystemTime
> for DateTime
<Utc
> {
580 fn from(t
: SystemTime
) -> DateTime
<Utc
> {
581 let (sec
, nsec
) = match t
.duration_since(UNIX_EPOCH
) {
582 Ok(dur
) => (dur
.as_secs() as i64, dur
.subsec_nanos()),
583 Err(e
) => { // unlikely but should be handled
584 let dur
= e
.duration();
585 let (sec
, nsec
) = (dur
.as_secs() as i64, dur
.subsec_nanos());
589 (-sec
- 1, 1_000_000_000 - nsec
)
593 Utc
.timestamp(sec
, nsec
)
597 #[cfg(feature="clock")]
598 impl From
<SystemTime
> for DateTime
<Local
> {
599 fn from(t
: SystemTime
) -> DateTime
<Local
> {
600 DateTime
::<Utc
>::from(t
).with_timezone(&Local
)
604 impl<Tz
: TimeZone
> From
<DateTime
<Tz
>> for SystemTime
{
605 fn from(dt
: DateTime
<Tz
>) -> SystemTime
{
606 use std
::time
::Duration
;
608 let sec
= dt
.timestamp();
609 let nsec
= dt
.timestamp_subsec_nanos();
611 // unlikely but should be handled
612 UNIX_EPOCH
- Duration
::new(-sec
as u64, 0) + Duration
::new(0, nsec
)
614 UNIX_EPOCH
+ Duration
::new(sec
as u64, nsec
)
619 #[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
620 fn test_encodable_json
<FUtc
, FFixed
, E
>(to_string_utc
: FUtc
, to_string_fixed
: FFixed
)
621 where FUtc
: Fn(&DateTime
<Utc
>) -> Result
<String
, E
>,
622 FFixed
: Fn(&DateTime
<FixedOffset
>) -> Result
<String
, E
>,
625 assert_eq
!(to_string_utc(&Utc
.ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(),
626 Some(r
#""2014-07-24T12:34:06Z""#.into()));
628 assert_eq
!(to_string_fixed(&FixedOffset
::east(3660).ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(),
629 Some(r
#""2014-07-24T12:34:06+01:01""#.into()));
630 assert_eq
!(to_string_fixed(&FixedOffset
::east(3650).ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(),
631 Some(r
#""2014-07-24T12:34:06+01:00:50""#.into()));
634 #[cfg(all(test, feature="clock", any(feature = "rustc-serialize", feature = "serde")))]
635 fn test_decodable_json
<FUtc
, FFixed
, FLocal
, E
>(utc_from_str
: FUtc
,
636 fixed_from_str
: FFixed
,
637 local_from_str
: FLocal
)
638 where FUtc
: Fn(&str) -> Result
<DateTime
<Utc
>, E
>,
639 FFixed
: Fn(&str) -> Result
<DateTime
<FixedOffset
>, E
>,
640 FLocal
: Fn(&str) -> Result
<DateTime
<Local
>, E
>,
643 // should check against the offset as well (the normal DateTime comparison will ignore them)
644 fn norm
<Tz
: TimeZone
>(dt
: &Option
<DateTime
<Tz
>>) -> Option
<(&DateTime
<Tz
>, &Tz
::Offset
)> {
645 dt
.as_ref().map(|dt
| (dt
, dt
.offset()))
648 assert_eq
!(norm(&utc_from_str(r
#""2014-07-24T12:34:06Z""#).ok()),
649 norm(&Some(Utc
.ymd(2014, 7, 24).and_hms(12, 34, 6))));
650 assert_eq
!(norm(&utc_from_str(r
#""2014-07-24T13:57:06+01:23""#).ok()),
651 norm(&Some(Utc
.ymd(2014, 7, 24).and_hms(12, 34, 6))));
653 assert_eq
!(norm(&fixed_from_str(r
#""2014-07-24T12:34:06Z""#).ok()),
654 norm(&Some(FixedOffset
::east(0).ymd(2014, 7, 24).and_hms(12, 34, 6))));
655 assert_eq
!(norm(&fixed_from_str(r
#""2014-07-24T13:57:06+01:23""#).ok()),
656 norm(&Some(FixedOffset
::east(60*60 + 23*60).ymd(2014, 7, 24).and_hms(13, 57, 6))));
658 // we don't know the exact local offset but we can check that
659 // the conversion didn't change the instant itself
660 assert_eq
!(local_from_str(r
#""2014-07-24T12:34:06Z""#)
661 .expect("local shouuld parse"),
662 Utc
.ymd(2014, 7, 24).and_hms(12, 34, 6));
663 assert_eq
!(local_from_str(r
#""2014-07-24T13:57:06+01:23""#)
664 .expect("local should parse with offset"),
665 Utc
.ymd(2014, 7, 24).and_hms(12, 34, 6));
667 assert
!(utc_from_str(r
#""2014-07-32T12:34:06Z""#).is_err());
668 assert
!(fixed_from_str(r
#""2014-07-32T12:34:06Z""#).is_err());
671 #[cfg(all(test, feature="clock", feature = "rustc-serialize"))]
672 fn test_decodable_json_timestamps
<FUtc
, FFixed
, FLocal
, E
>(utc_from_str
: FUtc
,
673 fixed_from_str
: FFixed
,
674 local_from_str
: FLocal
)
675 where FUtc
: Fn(&str) -> Result
<rustc_serialize
::TsSeconds
<Utc
>, E
>,
676 FFixed
: Fn(&str) -> Result
<rustc_serialize
::TsSeconds
<FixedOffset
>, E
>,
677 FLocal
: Fn(&str) -> Result
<rustc_serialize
::TsSeconds
<Local
>, E
>,
680 fn norm
<Tz
: TimeZone
>(dt
: &Option
<DateTime
<Tz
>>) -> Option
<(&DateTime
<Tz
>, &Tz
::Offset
)> {
681 dt
.as_ref().map(|dt
| (dt
, dt
.offset()))
684 assert_eq
!(norm(&utc_from_str("0").ok().map(DateTime
::from
)),
685 norm(&Some(Utc
.ymd(1970, 1, 1).and_hms(0, 0, 0))));
686 assert_eq
!(norm(&utc_from_str("-1").ok().map(DateTime
::from
)),
687 norm(&Some(Utc
.ymd(1969, 12, 31).and_hms(23, 59, 59))));
689 assert_eq
!(norm(&fixed_from_str("0").ok().map(DateTime
::from
)),
690 norm(&Some(FixedOffset
::east(0).ymd(1970, 1, 1).and_hms(0, 0, 0))));
691 assert_eq
!(norm(&fixed_from_str("-1").ok().map(DateTime
::from
)),
692 norm(&Some(FixedOffset
::east(0).ymd(1969, 12, 31).and_hms(23, 59, 59))));
694 assert_eq
!(*fixed_from_str("0").expect("0 timestamp should parse"),
695 Utc
.ymd(1970, 1, 1).and_hms(0, 0, 0));
696 assert_eq
!(*local_from_str("-1").expect("-1 timestamp should parse"),
697 Utc
.ymd(1969, 12, 31).and_hms(23, 59, 59));
700 #[cfg(feature = "rustc-serialize")]
701 pub mod rustc_serialize
{
705 #[cfg(feature="clock")]
707 use offset
::{TimeZone, LocalResult, Utc, FixedOffset}
;
708 use rustc_serialize
::{Encodable, Encoder, Decodable, Decoder}
;
710 impl<Tz
: TimeZone
> Encodable
for DateTime
<Tz
> {
711 fn encode
<S
: Encoder
>(&self, s
: &mut S
) -> Result
<(), S
::Error
> {
712 format
!("{:?}", self).encode(s
)
716 // try!-like function to convert a LocalResult into a serde-ish Result
717 fn from
<T
, D
>(me
: LocalResult
<T
>, d
: &mut D
) -> Result
<T
, D
::Error
>
722 LocalResult
::None
=> Err(d
.error(
723 "value is not a legal timestamp")),
724 LocalResult
::Ambiguous(..) => Err(d
.error(
725 "value is an ambiguous timestamp")),
726 LocalResult
::Single(val
) => Ok(val
)
730 impl Decodable
for DateTime
<FixedOffset
> {
731 fn decode
<D
: Decoder
>(d
: &mut D
) -> Result
<DateTime
<FixedOffset
>, D
::Error
> {
732 d
.read_str()?
.parse
::<DateTime
<FixedOffset
>>()
733 .map_err(|_
| d
.error("invalid date and time"))
738 impl Decodable
for TsSeconds
<FixedOffset
> {
740 fn decode
<D
: Decoder
>(d
: &mut D
) -> Result
<TsSeconds
<FixedOffset
>, D
::Error
> {
741 from(FixedOffset
::east(0).timestamp_opt(d
.read_i64()?
, 0), d
)
746 impl Decodable
for DateTime
<Utc
> {
747 fn decode
<D
: Decoder
>(d
: &mut D
) -> Result
<DateTime
<Utc
>, D
::Error
> {
749 .parse
::<DateTime
<FixedOffset
>>()
750 .map(|dt
| dt
.with_timezone(&Utc
))
751 .map_err(|_
| d
.error("invalid date and time"))
755 /// A `DateTime` that can be deserialized from a timestamp
757 /// A timestamp here is seconds since the epoch
759 pub struct TsSeconds
<Tz
: TimeZone
>(DateTime
<Tz
>);
762 impl<Tz
: TimeZone
> From
<TsSeconds
<Tz
>> for DateTime
<Tz
> {
763 /// Pull the inner DateTime<Tz> out
765 fn from(obj
: TsSeconds
<Tz
>) -> DateTime
<Tz
> {
771 impl<Tz
: TimeZone
> Deref
for TsSeconds
<Tz
> {
772 type Target
= DateTime
<Tz
>;
774 fn deref(&self) -> &Self::Target
{
780 impl Decodable
for TsSeconds
<Utc
> {
781 fn decode
<D
: Decoder
>(d
: &mut D
) -> Result
<TsSeconds
<Utc
>, D
::Error
> {
782 from(Utc
.timestamp_opt(d
.read_i64()?
, 0), d
)
787 #[cfg(feature="clock")]
788 impl Decodable
for DateTime
<Local
> {
789 fn decode
<D
: Decoder
>(d
: &mut D
) -> Result
<DateTime
<Local
>, D
::Error
> {
790 match d
.read_str()?
.parse
::<DateTime
<FixedOffset
>>() {
791 Ok(dt
) => Ok(dt
.with_timezone(&Local
)),
792 Err(_
) => Err(d
.error("invalid date and time")),
797 #[cfg(feature="clock")]
799 impl Decodable
for TsSeconds
<Local
> {
801 fn decode
<D
: Decoder
>(d
: &mut D
) -> Result
<TsSeconds
<Local
>, D
::Error
> {
802 from(Utc
.timestamp_opt(d
.read_i64()?
, 0), d
)
803 .map(|dt
| TsSeconds(dt
.with_timezone(&Local
)))
807 #[cfg(test)] use rustc_serialize::json;
810 fn test_encodable() {
811 super::test_encodable_json(json
::encode
, json
::encode
);
814 #[cfg(feature="clock")]
816 fn test_decodable() {
817 super::test_decodable_json(json
::decode
, json
::decode
, json
::decode
);
820 #[cfg(feature="clock")]
822 fn test_decodable_timestamps() {
823 super::test_decodable_json_timestamps(json
::decode
, json
::decode
, json
::decode
);
828 /// documented at re-export site
829 #[cfg(feature = "serde")]
833 #[cfg(feature="clock")]
835 use offset
::{LocalResult, TimeZone, Utc, FixedOffset}
;
836 use serdelib
::{ser, de}
;
838 // try!-like function to convert a LocalResult into a serde-ish Result
839 fn serde_from
<T
, E
, V
>(me
: LocalResult
<T
>, ts
: &V
) -> Result
<T
, E
>
845 LocalResult
::None
=> Err(E
::custom(
846 format
!("value is not a legal timestamp: {}", ts
))),
847 LocalResult
::Ambiguous(min
, max
) => Err(E
::custom(
848 format
!("value is an ambiguous timestamp: {}, could be either of {}, {}",
850 LocalResult
::Single(val
) => Ok(val
)
854 /// Ser/de to/from timestamps in nanoseconds
856 /// Intended for use with `serde`'s `with` attribute.
861 /// # // We mark this ignored so that we can test on 1.13 (which does not
862 /// # // support custom derive), and run tests with --ignored on beta and
863 /// # // nightly to actually trigger these.
865 /// # #[macro_use] extern crate serde_derive;
866 /// # #[macro_use] extern crate serde_json;
867 /// # extern crate chrono;
868 /// # use chrono::{TimeZone, DateTime, Utc};
869 /// use chrono::serde::ts_nanoseconds;
870 /// #[derive(Deserialize, Serialize)]
872 /// #[serde(with = "ts_nanoseconds")]
873 /// time: DateTime<Utc>
876 /// # fn example() -> Result<S, serde_json::Error> {
877 /// let time = Utc.ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733);
879 /// time: time.clone(),
882 /// let as_string = serde_json::to_string(&my_s)?;
883 /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
884 /// let my_s: S = serde_json::from_str(&as_string)?;
885 /// assert_eq!(my_s.time, time);
888 /// # fn main() { example().unwrap(); }
890 pub mod ts_nanoseconds
{
892 use serdelib
::{ser, de}
;
895 use offset
::TimeZone
;
897 use super::serde_from
;
899 /// Serialize a UTC datetime into an integer number of nanoseconds since the epoch
901 /// Intended for use with `serde`s `serialize_with` attribute.
906 /// # // We mark this ignored so that we can test on 1.13 (which does not
907 /// # // support custom derive), and run tests with --ignored on beta and
908 /// # // nightly to actually trigger these.
910 /// # #[macro_use] extern crate serde_derive;
911 /// # #[macro_use] extern crate serde_json;
912 /// # extern crate chrono;
913 /// # use chrono::{TimeZone, DateTime, Utc};
914 /// use chrono::serde::ts_nanoseconds::serialize as to_nano_ts;
915 /// #[derive(Serialize)]
917 /// #[serde(serialize_with = "to_nano_ts")]
918 /// time: DateTime<Utc>
921 /// # fn example() -> Result<String, serde_json::Error> {
923 /// time: Utc.ymd(2018, 5, 17).and_hms_nano(02, 04, 59, 918355733),
925 /// let as_string = serde_json::to_string(&my_s)?;
926 /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#);
929 /// # fn main() { example().unwrap(); }
931 pub fn serialize
<S
>(dt
: &DateTime
<Utc
>, serializer
: S
) -> Result
<S
::Ok
, S
::Error
>
932 where S
: ser
::Serializer
934 serializer
.serialize_i64(dt
.timestamp_nanos())
937 /// Deserialize a `DateTime` from a nanosecond timestamp
939 /// Intended for use with `serde`s `deserialize_with` attribute.
944 /// # // We mark this ignored so that we can test on 1.13 (which does not
945 /// # // support custom derive), and run tests with --ignored on beta and
946 /// # // nightly to actually trigger these.
948 /// # #[macro_use] extern crate serde_derive;
949 /// # #[macro_use] extern crate serde_json;
950 /// # extern crate chrono;
951 /// # use chrono::{DateTime, Utc};
952 /// use chrono::serde::ts_nanoseconds::deserialize as from_nano_ts;
953 /// #[derive(Deserialize)]
955 /// #[serde(deserialize_with = "from_nano_ts")]
956 /// time: DateTime<Utc>
959 /// # fn example() -> Result<S, serde_json::Error> {
960 /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?;
963 /// # fn main() { example().unwrap(); }
965 pub fn deserialize
<'de
, D
>(d
: D
) -> Result
<DateTime
<Utc
>, D
::Error
>
966 where D
: de
::Deserializer
<'de
>
968 Ok(try
!(d
.deserialize_i64(NanoSecondsTimestampVisitor
)))
971 struct NanoSecondsTimestampVisitor
;
973 impl<'de
> de
::Visitor
<'de
> for NanoSecondsTimestampVisitor
{
974 type Value
= DateTime
<Utc
>;
976 fn expecting(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
978 write
!(formatter
, "a unix timestamp in seconds")
981 /// Deserialize a timestamp in nanoseconds since the epoch
982 fn visit_i64
<E
>(self, value
: i64) -> Result
<DateTime
<Utc
>, E
>
985 serde_from(Utc
.timestamp_opt(value
/ 1_000_000_000,
986 (value
% 1_000_000_000) as u32),
990 /// Deserialize a timestamp in nanoseconds since the epoch
991 fn visit_u64
<E
>(self, value
: u64) -> Result
<DateTime
<Utc
>, E
>
994 serde_from(Utc
.timestamp_opt((value
/ 1_000_000_000) as i64,
995 (value
% 1_000_000_000) as u32),
1001 /// Ser/de to/from timestamps in milliseconds
1003 /// Intended for use with `serde`s `with` attribute.
1008 /// # // We mark this ignored so that we can test on 1.13 (which does not
1009 /// # // support custom derive), and run tests with --ignored on beta and
1010 /// # // nightly to actually trigger these.
1012 /// # #[macro_use] extern crate serde_derive;
1013 /// # #[macro_use] extern crate serde_json;
1014 /// # extern crate chrono;
1015 /// # use chrono::{TimeZone, DateTime, Utc};
1016 /// use chrono::serde::ts_milliseconds;
1017 /// #[derive(Deserialize, Serialize)]
1019 /// #[serde(with = "ts_milliseconds")]
1020 /// time: DateTime<Utc>
1023 /// # fn example() -> Result<S, serde_json::Error> {
1024 /// let time = Utc.ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918);
1026 /// time: time.clone(),
1029 /// let as_string = serde_json::to_string(&my_s)?;
1030 /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
1031 /// let my_s: S = serde_json::from_str(&as_string)?;
1032 /// assert_eq!(my_s.time, time);
1035 /// # fn main() { example().unwrap(); }
1037 pub mod ts_milliseconds
{
1039 use serdelib
::{ser, de}
;
1041 use {DateTime, Utc}
;
1042 use offset
::TimeZone
;
1044 use super::serde_from
;
1046 /// Serialize a UTC datetime into an integer number of milliseconds since the epoch
1048 /// Intended for use with `serde`s `serialize_with` attribute.
1053 /// # // We mark this ignored so that we can test on 1.13 (which does not
1054 /// # // support custom derive), and run tests with --ignored on beta and
1055 /// # // nightly to actually trigger these.
1057 /// # #[macro_use] extern crate serde_derive;
1058 /// # #[macro_use] extern crate serde_json;
1059 /// # extern crate chrono;
1060 /// # use chrono::{TimeZone, DateTime, Utc};
1061 /// use chrono::serde::ts_milliseconds::serialize as to_milli_ts;
1062 /// #[derive(Serialize)]
1064 /// #[serde(serialize_with = "to_milli_ts")]
1065 /// time: DateTime<Utc>
1068 /// # fn example() -> Result<String, serde_json::Error> {
1070 /// time: Utc.ymd(2018, 5, 17).and_hms_milli(02, 04, 59, 918),
1072 /// let as_string = serde_json::to_string(&my_s)?;
1073 /// assert_eq!(as_string, r#"{"time":1526522699918}"#);
1076 /// # fn main() { example().unwrap(); }
1078 pub fn serialize
<S
>(dt
: &DateTime
<Utc
>, serializer
: S
) -> Result
<S
::Ok
, S
::Error
>
1079 where S
: ser
::Serializer
1081 serializer
.serialize_i64(dt
.timestamp_millis())
1084 /// Deserialize a `DateTime` from a millisecond timestamp
1086 /// Intended for use with `serde`s `deserialize_with` attribute.
1091 /// # // We mark this ignored so that we can test on 1.13 (which does not
1092 /// # // support custom derive), and run tests with --ignored on beta and
1093 /// # // nightly to actually trigger these.
1095 /// # #[macro_use] extern crate serde_derive;
1096 /// # #[macro_use] extern crate serde_json;
1097 /// # extern crate chrono;
1098 /// # use chrono::{DateTime, Utc};
1099 /// use chrono::serde::ts_milliseconds::deserialize as from_milli_ts;
1100 /// #[derive(Deserialize)]
1102 /// #[serde(deserialize_with = "from_milli_ts")]
1103 /// time: DateTime<Utc>
1106 /// # fn example() -> Result<S, serde_json::Error> {
1107 /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?;
1110 /// # fn main() { example().unwrap(); }
1112 pub fn deserialize
<'de
, D
>(d
: D
) -> Result
<DateTime
<Utc
>, D
::Error
>
1113 where D
: de
::Deserializer
<'de
>
1115 Ok(try
!(d
.deserialize_i64(MilliSecondsTimestampVisitor
).map(|dt
| dt
.with_timezone(&Utc
))))
1118 struct MilliSecondsTimestampVisitor
;
1120 impl<'de
> de
::Visitor
<'de
> for MilliSecondsTimestampVisitor
{
1121 type Value
= DateTime
<Utc
>;
1123 fn expecting(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
1125 formatter
.write_str("a unix timestamp in milliseconds")
1128 /// Deserialize a timestamp in milliseconds since the epoch
1129 fn visit_i64
<E
>(self, value
: i64) -> Result
<DateTime
<Utc
>, E
>
1132 serde_from(Utc
.timestamp_opt(value
/ 1000,
1133 ((value
% 1000) * 1_000_000) as u32),
1137 /// Deserialize a timestamp in milliseconds since the epoch
1138 fn visit_u64
<E
>(self, value
: u64) -> Result
<DateTime
<Utc
>, E
>
1141 serde_from(Utc
.timestamp_opt((value
/ 1000) as i64,
1142 ((value
% 1000) * 1_000_000) as u32),
1148 /// Ser/de to/from timestamps in seconds
1150 /// Intended for use with `serde`'s `with` attribute.
1155 /// # // We mark this ignored so that we can test on 1.13 (which does not
1156 /// # // support custom derive), and run tests with --ignored on beta and
1157 /// # // nightly to actually trigger these.
1159 /// # #[macro_use] extern crate serde_derive;
1160 /// # #[macro_use] extern crate serde_json;
1161 /// # extern crate chrono;
1162 /// # use chrono::{TimeZone, DateTime, Utc};
1163 /// use chrono::serde::ts_seconds;
1164 /// #[derive(Deserialize, Serialize)]
1166 /// #[serde(with = "ts_seconds")]
1167 /// time: DateTime<Utc>
1170 /// # fn example() -> Result<S, serde_json::Error> {
1171 /// let time = Utc.ymd(2015, 5, 15).and_hms(10, 0, 0);
1173 /// time: time.clone(),
1176 /// let as_string = serde_json::to_string(&my_s)?;
1177 /// assert_eq!(as_string, r#"{"time":1431684000}"#);
1178 /// let my_s: S = serde_json::from_str(&as_string)?;
1179 /// assert_eq!(my_s.time, time);
1182 /// # fn main() { example().unwrap(); }
1184 pub mod ts_seconds
{
1186 use serdelib
::{ser, de}
;
1188 use {DateTime, Utc}
;
1189 use offset
::TimeZone
;
1191 use super::serde_from
;
1193 /// Serialize a UTC datetime into an integer number of seconds since the epoch
1195 /// Intended for use with `serde`s `serialize_with` attribute.
1200 /// # // We mark this ignored so that we can test on 1.13 (which does not
1201 /// # // support custom derive), and run tests with --ignored on beta and
1202 /// # // nightly to actually trigger these.
1204 /// # #[macro_use] extern crate serde_derive;
1205 /// # #[macro_use] extern crate serde_json;
1206 /// # extern crate chrono;
1207 /// # use chrono::{TimeZone, DateTime, Utc};
1208 /// use chrono::serde::ts_seconds::serialize as to_ts;
1209 /// #[derive(Serialize)]
1211 /// #[serde(serialize_with = "to_ts")]
1212 /// time: DateTime<Utc>
1215 /// # fn example() -> Result<String, serde_json::Error> {
1217 /// time: Utc.ymd(2015, 5, 15).and_hms(10, 0, 0),
1219 /// let as_string = serde_json::to_string(&my_s)?;
1220 /// assert_eq!(as_string, r#"{"time":1431684000}"#);
1223 /// # fn main() { example().unwrap(); }
1225 pub fn serialize
<S
>(dt
: &DateTime
<Utc
>, serializer
: S
) -> Result
<S
::Ok
, S
::Error
>
1226 where S
: ser
::Serializer
1228 serializer
.serialize_i64(dt
.timestamp())
1231 /// Deserialize a `DateTime` from a seconds timestamp
1233 /// Intended for use with `serde`s `deserialize_with` attribute.
1238 /// # // We mark this ignored so that we can test on 1.13 (which does not
1239 /// # // support custom derive), and run tests with --ignored on beta and
1240 /// # // nightly to actually trigger these.
1242 /// # #[macro_use] extern crate serde_derive;
1243 /// # #[macro_use] extern crate serde_json;
1244 /// # extern crate chrono;
1245 /// # use chrono::{DateTime, Utc};
1246 /// use chrono::serde::ts_seconds::deserialize as from_ts;
1247 /// #[derive(Deserialize)]
1249 /// #[serde(deserialize_with = "from_ts")]
1250 /// time: DateTime<Utc>
1253 /// # fn example() -> Result<S, serde_json::Error> {
1254 /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?;
1257 /// # fn main() { example().unwrap(); }
1259 pub fn deserialize
<'de
, D
>(d
: D
) -> Result
<DateTime
<Utc
>, D
::Error
>
1260 where D
: de
::Deserializer
<'de
>
1262 Ok(try
!(d
.deserialize_i64(SecondsTimestampVisitor
)))
1265 struct SecondsTimestampVisitor
;
1267 impl<'de
> de
::Visitor
<'de
> for SecondsTimestampVisitor
{
1268 type Value
= DateTime
<Utc
>;
1270 fn expecting(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
1272 formatter
.write_str("a unix timestamp in seconds")
1275 /// Deserialize a timestamp in seconds since the epoch
1276 fn visit_i64
<E
>(self, value
: i64) -> Result
<DateTime
<Utc
>, E
>
1279 serde_from(Utc
.timestamp_opt(value
, 0), &value
)
1282 /// Deserialize a timestamp in seconds since the epoch
1283 fn visit_u64
<E
>(self, value
: u64) -> Result
<DateTime
<Utc
>, E
>
1286 serde_from(Utc
.timestamp_opt(value
as i64, 0), &value
)
1291 impl<Tz
: TimeZone
> ser
::Serialize
for DateTime
<Tz
> {
1292 /// Serialize into a rfc3339 time string
1294 /// See [the `serde` module](./serde/index.html) for alternate
1296 fn serialize
<S
>(&self, serializer
: S
) -> Result
<S
::Ok
, S
::Error
>
1297 where S
: ser
::Serializer
1299 struct FormatWrapped
<'a
, D
: 'a
> {
1303 impl<'a
, D
: fmt
::Debug
> fmt
::Display
for FormatWrapped
<'a
, D
> {
1304 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1309 // Debug formatting is correct RFC3339, and it allows Zulu.
1310 serializer
.collect_str(&FormatWrapped { inner: &self }
)
1314 struct DateTimeVisitor
;
1316 impl<'de
> de
::Visitor
<'de
> for DateTimeVisitor
{
1317 type Value
= DateTime
<FixedOffset
>;
1319 fn expecting(&self, formatter
: &mut fmt
::Formatter
) -> fmt
::Result
1321 write
!(formatter
, "a formatted date and time string or a unix timestamp")
1324 fn visit_str
<E
>(self, value
: &str) -> Result
<DateTime
<FixedOffset
>, E
>
1327 value
.parse().map_err(|err
| E
::custom(format
!("{}", err
)))
1331 /// Deserialize a value that optionally includes a timezone offset in its
1332 /// string representation
1334 /// The value to be deserialized must be an rfc3339 string.
1336 /// See [the `serde` module](./serde/index.html) for alternate
1337 /// deserialization formats.
1338 impl<'de
> de
::Deserialize
<'de
> for DateTime
<FixedOffset
> {
1339 fn deserialize
<D
>(deserializer
: D
) -> Result
<Self, D
::Error
>
1340 where D
: de
::Deserializer
<'de
>
1342 deserializer
.deserialize_str(DateTimeVisitor
)
1346 /// Deserialize into a UTC value
1348 /// The value to be deserialized must be an rfc3339 string.
1350 /// See [the `serde` module](./serde/index.html) for alternate
1351 /// deserialization formats.
1352 impl<'de
> de
::Deserialize
<'de
> for DateTime
<Utc
> {
1353 fn deserialize
<D
>(deserializer
: D
) -> Result
<Self, D
::Error
>
1354 where D
: de
::Deserializer
<'de
>
1356 deserializer
.deserialize_str(DateTimeVisitor
).map(|dt
| dt
.with_timezone(&Utc
))
1360 /// Deserialize a value that includes no timezone in its string
1363 /// The value to be deserialized must be an rfc3339 string.
1365 /// See [the `serde` module](./serde/index.html) for alternate
1366 /// serialization formats.
1367 #[cfg(feature="clock")]
1368 impl<'de
> de
::Deserialize
<'de
> for DateTime
<Local
> {
1369 fn deserialize
<D
>(deserializer
: D
) -> Result
<Self, D
::Error
>
1370 where D
: de
::Deserializer
<'de
>
1372 deserializer
.deserialize_str(DateTimeVisitor
).map(|dt
| dt
.with_timezone(&Local
))
1376 #[cfg(test)] extern crate serde_json;
1377 #[cfg(test)] extern crate bincode;
1380 fn test_serde_serialize() {
1381 super::test_encodable_json(self::serde_json
::to_string
, self::serde_json
::to_string
);
1384 #[cfg(feature="clock")]
1386 fn test_serde_deserialize() {
1387 super::test_decodable_json(|input
| self::serde_json
::from_str(&input
), |input
| self::serde_json
::from_str(&input
),
1388 |input
| self::serde_json
::from_str(&input
));
1392 fn test_serde_bincode() {
1393 // Bincode is relevant to test separately from JSON because
1394 // it is not self-describing.
1395 use self::bincode
::{Infinite, serialize, deserialize}
;
1397 let dt
= Utc
.ymd(2014, 7, 24).and_hms(12, 34, 6);
1398 let encoded
= serialize(&dt
, Infinite
).unwrap();
1399 let decoded
: DateTime
<Utc
> = deserialize(&encoded
).unwrap();
1400 assert_eq
!(dt
, decoded
);
1401 assert_eq
!(dt
.offset(), decoded
.offset());
1407 use super::DateTime
;
1408 #[cfg(feature="clock")]
1410 use naive
::{NaiveTime, NaiveDate}
;
1411 #[cfg(feature="clock")]
1413 use offset
::{TimeZone, Utc, FixedOffset}
;
1414 use oldtime
::Duration
;
1415 use std
::time
::{SystemTime, UNIX_EPOCH}
;
1418 #[allow(non_snake_case)]
1419 fn test_datetime_offset() {
1420 let Est
= FixedOffset
::west(5*60*60);
1421 let Edt
= FixedOffset
::west(4*60*60);
1422 let Kst
= FixedOffset
::east(9*60*60);
1424 assert_eq
!(format
!("{}", Utc
.ymd(2014, 5, 6).and_hms(7, 8, 9)),
1425 "2014-05-06 07:08:09 UTC");
1426 assert_eq
!(format
!("{}", Edt
.ymd(2014, 5, 6).and_hms(7, 8, 9)),
1427 "2014-05-06 07:08:09 -04:00");
1428 assert_eq
!(format
!("{}", Kst
.ymd(2014, 5, 6).and_hms(7, 8, 9)),
1429 "2014-05-06 07:08:09 +09:00");
1430 assert_eq
!(format
!("{:?}", Utc
.ymd(2014, 5, 6).and_hms(7, 8, 9)),
1431 "2014-05-06T07:08:09Z");
1432 assert_eq
!(format
!("{:?}", Edt
.ymd(2014, 5, 6).and_hms(7, 8, 9)),
1433 "2014-05-06T07:08:09-04:00");
1434 assert_eq
!(format
!("{:?}", Kst
.ymd(2014, 5, 6).and_hms(7, 8, 9)),
1435 "2014-05-06T07:08:09+09:00");
1438 assert_eq
!(format
!("{:?}", Utc
.ymd(2014, 5, 6).and_hms(0, 0, 0)),
1439 "2014-05-06T00:00:00Z");
1440 assert_eq
!(format
!("{:?}", Edt
.ymd(2014, 5, 6).and_hms(0, 0, 0)),
1441 "2014-05-06T00:00:00-04:00");
1442 assert_eq
!(format
!("{:?}", Kst
.ymd(2014, 5, 6).and_hms(0, 0, 0)),
1443 "2014-05-06T00:00:00+09:00");
1444 assert_eq
!(format
!("{:?}", Utc
.ymd(2014, 5, 6).and_hms(23, 59, 59)),
1445 "2014-05-06T23:59:59Z");
1446 assert_eq
!(format
!("{:?}", Edt
.ymd(2014, 5, 6).and_hms(23, 59, 59)),
1447 "2014-05-06T23:59:59-04:00");
1448 assert_eq
!(format
!("{:?}", Kst
.ymd(2014, 5, 6).and_hms(23, 59, 59)),
1449 "2014-05-06T23:59:59+09:00");
1451 let dt
= Utc
.ymd(2014, 5, 6).and_hms(7, 8, 9);
1452 assert_eq
!(dt
, Edt
.ymd(2014, 5, 6).and_hms(3, 8, 9));
1453 assert_eq
!(dt
+ Duration
::seconds(3600 + 60 + 1), Utc
.ymd(2014, 5, 6).and_hms(8, 9, 10));
1454 assert_eq
!(dt
.signed_duration_since(Edt
.ymd(2014, 5, 6).and_hms(10, 11, 12)),
1455 Duration
::seconds(-7*3600 - 3*60 - 3));
1457 assert_eq
!(*Utc
.ymd(2014, 5, 6).and_hms(7, 8, 9).offset(), Utc
);
1458 assert_eq
!(*Edt
.ymd(2014, 5, 6).and_hms(7, 8, 9).offset(), Edt
);
1459 assert
!(*Edt
.ymd(2014, 5, 6).and_hms(7, 8, 9).offset() != Est
);
1463 fn test_datetime_date_and_time() {
1464 let tz
= FixedOffset
::east(5*60*60);
1465 let d
= tz
.ymd(2014, 5, 6).and_hms(7, 8, 9);
1466 assert_eq
!(d
.time(), NaiveTime
::from_hms(7, 8, 9));
1467 assert_eq
!(d
.date(), tz
.ymd(2014, 5, 6));
1468 assert_eq
!(d
.date().naive_local(), NaiveDate
::from_ymd(2014, 5, 6));
1469 assert_eq
!(d
.date().and_time(d
.time()), Some(d
));
1471 let tz
= FixedOffset
::east(4*60*60);
1472 let d
= tz
.ymd(2016, 5, 4).and_hms(3, 2, 1);
1473 assert_eq
!(d
.time(), NaiveTime
::from_hms(3, 2, 1));
1474 assert_eq
!(d
.date(), tz
.ymd(2016, 5, 4));
1475 assert_eq
!(d
.date().naive_local(), NaiveDate
::from_ymd(2016, 5, 4));
1476 assert_eq
!(d
.date().and_time(d
.time()), Some(d
));
1478 let tz
= FixedOffset
::west(13*60*60);
1479 let d
= tz
.ymd(2017, 8, 9).and_hms(12, 34, 56);
1480 assert_eq
!(d
.time(), NaiveTime
::from_hms(12, 34, 56));
1481 assert_eq
!(d
.date(), tz
.ymd(2017, 8, 9));
1482 assert_eq
!(d
.date().naive_local(), NaiveDate
::from_ymd(2017, 8, 9));
1483 assert_eq
!(d
.date().and_time(d
.time()), Some(d
));
1487 #[cfg(feature="clock")]
1488 fn test_datetime_with_timezone() {
1489 let local_now
= Local
::now();
1490 let utc_now
= local_now
.with_timezone(&Utc
);
1491 let local_now2
= utc_now
.with_timezone(&Local
);
1492 assert_eq
!(local_now
, local_now2
);
1496 #[allow(non_snake_case)]
1497 fn test_datetime_rfc2822_and_rfc3339() {
1498 let EDT
= FixedOffset
::east(5*60*60);
1499 assert_eq
!(Utc
.ymd(2015, 2, 18).and_hms(23, 16, 9).to_rfc2822(),
1500 "Wed, 18 Feb 2015 23:16:09 +0000");
1501 assert_eq
!(Utc
.ymd(2015, 2, 18).and_hms(23, 16, 9).to_rfc3339(),
1502 "2015-02-18T23:16:09+00:00");
1503 assert_eq
!(EDT
.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150).to_rfc2822(),
1504 "Wed, 18 Feb 2015 23:16:09 +0500");
1505 assert_eq
!(EDT
.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150).to_rfc3339(),
1506 "2015-02-18T23:16:09.150+05:00");
1507 assert_eq
!(EDT
.ymd(2015, 2, 18).and_hms_micro(23, 59, 59, 1_234_567).to_rfc2822(),
1508 "Wed, 18 Feb 2015 23:59:60 +0500");
1509 assert_eq
!(EDT
.ymd(2015, 2, 18).and_hms_micro(23, 59, 59, 1_234_567).to_rfc3339(),
1510 "2015-02-18T23:59:60.234567+05:00");
1512 assert_eq
!(DateTime
::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 +0000"),
1513 Ok(FixedOffset
::east(0).ymd(2015, 2, 18).and_hms(23, 16, 9)));
1514 assert_eq
!(DateTime
::parse_from_rfc3339("2015-02-18T23:16:09Z"),
1515 Ok(FixedOffset
::east(0).ymd(2015, 2, 18).and_hms(23, 16, 9)));
1516 assert_eq
!(DateTime
::parse_from_rfc2822("Wed, 18 Feb 2015 23:59:60 +0500"),
1517 Ok(EDT
.ymd(2015, 2, 18).and_hms_milli(23, 59, 59, 1_000)));
1518 assert_eq
!(DateTime
::parse_from_rfc3339("2015-02-18T23:59:60.234567+05:00"),
1519 Ok(EDT
.ymd(2015, 2, 18).and_hms_micro(23, 59, 59, 1_234_567)));
1523 fn test_rfc3339_opts() {
1524 use SecondsFormat
::*;
1525 let pst
= FixedOffset
::east(8 * 60 * 60);
1526 let dt
= pst
.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_000);
1527 assert_eq
!(dt
.to_rfc3339_opts(Secs
, false), "2018-01-11T10:05:13+08:00");
1528 assert_eq
!(dt
.to_rfc3339_opts(Secs
, true), "2018-01-11T10:05:13+08:00");
1529 assert_eq
!(dt
.to_rfc3339_opts(Millis
, false), "2018-01-11T10:05:13.084+08:00");
1530 assert_eq
!(dt
.to_rfc3339_opts(Micros
, false), "2018-01-11T10:05:13.084660+08:00");
1531 assert_eq
!(dt
.to_rfc3339_opts(Nanos
, false), "2018-01-11T10:05:13.084660000+08:00");
1532 assert_eq
!(dt
.to_rfc3339_opts(AutoSi
, false), "2018-01-11T10:05:13.084660+08:00");
1534 let ut
= DateTime
::<Utc
>::from_utc(dt
.naive_utc(), Utc
);
1535 assert_eq
!(ut
.to_rfc3339_opts(Secs
, false), "2018-01-11T02:05:13+00:00");
1536 assert_eq
!(ut
.to_rfc3339_opts(Secs
, true), "2018-01-11T02:05:13Z");
1537 assert_eq
!(ut
.to_rfc3339_opts(Millis
, false), "2018-01-11T02:05:13.084+00:00");
1538 assert_eq
!(ut
.to_rfc3339_opts(Millis
, true), "2018-01-11T02:05:13.084Z");
1539 assert_eq
!(ut
.to_rfc3339_opts(Micros
, true), "2018-01-11T02:05:13.084660Z");
1540 assert_eq
!(ut
.to_rfc3339_opts(Nanos
, true), "2018-01-11T02:05:13.084660000Z");
1541 assert_eq
!(ut
.to_rfc3339_opts(AutoSi
, true), "2018-01-11T02:05:13.084660Z");
1546 fn test_rfc3339_opts_nonexhaustive() {
1548 let dt
= Utc
.ymd(1999, 10, 9).and_hms(1, 2, 3);
1549 dt
.to_rfc3339_opts(SecondsFormat
::__NonExhaustive
, true);
1553 fn test_datetime_from_str() {
1554 assert_eq
!("2015-2-18T23:16:9.15Z".parse
::<DateTime
<FixedOffset
>>(),
1555 Ok(FixedOffset
::east(0).ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150)));
1556 assert_eq
!("2015-2-18T13:16:9.15-10:00".parse
::<DateTime
<FixedOffset
>>(),
1557 Ok(FixedOffset
::west(10 * 3600).ymd(2015, 2, 18).and_hms_milli(13, 16, 9, 150)));
1558 assert
!("2015-2-18T23:16:9.15".parse
::<DateTime
<FixedOffset
>>().is_err());
1560 assert_eq
!("2015-2-18T23:16:9.15Z".parse
::<DateTime
<Utc
>>(),
1561 Ok(Utc
.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150)));
1562 assert_eq
!("2015-2-18T13:16:9.15-10:00".parse
::<DateTime
<Utc
>>(),
1563 Ok(Utc
.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150)));
1564 assert
!("2015-2-18T23:16:9.15".parse
::<DateTime
<Utc
>>().is_err());
1566 // no test for `DateTime<Local>`, we cannot verify that much.
1570 fn test_datetime_parse_from_str() {
1571 let ymdhms
= |y
,m
,d
,h
,n
,s
,off
| FixedOffset
::east(off
).ymd(y
,m
,d
).and_hms(h
,n
,s
);
1572 assert_eq
!(DateTime
::parse_from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
1573 Ok(ymdhms(2014, 5, 7, 12, 34, 56, 570*60))); // ignore offset
1574 assert
!(DateTime
::parse_from_str("20140507000000", "%Y%m%d%H%M%S").is_err()); // no offset
1575 assert
!(DateTime
::parse_from_str("Fri, 09 Aug 2013 23:54:35 GMT",
1576 "%a, %d %b %Y %H:%M:%S GMT").is_err());
1577 assert_eq
!(Utc
.datetime_from_str("Fri, 09 Aug 2013 23:54:35 GMT",
1578 "%a, %d %b %Y %H:%M:%S GMT"),
1579 Ok(Utc
.ymd(2013, 8, 9).and_hms(23, 54, 35)));
1583 #[cfg(feature="clock")]
1584 fn test_datetime_format_with_local() {
1585 // if we are not around the year boundary, local and UTC date should have the same year
1586 let dt
= Local
::now().with_month(5).unwrap();
1587 assert_eq
!(dt
.format("%Y").to_string(), dt
.with_timezone(&Utc
).format("%Y").to_string());
1591 #[cfg(feature="clock")]
1592 fn test_datetime_is_copy() {
1593 // UTC is known to be `Copy`.
1600 #[cfg(feature="clock")]
1601 fn test_datetime_is_send() {
1604 // UTC is known to be `Send`.
1606 thread
::spawn(move || {
1612 fn test_subsecond_part() {
1613 let datetime
= Utc
.ymd(2014, 7, 8).and_hms_nano(9, 10, 11, 1234567);
1615 assert_eq
!(1, datetime
.timestamp_subsec_millis());
1616 assert_eq
!(1234, datetime
.timestamp_subsec_micros());
1617 assert_eq
!(1234567, datetime
.timestamp_subsec_nanos());
1621 fn test_from_system_time() {
1622 use std
::time
::Duration
;
1624 let epoch
= Utc
.ymd(1970, 1, 1).and_hms(0, 0, 0);
1626 // SystemTime -> DateTime<Utc>
1627 assert_eq
!(DateTime
::<Utc
>::from(UNIX_EPOCH
), epoch
);
1628 assert_eq
!(DateTime
::<Utc
>::from(UNIX_EPOCH
+ Duration
::new(999_999_999, 999_999_999)),
1629 Utc
.ymd(2001, 9, 9).and_hms_nano(1, 46, 39, 999_999_999));
1630 assert_eq
!(DateTime
::<Utc
>::from(UNIX_EPOCH
- Duration
::new(999_999_999, 999_999_999)),
1631 Utc
.ymd(1938, 4, 24).and_hms_nano(22, 13, 20, 1));
1633 // DateTime<Utc> -> SystemTime
1634 assert_eq
!(SystemTime
::from(epoch
), UNIX_EPOCH
);
1635 assert_eq
!(SystemTime
::from(Utc
.ymd(2001, 9, 9).and_hms_nano(1, 46, 39, 999_999_999)),
1636 UNIX_EPOCH
+ Duration
::new(999_999_999, 999_999_999));
1637 assert_eq
!(SystemTime
::from(Utc
.ymd(1938, 4, 24).and_hms_nano(22, 13, 20, 1)),
1638 UNIX_EPOCH
- Duration
::new(999_999_999, 999_999_999));
1640 // DateTime<any tz> -> SystemTime (via `with_timezone`)
1641 #[cfg(feature="clock")] {
1642 assert_eq
!(SystemTime
::from(epoch
.with_timezone(&Local
)), UNIX_EPOCH
);
1644 assert_eq
!(SystemTime
::from(epoch
.with_timezone(&FixedOffset
::east(32400))), UNIX_EPOCH
);
1645 assert_eq
!(SystemTime
::from(epoch
.with_timezone(&FixedOffset
::west(28800))), UNIX_EPOCH
);