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
16pub 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
24pub fn set_offset_sec(sec: i32) {
26 GLOBAL_OFFSET.store(sec, Ordering::SeqCst);
27}
28
29#[derive(Clone, Debug, Eq, PartialEq, Hash)]
36pub struct DateTime {
37 pub inner: time1::OffsetDateTime,
38}
39
40impl DateTime {
41 pub fn utc() -> Self {
43 Self::from_system_time(SystemTime::now(), 0)
44 }
45 pub fn now() -> Self {
47 Self::from_system_time(SystemTime::now(), 0).set_offset(offset_sec())
48 }
49
50 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 pub fn add(mut self, d: Duration) -> Self {
65 self.inner = self.inner.add(d);
66 self
67 }
68
69 pub fn sub(mut self, d: Duration) -> Self {
71 self.inner = self.inner.sub(d);
72 self
73 }
74
75 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 pub fn before(&self, other: &DateTime) -> bool {
86 self < other
87 }
88
89 pub fn after(&self, other: &DateTime) -> bool {
91 self > other
92 }
93
94 pub fn unix_timestamp(&self) -> i64 {
96 self.inner.unix_timestamp()
97 }
98
99 pub fn unix_timestamp_micros(&self) -> i64 {
101 (self.inner.unix_timestamp_nanos() / 1000) as i64
102 }
103
104 pub fn unix_timestamp_millis(&self) -> i64 {
106 (self.inner.unix_timestamp_nanos() / 1000000) as i64
107 }
108
109 pub fn unix_timestamp_nano(&self) -> i128 {
111 self.inner.unix_timestamp_nanos()
112 }
113
114 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 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 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 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 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 pub fn parse(format: &str, arg: &str) -> Result<DateTime, Error> {
275 let mut len = 19;
276 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 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 pub fn week_day(&self) -> u8 {
388 let secs_since_epoch = self.unix_timestamp();
389 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 pub fn micro(&self) -> u32 {
409 self.inner.microsecond()
410 }
411
412 pub fn sec(&self) -> u8 {
414 self.inner.second()
415 }
416
417 pub fn minute(&self) -> u8 {
419 self.inner.minute()
420 }
421
422 pub fn hour(&self) -> u8 {
424 self.inner.hour()
425 }
426
427 pub fn day(&self) -> u8 {
429 self.inner.day()
430 }
431
432 pub fn mon(&self) -> u8 {
434 self.inner.month() as u8
435 }
436
437 pub fn year(&self) -> i32 {
439 self.inner.year()
440 }
441
442 pub fn offset(&self) -> i32 {
444 self.inner.offset().whole_seconds()
445 }
446
447 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 pub fn display_stand(&self) -> String {
461 let mut v = self.display(false);
462 v.replace_range(10..11, " ");
463 v
464 }
465
466 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 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
683impl 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
712impl 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 fn from_str(arg: &str) -> Result<DateTime, Error> {
735 Self::from_str_default(arg, offset_sec())
736 }
737}
738
739impl Display for DateTime {
740 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}