fastdate/
datetime.rs

1use crate::error::Error;
2use crate::sys::Timespec;
3use crate::{Date, Time};
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use std::cmp;
6use std::fmt::{Display, Formatter};
7use std::ops::{Add, Sub};
8use std::str::FromStr;
9use std::sync::atomic::{AtomicI32, Ordering};
10use std::time::{Duration, SystemTime, UNIX_EPOCH};
11use time1::UtcOffset;
12use time1::format_description::well_known::Rfc3339;
13
14static GLOBAL_OFFSET: AtomicI32 = AtomicI32::new(-99999);
15
16/// offset with utc 0.zone
17pub fn offset_sec() -> i32 {
18    if GLOBAL_OFFSET.load(Ordering::Relaxed) == -99999 {
19        GLOBAL_OFFSET.store(Timespec::now().local().tm_utcoff, Ordering::SeqCst);
20    }
21    GLOBAL_OFFSET.load(Ordering::Relaxed)
22}
23
24/// set GLOBAL_OFFSET
25pub fn set_offset_sec(sec: i32) {
26    GLOBAL_OFFSET.store(sec, Ordering::SeqCst);
27}
28
29/// Log timestamp type.
30///
31/// Parse using `FromStr` impl.
32/// Format using the `Display` trait.
33/// Convert timestamp into/from `SystemTime` to use.
34/// Supports compare and sorting.
35#[derive(Clone, Debug, Eq, PartialEq, Hash)]
36pub struct DateTime {
37    pub inner: time1::OffsetDateTime,
38}
39
40impl DateTime {
41    ///utc time
42    pub fn utc() -> Self {
43        Self::from_system_time(SystemTime::now(), 0)
44    }
45    ///local zone time
46    pub fn now() -> Self {
47        Self::from_system_time(SystemTime::now(), 0).set_offset(offset_sec())
48    }
49
50    /// set offset
51    /// ```rust
52    /// let mut  dt = fastdate::DateTime::utc();
53    /// dt = dt.set_offset(fastdate::offset_sec());
54    /// ```
55    pub fn set_offset(mut self, mut offset_sec: i32) -> DateTime {
56        offset_sec = offset_sec.clamp(-86399, 86399);
57        self.inner = self
58            .inner
59            .to_offset(UtcOffset::from_whole_seconds(offset_sec).unwrap());
60        self
61    }
62
63    /// add Duration
64    pub fn add(mut self, d: Duration) -> Self {
65        self.inner = self.inner.add(d);
66        self
67    }
68
69    /// sub Duration
70    pub fn sub(mut self, d: Duration) -> Self {
71        self.inner = self.inner.sub(d);
72        self
73    }
74
75    ///add/sub sec
76    pub fn add_sub_sec(self, sec: i64) -> Self {
77        if sec >= 0 {
78            self.add(Duration::from_secs(sec as u64))
79        } else {
80            self.sub(Duration::from_secs((-sec) as u64))
81        }
82    }
83
84    /// is self before on other?
85    pub fn before(&self, other: &DateTime) -> bool {
86        self < other
87    }
88
89    /// is self after on other?
90    pub fn after(&self, other: &DateTime) -> bool {
91        self > other
92    }
93
94    /// unix_timestamp sec
95    pub fn unix_timestamp(&self) -> i64 {
96        self.inner.unix_timestamp()
97    }
98
99    ///unix_timestamp micros
100    pub fn unix_timestamp_micros(&self) -> i64 {
101        (self.inner.unix_timestamp_nanos() / 1000) as i64
102    }
103
104    ///unix_timestamp millis
105    pub fn unix_timestamp_millis(&self) -> i64 {
106        (self.inner.unix_timestamp_nanos() / 1000000) as i64
107    }
108
109    ///unix_timestamp nano
110    pub fn unix_timestamp_nano(&self) -> i128 {
111        self.inner.unix_timestamp_nanos()
112    }
113
114    ///from timestamp sec
115    pub fn from_timestamp(sec: i64) -> DateTime {
116        if sec >= 0 {
117            Self::from_system_time(UNIX_EPOCH + Duration::from_secs(sec as u64), 0)
118        } else {
119            Self::from_system_time(UNIX_EPOCH - Duration::from_secs((-sec) as u64), 0)
120        }
121    }
122    ///from timestamp micros
123    pub fn from_timestamp_micros(micros: i64) -> DateTime {
124        if micros >= 0 {
125            Self::from_system_time(UNIX_EPOCH + Duration::from_micros(micros as u64), 0)
126        } else {
127            Self::from_system_time(UNIX_EPOCH - Duration::from_micros((-micros) as u64), 0)
128        }
129    }
130    ///from timestamp millis
131    pub fn from_timestamp_millis(ms: i64) -> DateTime {
132        if ms >= 0 {
133            Self::from_system_time(UNIX_EPOCH + Duration::from_millis(ms as u64), 0)
134        } else {
135            Self::from_system_time(UNIX_EPOCH - Duration::from_millis((-ms) as u64), 0)
136        }
137    }
138    ///from timestamp nano
139    pub fn from_timestamp_nano(nano: i128) -> DateTime {
140        if nano >= 0 {
141            Self::from_system_time(UNIX_EPOCH + Duration::from_nanos(nano as u64), 0)
142        } else {
143            Self::from_system_time(UNIX_EPOCH - Duration::from_nanos((-nano) as u64), 0)
144        }
145    }
146
147    /// format support token = ["YYYY","MM","DD","hh","mm","ss",".000000",".000000000","+00:00"]
148    /// ```
149    /// let dt = fastdate::DateTime::from((
150    ///         fastdate::Date {
151    ///             day: 1,
152    ///             mon: 1,
153    ///             year: 2000,
154    ///         },
155    ///         fastdate::Time {
156    ///             nano: 123456000,
157    ///             sec: 11,
158    ///             minute: 1,
159    ///             hour: 1,
160    ///         })).set_offset(8 * 60 * 60);
161    ///   println!("{}",dt.format("YYYY-MM-DD hh:mm:ss"));
162    ///   println!("{}",dt.format("YYYY-MM-DD hh:mm:ss.000000"));
163    ///   println!("{}",dt.format("YYYY-MM-DD hh:mm:ss.000000+00:00"));
164    ///   println!("{}",dt.format("YYYY/MM/DD/hh/mm/ss/.000000/+00:00"));
165    ///   println!("{}",dt.format("YYYY-MM-DD/hh/mm/ss"));
166    ///
167    /// ```
168    pub fn format(&self, fmt: &str) -> String {
169        use std::fmt::Write;
170        let (mut h, mut m, _) = self.offset_hms();
171        let offset = self.offset();
172        let add_sub = if offset >= 0 { '+' } else { '-' };
173        let mut result = String::with_capacity(fmt.len());
174        let chars = fmt.as_bytes();
175        let mut index = 0;
176        let iter = chars.iter();
177        for c in iter {
178            result.push(*c as char);
179            if result.ends_with(".000000000") {
180                for _ in 0..".000000000".len() {
181                    result.pop();
182                }
183                write!(result, ".{:09}", self.nano()).unwrap()
184            } else if result.ends_with(".000000") {
185                if (index + 3) < fmt.len()
186                    && chars[index + 1] == b'0'
187                    && chars[index + 2] == b'0'
188                    && chars[index + 3] == b'0'
189                {
190                    index += 1;
191                    continue;
192                }
193                for _ in 0..".000000".len() {
194                    result.pop();
195                }
196                write!(result, ".{:06}", self.nano() / 1000).unwrap();
197            } else if result.ends_with("+00:00") {
198                for _ in 0.."+00:00".len() {
199                    result.pop();
200                }
201                h = h.abs();
202                m = m.abs();
203                write!(result, "{}{:02}:{:02}", add_sub, h, m).unwrap();
204            } else if result.ends_with("YYYY") {
205                for _ in 0.."YYYY".len() {
206                    result.pop();
207                }
208                write!(result, "{:04}", self.year()).unwrap()
209            } else if result.ends_with("MM") {
210                for _ in 0.."MM".len() {
211                    result.pop();
212                }
213                result.write_fmt(format_args!("{:02}", self.mon())).unwrap()
214            } else if result.ends_with("DD") {
215                for _ in 0.."DD".len() {
216                    result.pop();
217                }
218                write!(result, "{:02}", self.day()).unwrap()
219            } else if result.ends_with("hh") {
220                for _ in 0.."hh".len() {
221                    result.pop();
222                }
223                write!(result, "{:02}", self.hour()).unwrap()
224            } else if result.ends_with("mm") {
225                for _ in 0.."mm".len() {
226                    result.pop();
227                }
228                write!(result, "{:02}", self.minute()).unwrap();
229            } else if result.ends_with("ss") {
230                for _ in 0.."ss".len() {
231                    result.pop();
232                }
233                write!(result, "{:02}", self.sec()).unwrap();
234            }
235            index += 1;
236        }
237        result
238    }
239
240    /// parse an string by format.
241    /// format support token = ["YYYY","MM","DD","hh","mm","ss",".000000","+00:00","Z"]
242    /// format str must be example:
243    /// parse nano
244    /// ```rust
245    ///  fastdate::DateTime::parse("YYYY-MM-DD hh:mm:ss.000000000Z", "2022-12-13 11:12:14.123456789Z").unwrap();
246    ///  fastdate::DateTime::parse("YYYY-MM-DD hh:mm:ss.000000000+00:00", "2022-12-13 11:12:14.123456789+06:00").unwrap();
247    /// ```
248    /// or time zone(UTC+Hour)
249    /// ```rust
250    ///  fastdate::DateTime::parse("YYYY-MM-DD hh:mm:ss.000000+00:00", "2022-12-13 11:12:14.123456+06:00").unwrap();
251    ///  fastdate::DateTime::parse("YYYY-MM-DD hh:mm:ss.000000+00:00", "2022-12-13 11:12:14.123456-03:00").unwrap();
252    /// ```
253    /// or time zone(UTC)
254    /// ```rust
255    ///  fastdate::DateTime::parse("YYYY-MM-DD hh:mm:ss.000000Z", "2022-12-13 11:12:14.123456Z").unwrap();
256    /// ```
257    /// parse local time
258    /// ```rust
259    ///  fastdate::DateTime::parse("YYYY-MM-DD hh:mm:ss.000000","2022-12-13 11:12:14.123456").unwrap();
260    /// ```
261    /// or any position
262    /// ```rust
263    ///  fastdate::DateTime::parse("YYYY-MM-DD,hh:mm:ss.000000","2022-12-13,11:12:14.123456").unwrap();
264    /// ```
265    /// or time zone(UTC)
266    /// ```rust
267    ///  fastdate::DateTime::parse("YYYY-MM-DD hh:mm:ss.000000Z", "2022-12-13 11:12:14.123456Z").unwrap();
268    /// ```
269    /// or time zone(UTC+Hour)
270    /// ```rust
271    ///  fastdate::DateTime::parse("YYYY-MM-DD hh:mm:ss.000000+00:00", "2022-12-13 11:12:14.123456+08:00").unwrap();
272    /// ```
273    /// ```
274    pub fn parse(format: &str, arg: &str) -> Result<DateTime, Error> {
275        let mut len = 19;
276        //this is RFC3339 datetime buffer
277        let bytes = arg.as_bytes();
278        let mut buf: [u8; 35] = *b"0000-00-00T00:00:00.000000000+00:00";
279        if let Some(year) = format.find("YYYY") {
280            for (index, _) in (0..4).enumerate() {
281                buf[index] = *bytes
282                    .get(year + index)
283                    .ok_or_else(|| Error::from("warn 'YYYY'"))?;
284            }
285        }
286        if let Some(mon) = format.find("MM") {
287            for (index, _) in (0..2).enumerate() {
288                buf[5 + index] = *bytes
289                    .get(mon + index)
290                    .ok_or_else(|| Error::from("warn 'MM'"))?;
291            }
292        }
293        if let Some(day) = format.find("DD") {
294            for (index, _) in (0..2).enumerate() {
295                buf[8 + index] = *bytes
296                    .get(day + index)
297                    .ok_or_else(|| Error::from("warn 'DD'"))?;
298            }
299        }
300        if let Some(hour) = format.find("hh") {
301            for (index, _) in (0..2).enumerate() {
302                buf[11 + index] = *bytes
303                    .get(hour + index)
304                    .ok_or_else(|| Error::from("warn 'hh'"))?;
305            }
306        }
307        if let Some(minute) = format.find("mm") {
308            for (index, _) in (0..2).enumerate() {
309                buf[14 + index] = *bytes
310                    .get(minute + index)
311                    .ok_or_else(|| Error::from("warn 'mm'"))?;
312            }
313        }
314        if let Some(sec) = format.find("ss") {
315            for (index, _) in (0..2).enumerate() {
316                buf[17 + index] = *bytes
317                    .get(sec + index)
318                    .ok_or_else(|| Error::from("warn 'ss'"))?;
319            }
320        }
321        let mut find_nano = false;
322        //parse '.000000000'
323        if let Some(nano) = format.find(".000000000") {
324            for index in 0..10 {
325                buf[19 + index] = *bytes
326                    .get(nano + index)
327                    .ok_or_else(|| Error::from("warn '.000000000'"))?;
328            }
329            len += 10;
330            find_nano = true;
331        }
332        if !find_nano {
333            if let Some(micro) = format.find(".000000") {
334                for index in 0..7 {
335                    buf[19 + index] = *bytes
336                        .get(micro + index)
337                        .ok_or_else(|| Error::from("warn '.000000'"))?;
338                }
339                len += 7;
340            }
341        }
342        let mut have_offset = false;
343        if format.contains("Z") {
344            buf[len] = b'Z';
345            len += 1;
346            have_offset = true;
347        }
348        if let Some(zone) = format.find("+00:00") {
349            for index in 0..6 {
350                let x = bytes
351                    .get(zone + index)
352                    .ok_or_else(|| Error::from("warn '+00:00'"))?;
353                buf[len + index] = *x;
354            }
355            len += 6;
356            have_offset = true;
357        }
358        if !have_offset {
359            let offset_sec = offset_sec();
360            let of = UtcOffset::from_whole_seconds(offset_sec).unwrap();
361            let (h, m, _) = of.as_hms();
362            if offset_sec >= 0 {
363                buf[len] = b'+';
364                len += 1;
365            } else {
366                buf[len] = b'-';
367                len += 1;
368            }
369            buf[len] = b'0' + (h.abs() / 10) as u8;
370            len += 1;
371            buf[len] = b'0' + (h.abs() % 10) as u8;
372            len += 1;
373            buf[len] = b':';
374            len += 1;
375            buf[len] = b'0' + (m.abs() / 10) as u8;
376            len += 1;
377            buf[len] = b'0' + (m.abs() % 10) as u8;
378            len += 1;
379        }
380        let str = std::str::from_utf8(&buf[..len]).unwrap_or_default();
381        let inner = time1::OffsetDateTime::parse(str, &Rfc3339)
382            .map_err(|e| Error::from(format!("{} of '{}'", e, arg)))?;
383        Ok(Self { inner })
384    }
385
386    /// get week_day
387    pub fn week_day(&self) -> u8 {
388        let secs_since_epoch = self.unix_timestamp();
389        /* 2000-03-01 (mod 400 year, immediately after feb29 */
390        const LEAPOCH: i64 = 11017;
391        let days = (secs_since_epoch / 86400) - LEAPOCH;
392        let mut wday = (3 + days) % 7;
393        if wday <= 0 {
394            wday += 7
395        };
396        wday as u8
397    }
398
399    pub fn nano(&self) -> u32 {
400        self.inner.nanosecond()
401    }
402
403    pub fn ms(&self) -> u16 {
404        self.inner.millisecond()
405    }
406
407    /// get micro secs
408    pub fn micro(&self) -> u32 {
409        self.inner.microsecond()
410    }
411
412    /// get sec
413    pub fn sec(&self) -> u8 {
414        self.inner.second()
415    }
416
417    /// minute
418    pub fn minute(&self) -> u8 {
419        self.inner.minute()
420    }
421
422    /// get hour
423    pub fn hour(&self) -> u8 {
424        self.inner.hour()
425    }
426
427    /// get day
428    pub fn day(&self) -> u8 {
429        self.inner.day()
430    }
431
432    /// get mon
433    pub fn mon(&self) -> u8 {
434        self.inner.month() as u8
435    }
436
437    /// get year
438    pub fn year(&self) -> i32 {
439        self.inner.year()
440    }
441
442    ///offset sec
443    pub fn offset(&self) -> i32 {
444        self.inner.offset().whole_seconds()
445    }
446
447    ///offset_hms: hour,minute,sec
448    pub fn offset_hms(&self) -> (i8, i8, i8) {
449        self.inner.offset().as_hms()
450    }
451
452    pub fn from_system_time(s: SystemTime, offset: i32) -> Self {
453        Self {
454            inner: time1::OffsetDateTime::from(s),
455        }
456        .set_offset(offset)
457    }
458
459    /// stand "0000-00-00 00:00:00.000000000"
460    pub fn display_stand(&self) -> String {
461        let mut v = self.display(false);
462        v.replace_range(10..11, " ");
463        v
464    }
465
466    /// RFC3339 "0000-00-00T00:00:00.000000000Z"
467    /// RFC3339 "0000-00-00T00:00:00.000000000+00:00:00"
468    pub fn display(&self, zone: bool) -> String {
469        let mut buf: [u8; 38] = *b"0000-00-00T00:00:00.000000000+00:00:00";
470        let len = self.do_display(&mut buf, zone);
471        std::str::from_utf8(&buf[..len]).unwrap().to_string()
472    }
473
474    /// let mut buf: [u8; 38] = *b"0000-00-00T00:00:00.000000000+00:00:00";
475    /// than print this:
476    /// RFC3339 "0000-00-00T00:00:00.000000000Z"
477    /// RFC3339 "0000-00-00T00:00:00.000000000+00:00:00"
478    pub fn do_display(&self, buf: &mut [u8; 38], add_zone: bool) -> usize {
479        let year = self.year();
480        let mon = self.mon();
481        let day = self.day();
482        buf[0] = b'0' + (year / 1000) as u8;
483        buf[1] = b'0' + (year / 100 % 10) as u8;
484        buf[2] = b'0' + (year / 10 % 10) as u8;
485        buf[3] = b'0' + (year % 10) as u8;
486        buf[5] = b'0' + (mon / 10);
487        buf[6] = b'0' + (mon % 10);
488        buf[8] = b'0' + (day / 10);
489        buf[9] = b'0' + (day % 10);
490        let time = Time::from(self.clone());
491        let mut len = time.display_time(11, buf);
492        if add_zone {
493            let offset = self.offset();
494            if offset == 0 {
495                buf[len] = b'Z';
496                len += 1;
497            } else {
498                let (h, m, s) = self.offset_hms();
499                if offset >= 0 {
500                    buf[len] = b'+';
501                    len += 1;
502                    buf[len] = b'0' + (h as u8 / 10);
503                    len += 1;
504                    buf[len] = b'0' + (h as u8 % 10);
505                    len += 1;
506                    buf[len] = b':';
507                    len += 1;
508                    buf[len] = b'0' + (m as u8 / 10);
509                    len += 1;
510                    buf[len] = b'0' + (m as u8 % 10);
511                    len += 1;
512                    if s != 0 {
513                        buf[len] = b':';
514                        len += 1;
515                        buf[len] = b'0' + (s as u8 / 10);
516                        len += 1;
517                        buf[len] = b'0' + (s as u8 % 10);
518                        len += 1;
519                    }
520                } else {
521                    buf[len] = b'-';
522                    len += 1;
523                    buf[len] = b'0' + (-h as u8 / 10);
524                    len += 1;
525                    buf[len] = b'0' + (-h as u8 % 10);
526                    len += 1;
527                    buf[len] = b':';
528                    len += 1;
529                    buf[len] = b'0' + (-m as u8 / 10);
530                    len += 1;
531                    buf[len] = b'0' + (-m as u8 % 10);
532                    len += 1;
533                    if s != 0 {
534                        buf[len] = b':';
535                        len += 1;
536                        buf[len] = b'0' + (-s as u8 / 10);
537                        len += 1;
538                        buf[len] = b'0' + (-s as u8 % 10);
539                        len += 1;
540                    }
541                }
542            }
543        }
544        len
545    }
546
547    pub fn set_nano(mut self, nano: u32) -> Self {
548        let v = self.nano();
549        if nano != v {
550            self = self.sub(Duration::from_nanos(v as u64));
551            self = self.add(Duration::from_micros(nano as u64));
552        }
553        self
554    }
555
556    pub fn from_str_default(arg: &str, default_offset: i32) -> Result<DateTime, Error> {
557        let mut v = {
558            let mut v = String::with_capacity(arg.len() + 6);
559            for x in arg.chars() {
560                v.push(x);
561            }
562            v
563        };
564        if v.len() == 10 {
565            v.push_str("T00:00:00.00");
566        }
567        if v.len() > 10 && &v[10..11] != "T" {
568            v.replace_range(10..11, "T");
569        }
570        let mut have_offset = None;
571        if v.ends_with("Z") {
572            v.pop();
573            v.push_str("+00:00");
574            have_offset = Some(v.len() - 6);
575        } else {
576            if v.len() >= 6 {
577                let index = v.len() - 6;
578                let b = &v[index..(index + 1)];
579                if b == "+" || b == "-" {
580                    have_offset = Some(index);
581                }
582            }
583            if v.len() >= 3 {
584                let index = v.len() - 3;
585                let b = &v[index..(index + 1)];
586                if b == "+" || b == "-" {
587                    have_offset = Some(index);
588                    v.push_str(":00");
589                }
590            }
591        }
592        if let Some(mut offset) = have_offset {
593            if offset >= 1 {
594                offset -= 1;
595                if v.len() > offset && &v[offset..(offset + 1)] == " " {
596                    v.remove(offset);
597                }
598            }
599        }
600        if have_offset.is_none() {
601            let of = UtcOffset::from_whole_seconds(default_offset).unwrap();
602            let (h, m, _) = of.as_hms();
603            if h >= 0 && m >= 0 {
604                v.push_str(&format!("+{:02}:{:02}", h.abs(), m.abs()));
605            } else {
606                v.push_str(&format!("-{:02}:{:02}", h.abs(), m.abs()));
607            }
608        }
609        let inner = time1::OffsetDateTime::parse(&v, &Rfc3339)
610            .map_err(|e| Error::from(format!("{} of '{}'", e, arg)))?;
611        Ok(Self { inner })
612    }
613}
614
615impl Add<Duration> for DateTime {
616    type Output = DateTime;
617
618    fn add(self, rhs: Duration) -> Self::Output {
619        self.add(rhs)
620    }
621}
622
623impl Sub<Duration> for DateTime {
624    type Output = DateTime;
625
626    fn sub(self, rhs: Duration) -> Self::Output {
627        self.sub(rhs)
628    }
629}
630
631impl Add<&Duration> for DateTime {
632    type Output = DateTime;
633
634    fn add(self, rhs: &Duration) -> Self::Output {
635        self.add(*rhs)
636    }
637}
638
639impl Sub<&Duration> for DateTime {
640    type Output = DateTime;
641
642    fn sub(self, rhs: &Duration) -> Self::Output {
643        self.sub(*rhs)
644    }
645}
646
647impl Sub<DateTime> for DateTime {
648    type Output = Duration;
649
650    fn sub(self, rhs: DateTime) -> Self::Output {
651        let nano = self.unix_timestamp_nano() - rhs.unix_timestamp_nano();
652        Duration::from_nanos(nano as u64)
653    }
654}
655
656impl From<SystemTime> for DateTime {
657    fn from(v: SystemTime) -> DateTime {
658        DateTime::from_system_time(v, 0)
659    }
660}
661
662impl From<DateTime> for SystemTime {
663    fn from(v: DateTime) -> SystemTime {
664        let nano = v.unix_timestamp_nano();
665        if nano >= 0 {
666            UNIX_EPOCH + Duration::from_nanos(nano as u64)
667        } else {
668            UNIX_EPOCH - Duration::from_nanos(nano as u64)
669        }
670    }
671}
672
673impl From<Date> for DateTime {
674    fn from(arg: Date) -> Self {
675        Self::from_str(&format!(
676            "{:04}-{:02}-{:02} 00:00:00.000000000Z",
677            arg.year, arg.mon, arg.day
678        ))
679        .unwrap()
680    }
681}
682
683/// from((Date{},offset_sec()))
684impl From<(Date, i32)> for DateTime {
685    fn from(arg: (Date, i32)) -> Self {
686        Self::from(arg.0)
687            .set_offset(arg.1)
688            .add_sub_sec(-arg.1 as i64)
689    }
690}
691
692impl From<Time> for DateTime {
693    fn from(arg: Time) -> Self {
694        Self::from_str(&format!(
695            "0000-01-01 {:02}:{:02}:{:02}.{:09}Z",
696            arg.hour, arg.minute, arg.sec, arg.nano
697        ))
698        .unwrap()
699    }
700}
701
702impl From<(Date, Time)> for DateTime {
703    fn from(arg: (Date, Time)) -> Self {
704        Self::from_str(&format!(
705            "{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:09}Z",
706            arg.0.year, arg.0.mon, arg.0.day, arg.1.hour, arg.1.minute, arg.1.sec, arg.1.nano
707        ))
708        .unwrap()
709    }
710}
711
712///from(Date{},Time{},offset_sec())
713impl From<(Date, Time, i32)> for DateTime {
714    fn from(arg: (Date, Time, i32)) -> Self {
715        let mut datetime = Self::from_str(&format!(
716            "{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:09}Z",
717            arg.0.year, arg.0.mon, arg.0.day, arg.1.hour, arg.1.minute, arg.1.sec, arg.1.nano
718        ))
719        .unwrap();
720        datetime = datetime.set_offset(arg.2).add_sub_sec(-arg.2 as i64);
721        datetime
722    }
723}
724
725impl FromStr for DateTime {
726    type Err = Error;
727
728    /// parse_from_str
729    ///
730    /// "2019-10-12T07:20:50.52Z"          (UTC+0)
731    /// "2019-10-12T07:20:50.52+00:00"     (UTC+0)
732    /// "2019-10-12T14:20:50.52+07:00"     (UTC+7)
733    /// "2019-10-12T03:20:50.52-04:00"     (UTC-4)
734    fn from_str(arg: &str) -> Result<DateTime, Error> {
735        Self::from_str_default(arg, offset_sec())
736    }
737}
738
739impl Display for DateTime {
740    /// fmt RFC3339Nano = "2006-01-02T15:04:05.999999999"
741    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
742        let mut buf: [u8; 38] = *b"0000-00-00T00:00:00.000000000+00:00:00";
743        let len = self.do_display(&mut buf, true);
744        f.write_str(std::str::from_utf8(&buf[..len]).unwrap())
745    }
746}
747
748impl Ord for DateTime {
749    fn cmp(&self, other: &DateTime) -> cmp::Ordering {
750        self.unix_timestamp_nano().cmp(&other.unix_timestamp_nano())
751    }
752}
753
754impl PartialOrd for DateTime {
755    fn partial_cmp(&self, other: &DateTime) -> Option<cmp::Ordering> {
756        Some(self.unix_timestamp_nano().cmp(&other.unix_timestamp_nano()))
757    }
758}
759
760impl Serialize for DateTime {
761    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
762    where
763        S: Serializer,
764    {
765        serializer.serialize_str(&self.to_string())
766    }
767}
768
769impl<'de> Deserialize<'de> for DateTime {
770    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
771    where
772        D: Deserializer<'de>,
773    {
774        use serde::de::Error;
775        let s = String::deserialize(deserializer)?;
776        DateTime::from_str(&s).map_err(D::Error::custom)
777    }
778}