1use std::fmt;
6#[cfg(feature = "chrono")]
7use std::sync::OnceLock;
8
9use serde::de::Visitor;
10use serde::Deserialize;
11
12use super::CellErrorType;
13
14const DAY_SECONDS: f64 = 24.0 * 60.0 * 60.;
16const HOUR_SECONDS: u64 = 60 * 60;
17const MINUTE_SECONDS: u64 = 60;
18const YEAR_DAYS: u64 = 365;
19const YEAR_DAYS_4: u64 = YEAR_DAYS * 4 + 1;
20const YEAR_DAYS_100: u64 = YEAR_DAYS * 100 + 25;
21const YEAR_DAYS_400: u64 = YEAR_DAYS * 400 + 97;
22
23#[cfg(feature = "chrono")]
24static EXCEL_EPOCH: OnceLock<chrono::NaiveDateTime> = OnceLock::new();
25
26#[cfg(feature = "chrono")]
27const EXCEL_1900_1904_DIFF: f64 = 1462.;
29
30#[cfg(feature = "chrono")]
31const MS_MULTIPLIER: f64 = 24f64 * 60f64 * 60f64 * 1e+3f64;
32
33#[derive(Debug, Clone, PartialEq, Default)]
36pub enum Data {
37 Int(i64),
39 Float(f64),
41 String(String),
43 Bool(bool),
45 DateTime(ExcelDateTime),
47 DateTimeIso(String),
49 DurationIso(String),
51 Error(CellErrorType),
53 #[default]
55 Empty,
56}
57
58impl DataType for Data {
61 fn is_empty(&self) -> bool {
62 *self == Data::Empty
63 }
64 fn is_int(&self) -> bool {
65 matches!(*self, Data::Int(_))
66 }
67 fn is_float(&self) -> bool {
68 matches!(*self, Data::Float(_))
69 }
70 fn is_bool(&self) -> bool {
71 matches!(*self, Data::Bool(_))
72 }
73 fn is_string(&self) -> bool {
74 matches!(*self, Data::String(_))
75 }
76
77 fn is_duration_iso(&self) -> bool {
78 matches!(*self, Data::DurationIso(_))
79 }
80
81 fn is_datetime(&self) -> bool {
82 matches!(*self, Data::DateTime(_))
83 }
84
85 fn is_datetime_iso(&self) -> bool {
86 matches!(*self, Data::DateTimeIso(_))
87 }
88
89 fn is_error(&self) -> bool {
90 matches!(*self, Data::Error(_))
91 }
92
93 fn get_int(&self) -> Option<i64> {
94 if let Data::Int(v) = self {
95 Some(*v)
96 } else {
97 None
98 }
99 }
100 fn get_float(&self) -> Option<f64> {
101 if let Data::Float(v) = self {
102 Some(*v)
103 } else {
104 None
105 }
106 }
107 fn get_bool(&self) -> Option<bool> {
108 if let Data::Bool(v) = self {
109 Some(*v)
110 } else {
111 None
112 }
113 }
114 fn get_string(&self) -> Option<&str> {
115 if let Data::String(v) = self {
116 Some(&**v)
117 } else {
118 None
119 }
120 }
121
122 fn get_datetime(&self) -> Option<ExcelDateTime> {
123 match self {
124 Data::DateTime(v) => Some(*v),
125 _ => None,
126 }
127 }
128
129 fn get_datetime_iso(&self) -> Option<&str> {
130 match self {
131 Data::DateTimeIso(v) => Some(&**v),
132 _ => None,
133 }
134 }
135
136 fn get_duration_iso(&self) -> Option<&str> {
137 match self {
138 Data::DurationIso(v) => Some(&**v),
139 _ => None,
140 }
141 }
142
143 fn get_error(&self) -> Option<&CellErrorType> {
144 match self {
145 Data::Error(e) => Some(e),
146 _ => None,
147 }
148 }
149
150 fn as_string(&self) -> Option<String> {
151 match self {
152 Data::Float(v) => Some(v.to_string()),
153 Data::Int(v) => Some(v.to_string()),
154 Data::String(v) => Some(v.clone()),
155 _ => None,
156 }
157 }
158
159 fn as_i64(&self) -> Option<i64> {
160 match self {
161 Data::Int(v) => Some(*v),
162 Data::Float(v) => Some(*v as i64),
163 Data::Bool(v) => Some(*v as i64),
164 Data::String(v) => atoi_simd::parse::<i64>(v.as_bytes()).ok(),
165 _ => None,
166 }
167 }
168
169 fn as_f64(&self) -> Option<f64> {
170 match self {
171 Data::Int(v) => Some(*v as f64),
172 Data::Float(v) => Some(*v),
173 Data::Bool(v) => Some((*v as i32).into()),
174 Data::String(v) => fast_float2::parse(v).ok(),
175 _ => None,
176 }
177 }
178}
179
180impl PartialEq<&str> for Data {
181 fn eq(&self, other: &&str) -> bool {
182 matches!(self, Data::String(s) if s == other)
183 }
184}
185
186impl PartialEq<str> for Data {
187 fn eq(&self, other: &str) -> bool {
188 matches!(self, Data::String(s) if s == other)
189 }
190}
191
192impl PartialEq<f64> for Data {
193 fn eq(&self, other: &f64) -> bool {
194 matches!(self, Data::Float(s) if *s == *other)
195 }
196}
197
198impl PartialEq<bool> for Data {
199 fn eq(&self, other: &bool) -> bool {
200 matches!(self, Data::Bool(s) if *s == *other)
201 }
202}
203
204impl PartialEq<i64> for Data {
205 fn eq(&self, other: &i64) -> bool {
206 matches!(self, Data::Int(s) if *s == *other)
207 }
208}
209
210impl fmt::Display for Data {
211 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
212 match self {
213 Data::Int(e) => write!(f, "{e}"),
214 Data::Float(e) => write!(f, "{e}"),
215 Data::String(e) => write!(f, "{e}"),
216 Data::Bool(e) => write!(f, "{e}"),
217 Data::DateTime(e) => write!(f, "{e}"),
218 Data::DateTimeIso(e) => write!(f, "{e}"),
219 Data::DurationIso(e) => write!(f, "{e}"),
220 Data::Error(e) => write!(f, "{e}"),
221 Data::Empty => Ok(()),
222 }
223 }
224}
225
226impl<'de> Deserialize<'de> for Data {
227 #[inline]
228 fn deserialize<D>(deserializer: D) -> Result<Data, D::Error>
229 where
230 D: serde::Deserializer<'de>,
231 {
232 struct DataVisitor;
233
234 impl<'de> Visitor<'de> for DataVisitor {
235 type Value = Data;
236
237 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
238 formatter.write_str("any valid JSON value")
239 }
240
241 #[inline]
242 fn visit_bool<E>(self, value: bool) -> Result<Data, E> {
243 Ok(Data::Bool(value))
244 }
245
246 #[inline]
247 fn visit_i64<E>(self, value: i64) -> Result<Data, E> {
248 Ok(Data::Int(value))
249 }
250
251 #[inline]
252 fn visit_u64<E>(self, value: u64) -> Result<Data, E> {
253 Ok(Data::Int(value as i64))
254 }
255
256 #[inline]
257 fn visit_f64<E>(self, value: f64) -> Result<Data, E> {
258 Ok(Data::Float(value))
259 }
260
261 #[inline]
262 fn visit_str<E>(self, value: &str) -> Result<Data, E>
263 where
264 E: serde::de::Error,
265 {
266 self.visit_string(String::from(value))
267 }
268
269 #[inline]
270 fn visit_string<E>(self, value: String) -> Result<Data, E> {
271 Ok(Data::String(value))
272 }
273
274 #[inline]
275 fn visit_none<E>(self) -> Result<Data, E> {
276 Ok(Data::Empty)
277 }
278
279 #[inline]
280 fn visit_some<D>(self, deserializer: D) -> Result<Data, D::Error>
281 where
282 D: serde::Deserializer<'de>,
283 {
284 Deserialize::deserialize(deserializer)
285 }
286
287 #[inline]
288 fn visit_unit<E>(self) -> Result<Data, E> {
289 Ok(Data::Empty)
290 }
291 }
292
293 deserializer.deserialize_any(DataVisitor)
294 }
295}
296
297macro_rules! define_from {
298 ($variant:path, $ty:ty) => {
299 impl From<$ty> for Data {
300 fn from(v: $ty) -> Self {
301 $variant(v)
302 }
303 }
304 };
305}
306
307define_from!(Data::Int, i64);
308define_from!(Data::Float, f64);
309define_from!(Data::String, String);
310define_from!(Data::Bool, bool);
311define_from!(Data::Error, CellErrorType);
312
313impl<'a> From<&'a str> for Data {
314 fn from(v: &'a str) -> Self {
315 Data::String(String::from(v))
316 }
317}
318
319impl From<()> for Data {
320 fn from(_: ()) -> Self {
321 Data::Empty
322 }
323}
324
325impl<T> From<Option<T>> for Data
326where
327 Data: From<T>,
328{
329 fn from(v: Option<T>) -> Self {
330 match v {
331 Some(v) => From::from(v),
332 None => Data::Empty,
333 }
334 }
335}
336
337#[derive(Debug, Clone, PartialEq, Default)]
340pub enum DataRef<'a> {
341 Int(i64),
343 Float(f64),
345 String(String),
347 SharedString(&'a str),
349 Bool(bool),
351 DateTime(ExcelDateTime),
353 DateTimeIso(String),
355 DurationIso(String),
357 Error(CellErrorType),
359 #[default]
361 Empty,
362}
363
364impl DataType for DataRef<'_> {
365 fn is_empty(&self) -> bool {
366 *self == DataRef::Empty
367 }
368
369 fn is_int(&self) -> bool {
370 matches!(*self, DataRef::Int(_))
371 }
372
373 fn is_float(&self) -> bool {
374 matches!(*self, DataRef::Float(_))
375 }
376
377 fn is_bool(&self) -> bool {
378 matches!(*self, DataRef::Bool(_))
379 }
380
381 fn is_string(&self) -> bool {
382 matches!(*self, DataRef::String(_) | DataRef::SharedString(_))
383 }
384
385 fn is_duration_iso(&self) -> bool {
386 matches!(*self, DataRef::DurationIso(_))
387 }
388
389 fn is_datetime(&self) -> bool {
390 matches!(*self, DataRef::DateTime(_))
391 }
392
393 fn is_datetime_iso(&self) -> bool {
394 matches!(*self, DataRef::DateTimeIso(_))
395 }
396
397 fn is_error(&self) -> bool {
398 matches!(*self, DataRef::Error(_))
399 }
400
401 fn get_int(&self) -> Option<i64> {
402 if let DataRef::Int(v) = self {
403 Some(*v)
404 } else {
405 None
406 }
407 }
408
409 fn get_float(&self) -> Option<f64> {
410 if let DataRef::Float(v) = self {
411 Some(*v)
412 } else {
413 None
414 }
415 }
416
417 fn get_bool(&self) -> Option<bool> {
418 if let DataRef::Bool(v) = self {
419 Some(*v)
420 } else {
421 None
422 }
423 }
424
425 fn get_string(&self) -> Option<&str> {
426 match self {
427 DataRef::String(v) => Some(&**v),
428 DataRef::SharedString(v) => Some(v),
429 _ => None,
430 }
431 }
432
433 fn get_datetime(&self) -> Option<ExcelDateTime> {
434 match self {
435 DataRef::DateTime(v) => Some(*v),
436 _ => None,
437 }
438 }
439
440 fn get_datetime_iso(&self) -> Option<&str> {
441 match self {
442 DataRef::DateTimeIso(v) => Some(&**v),
443 _ => None,
444 }
445 }
446
447 fn get_duration_iso(&self) -> Option<&str> {
448 match self {
449 DataRef::DurationIso(v) => Some(&**v),
450 _ => None,
451 }
452 }
453
454 fn get_error(&self) -> Option<&CellErrorType> {
455 match self {
456 DataRef::Error(e) => Some(e),
457 _ => None,
458 }
459 }
460
461 fn as_string(&self) -> Option<String> {
462 match self {
463 DataRef::Float(v) => Some(v.to_string()),
464 DataRef::Int(v) => Some(v.to_string()),
465 DataRef::String(v) => Some(v.clone()),
466 DataRef::SharedString(v) => Some(v.to_string()),
467 _ => None,
468 }
469 }
470
471 fn as_i64(&self) -> Option<i64> {
472 match self {
473 DataRef::Int(v) => Some(*v),
474 DataRef::Float(v) => Some(*v as i64),
475 DataRef::Bool(v) => Some(*v as i64),
476 DataRef::String(v) => atoi_simd::parse::<i64>(v.as_bytes()).ok(),
477 DataRef::SharedString(v) => atoi_simd::parse::<i64>(v.as_bytes()).ok(),
478 _ => None,
479 }
480 }
481
482 fn as_f64(&self) -> Option<f64> {
483 match self {
484 DataRef::Int(v) => Some(*v as f64),
485 DataRef::Float(v) => Some(*v),
486 DataRef::Bool(v) => Some((*v as i32).into()),
487 DataRef::String(v) => fast_float2::parse(v).ok(),
488 DataRef::SharedString(v) => fast_float2::parse(v).ok(),
489 _ => None,
490 }
491 }
492}
493
494impl PartialEq<&str> for DataRef<'_> {
495 fn eq(&self, other: &&str) -> bool {
496 matches!(self, DataRef::String(s) if s == other)
497 }
498}
499
500impl PartialEq<str> for DataRef<'_> {
501 fn eq(&self, other: &str) -> bool {
502 matches!(self, DataRef::String(s) if s == other)
503 }
504}
505
506impl PartialEq<f64> for DataRef<'_> {
507 fn eq(&self, other: &f64) -> bool {
508 matches!(self, DataRef::Float(s) if *s == *other)
509 }
510}
511
512impl PartialEq<bool> for DataRef<'_> {
513 fn eq(&self, other: &bool) -> bool {
514 matches!(self, DataRef::Bool(s) if *s == *other)
515 }
516}
517
518impl PartialEq<i64> for DataRef<'_> {
519 fn eq(&self, other: &i64) -> bool {
520 matches!(self, DataRef::Int(s) if *s == *other)
521 }
522}
523
524pub trait DataType {
527 fn is_empty(&self) -> bool;
529
530 fn is_int(&self) -> bool;
532
533 fn is_float(&self) -> bool;
535
536 fn is_bool(&self) -> bool;
538
539 fn is_string(&self) -> bool;
541
542 fn is_error(&self) -> bool;
544
545 fn is_duration_iso(&self) -> bool;
547
548 fn is_datetime(&self) -> bool;
550
551 fn is_datetime_iso(&self) -> bool;
553
554 fn get_int(&self) -> Option<i64>;
556
557 fn get_float(&self) -> Option<f64>;
559
560 fn get_bool(&self) -> Option<bool>;
562
563 fn get_string(&self) -> Option<&str>;
565
566 fn get_datetime(&self) -> Option<ExcelDateTime>;
568
569 fn get_datetime_iso(&self) -> Option<&str>;
571
572 fn get_duration_iso(&self) -> Option<&str>;
574
575 fn get_error(&self) -> Option<&CellErrorType>;
577
578 fn as_string(&self) -> Option<String>;
580
581 fn as_i64(&self) -> Option<i64>;
583
584 fn as_f64(&self) -> Option<f64>;
586
587 #[cfg(feature = "chrono")]
589 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
590 fn as_date(&self) -> Option<chrono::NaiveDate> {
591 use std::str::FromStr;
592 if self.is_datetime_iso() {
593 self.as_datetime().map(|dt| dt.date()).or_else(|| {
594 self.get_datetime_iso()
595 .and_then(|s| chrono::NaiveDate::from_str(s).ok())
596 })
597 } else {
598 self.as_datetime().map(|dt| dt.date())
599 }
600 }
601
602 #[cfg(feature = "chrono")]
604 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
605 fn as_time(&self) -> Option<chrono::NaiveTime> {
606 use std::str::FromStr;
607 if self.is_datetime_iso() {
608 self.as_datetime().map(|dt| dt.time()).or_else(|| {
609 self.get_datetime_iso()
610 .and_then(|s| chrono::NaiveTime::from_str(s).ok())
611 })
612 } else if self.is_duration_iso() {
613 self.get_duration_iso()
614 .and_then(|s| chrono::NaiveTime::parse_from_str(s, "PT%HH%MM%S%.fS").ok())
615 } else {
616 self.as_datetime().map(|dt| dt.time())
617 }
618 }
619
620 #[cfg(feature = "chrono")]
622 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
623 fn as_duration(&self) -> Option<chrono::Duration> {
624 use chrono::Timelike;
625
626 if self.is_datetime() {
627 self.get_datetime().and_then(|dt| dt.as_duration())
628 } else if self.is_duration_iso() {
629 self.as_time().map(|t| {
632 chrono::Duration::nanoseconds(
633 t.num_seconds_from_midnight() as i64 * 1_000_000_000 + t.nanosecond() as i64,
634 )
635 })
636 } else {
637 None
638 }
639 }
640
641 #[cfg(feature = "chrono")]
643 fn as_datetime(&self) -> Option<chrono::NaiveDateTime> {
644 use std::str::FromStr;
645
646 if self.is_int() || self.is_float() {
647 self.as_f64()
648 .map(|f| ExcelDateTime::from_value_only(f).as_datetime())
649 } else if self.is_datetime() {
650 self.get_datetime().map(|d| d.as_datetime())
651 } else if self.is_datetime_iso() {
652 self.get_datetime_iso()
653 .map(|s| chrono::NaiveDateTime::from_str(s).ok())
654 } else {
655 None
656 }
657 .flatten()
658 }
659}
660
661impl<'a> From<DataRef<'a>> for Data {
662 fn from(value: DataRef<'a>) -> Self {
663 match value {
664 DataRef::Int(v) => Data::Int(v),
665 DataRef::Float(v) => Data::Float(v),
666 DataRef::String(v) => Data::String(v),
667 DataRef::SharedString(v) => Data::String(v.into()),
668 DataRef::Bool(v) => Data::Bool(v),
669 DataRef::DateTime(v) => Data::DateTime(v),
670 DataRef::DateTimeIso(v) => Data::DateTimeIso(v),
671 DataRef::DurationIso(v) => Data::DurationIso(v),
672 DataRef::Error(v) => Data::Error(v),
673 DataRef::Empty => Data::Empty,
674 }
675 }
676}
677
678#[derive(Debug, Clone, Copy, PartialEq)]
681pub enum ExcelDateTimeType {
682 DateTime,
684 TimeDelta,
686}
687
688#[derive(Debug, Clone, Copy, PartialEq)]
690pub struct ExcelDateTime {
691 value: f64,
692 datetime_type: ExcelDateTimeType,
693 is_1904: bool,
694}
695
696impl ExcelDateTime {
697 pub fn new(value: f64, datetime_type: ExcelDateTimeType, is_1904: bool) -> Self {
699 ExcelDateTime {
700 value,
701 datetime_type,
702 is_1904,
703 }
704 }
705
706 #[cfg(feature = "chrono")]
708 fn from_value_only(value: f64) -> Self {
709 ExcelDateTime {
710 value,
711 ..Default::default()
712 }
713 }
714
715 pub fn is_duration(&self) -> bool {
717 matches!(self.datetime_type, ExcelDateTimeType::TimeDelta)
718 }
719
720 pub fn is_datetime(&self) -> bool {
722 matches!(self.datetime_type, ExcelDateTimeType::DateTime)
723 }
724
725 pub fn as_f64(&self) -> f64 {
727 self.value
728 }
729
730 pub fn to_ymd_hms_milli(&self) -> (u16, u8, u8, u8, u8, u8, u16) {
777 Self::excel_to_standard_datetime(self.value, self.is_1904)
778 }
779
780 #[cfg(feature = "chrono")]
782 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
783 pub fn as_duration(&self) -> Option<chrono::Duration> {
784 let ms = self.value * MS_MULTIPLIER;
785 Some(chrono::Duration::milliseconds(ms.round() as i64))
786 }
787
788 #[cfg(feature = "chrono")]
790 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
791 pub fn as_datetime(&self) -> Option<chrono::NaiveDateTime> {
792 let excel_epoch = EXCEL_EPOCH.get_or_init(|| {
793 chrono::NaiveDate::from_ymd_opt(1899, 12, 30)
794 .unwrap()
795 .and_time(chrono::NaiveTime::MIN)
796 });
797 let f = if self.is_1904 {
798 self.value + EXCEL_1900_1904_DIFF
799 } else {
800 self.value
801 };
802 let f = if f >= 60.0 { f } else { f + 1.0 };
803 let ms = f * MS_MULTIPLIER;
804 let excel_duration = chrono::Duration::milliseconds(ms.round() as i64);
805 excel_epoch.checked_add_signed(excel_duration)
806 }
807
808 fn excel_to_standard_datetime(
832 excel_datetime: f64,
833 is_1904: bool,
834 ) -> (u16, u8, u8, u8, u8, u8, u16) {
835 let mut months = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
836
837 let mut days = excel_datetime.floor() as u64;
839
840 if is_1904 {
842 days += 111_033;
844 } else if days > YEAR_DAYS {
845 days += 109_571;
847 } else {
848 days += 109_572;
850 }
851
852 let year_days_400 = days / YEAR_DAYS_400;
854 let mut days = days % YEAR_DAYS_400;
855
856 let year_days_100;
860 if days < YEAR_DAYS_100 {
861 year_days_100 = days / YEAR_DAYS_100;
862 days %= YEAR_DAYS_100;
863 } else {
864 year_days_100 = 1 + (days - YEAR_DAYS_100) / (YEAR_DAYS_100 - 1);
865 days = (days - YEAR_DAYS_100) % (YEAR_DAYS_100 - 1);
866 }
867
868 let year_days_4;
874 let mut non_leap_year_block = false;
875 if year_days_100 == 0 {
876 year_days_4 = days / YEAR_DAYS_4;
878 days %= YEAR_DAYS_4;
879 } else if days < YEAR_DAYS_4 {
880 year_days_4 = days / (YEAR_DAYS_4 - 1);
882 days %= YEAR_DAYS_4 - 1;
883 non_leap_year_block = true;
884 } else {
885 year_days_4 = 1 + (days - (YEAR_DAYS_4 - 1)) / YEAR_DAYS_4;
887 days = (days - (YEAR_DAYS_4 - 1)) % YEAR_DAYS_4;
888 }
889
890 let year_days_1;
893 if non_leap_year_block {
894 year_days_1 = days / YEAR_DAYS;
896 days %= YEAR_DAYS;
897 } else if days < YEAR_DAYS + 1 {
898 year_days_1 = days / (YEAR_DAYS + 1);
900 days %= YEAR_DAYS + 1;
901 } else {
902 year_days_1 = 1 + (days - (YEAR_DAYS + 1)) / YEAR_DAYS;
904 days = (days - (YEAR_DAYS + 1)) % YEAR_DAYS;
905 }
906
907 let year = 1600 + year_days_400 * 400 + year_days_100 * 100 + year_days_4 * 4 + year_days_1;
909
910 days += 1;
912
913 if Self::is_leap_year(year) {
915 months[1] = 29;
916 }
917
918 if !is_1904 && year == 1900 {
920 months[1] = 29;
921
922 if excel_datetime.trunc() == 366.0 {
924 days += 1;
925 }
926 }
927
928 let mut month = 1;
930 for month_days in months {
931 if days > month_days {
932 days -= month_days;
933 month += 1;
934 } else {
935 break;
936 }
937 }
938
939 let day = days;
941
942 let time = excel_datetime.fract();
944 let mut milli = ((time * DAY_SECONDS).fract() * 1000.0).round() as u64;
945 let mut day_as_seconds = (time * DAY_SECONDS) as u64;
946
947 if milli == 1000 {
949 day_as_seconds += 1;
950 milli = 0;
951 }
952
953 let hour = day_as_seconds / HOUR_SECONDS;
955 let min = (day_as_seconds - hour * HOUR_SECONDS) / MINUTE_SECONDS;
956 let sec = (day_as_seconds - hour * HOUR_SECONDS - min * MINUTE_SECONDS) % MINUTE_SECONDS;
957
958 (
960 year as u16,
961 month as u8,
962 day as u8,
963 hour as u8,
964 min as u8,
965 sec as u8,
966 milli as u16,
967 )
968 }
969
970 fn is_leap_year(year: u64) -> bool {
972 year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
973 }
974}
975
976impl Default for ExcelDateTime {
977 fn default() -> Self {
978 ExcelDateTime {
979 value: 0.,
980 datetime_type: ExcelDateTimeType::DateTime,
981 is_1904: false,
982 }
983 }
984}
985
986impl fmt::Display for ExcelDateTime {
987 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
988 write!(f, "{}", self.value)
989 }
990}
991
992#[cfg(all(test, feature = "chrono"))]
993mod date_tests {
994 use super::*;
995
996 #[test]
997 fn test_dates() {
998 use chrono::{Duration, NaiveDate, NaiveDateTime, NaiveTime};
999
1000 #[allow(clippy::excessive_precision)]
1001 let unix_epoch = Data::Float(25569.);
1002 assert_eq!(
1003 unix_epoch.as_datetime(),
1004 Some(NaiveDateTime::new(
1005 NaiveDate::from_ymd_opt(1970, 1, 1).unwrap(),
1006 NaiveTime::from_hms_opt(0, 0, 0).unwrap(),
1007 ))
1008 );
1009
1010 let unix_epoch_precision = Data::Float(44484.7916666667);
1012 assert_eq!(
1013 unix_epoch_precision.as_datetime(),
1014 Some(NaiveDateTime::new(
1015 NaiveDate::from_ymd_opt(2021, 10, 15).unwrap(),
1016 NaiveTime::from_hms_opt(19, 0, 0).unwrap(),
1017 ))
1018 );
1019
1020 #[allow(clippy::excessive_precision)]
1022 let date = Data::Float(0.18737500000000001);
1023 assert_eq!(
1024 date.as_time(),
1025 Some(NaiveTime::from_hms_milli_opt(4, 29, 49, 200).unwrap())
1026 );
1027
1028 #[allow(clippy::excessive_precision)]
1029 let date = Data::Float(0.25951736111111101);
1030 assert_eq!(
1031 date.as_time(),
1032 Some(NaiveTime::from_hms_milli_opt(6, 13, 42, 300).unwrap())
1033 );
1034
1035 assert_eq!(Data::Float(1e20).as_time(), None);
1037
1038 #[allow(clippy::excessive_precision)]
1039 let unix_epoch_15h30m = Data::Float(25569.645833333333333);
1040 let chrono_dt = NaiveDateTime::new(
1041 NaiveDate::from_ymd_opt(1970, 1, 1).unwrap(),
1042 NaiveTime::from_hms_opt(15, 30, 0).unwrap(),
1043 );
1044 let micro = Duration::microseconds(1);
1045 assert!(unix_epoch_15h30m.as_datetime().unwrap() - chrono_dt < micro);
1046 }
1047
1048 #[test]
1049 fn test_int_dates() {
1050 use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
1051
1052 let unix_epoch = Data::Int(25569);
1053 assert_eq!(
1054 unix_epoch.as_datetime(),
1055 Some(NaiveDateTime::new(
1056 NaiveDate::from_ymd_opt(1970, 1, 1).unwrap(),
1057 NaiveTime::from_hms_opt(0, 0, 0).unwrap(),
1058 ))
1059 );
1060
1061 let time = Data::Int(44060);
1062 assert_eq!(
1063 time.as_datetime(),
1064 Some(NaiveDateTime::new(
1065 NaiveDate::from_ymd_opt(2020, 8, 17).unwrap(),
1066 NaiveTime::from_hms_opt(0, 0, 0).unwrap(),
1067 ))
1068 );
1069 }
1070}
1071
1072#[cfg(test)]
1073mod tests {
1074 use super::*;
1075
1076 #[test]
1077 fn test_partial_eq() {
1078 assert_eq!(Data::String("value".to_string()), "value");
1079 assert_eq!(Data::String("value".to_string()), "value"[..]);
1080 assert_eq!(Data::Float(100.0), 100.0f64);
1081 assert_eq!(Data::Bool(true), true);
1082 assert_eq!(Data::Int(100), 100i64);
1083 }
1084
1085 #[test]
1086 fn test_as_i64_with_bools() {
1087 assert_eq!(Data::Bool(true).as_i64(), Some(1));
1088 assert_eq!(Data::Bool(false).as_i64(), Some(0));
1089 assert_eq!(DataRef::Bool(true).as_i64(), Some(1));
1090 assert_eq!(DataRef::Bool(false).as_i64(), Some(0));
1091 }
1092
1093 #[test]
1094 fn test_as_f64_with_bools() {
1095 assert_eq!(Data::Bool(true).as_f64(), Some(1.0));
1096 assert_eq!(Data::Bool(false).as_f64(), Some(0.0));
1097 assert_eq!(DataRef::Bool(true).as_f64(), Some(1.0));
1098 assert_eq!(DataRef::Bool(false).as_f64(), Some(0.0));
1099 }
1100
1101 #[test]
1102 fn test_datetimes_1900_epoch() {
1103 #[allow(clippy::excessive_precision)]
1104 let test_data = vec![
1105 (0.0, (1899, 12, 31, 0, 0, 0, 0)),
1106 (0.99998842592, (1899, 12, 31, 23, 59, 59, 0)),
1107 (30188.010650613425, (1982, 8, 25, 0, 15, 20, 213)),
1108 (60376.011670023145, (2065, 4, 19, 0, 16, 48, 290)),
1109 (90565.038488958337, (2147, 12, 15, 0, 55, 25, 446)),
1110 (120753.04359827546, (2230, 8, 10, 1, 2, 46, 891)),
1111 (150942.04462496529, (2313, 4, 6, 1, 4, 15, 597)),
1112 (181130.04838991899, (2395, 11, 30, 1, 9, 40, 889)),
1113 (211318.04968240741, (2478, 7, 25, 1, 11, 32, 560)),
1114 (241507.06272186342, (2561, 3, 21, 1, 30, 19, 169)),
1115 (271695.07529606484, (2643, 11, 15, 1, 48, 25, 580)),
1116 (301884.08578609955, (2726, 7, 12, 2, 3, 31, 919)),
1117 (332072.09111094906, (2809, 3, 6, 2, 11, 11, 986)),
1118 (362261.10042934027, (2891, 10, 31, 2, 24, 37, 95)),
1119 (392449.10772245371, (2974, 6, 26, 2, 35, 7, 220)),
1120 (422637.11472348380, (3057, 2, 19, 2, 45, 12, 109)),
1121 (452826.12962951389, (3139, 10, 17, 3, 6, 39, 990)),
1122 (483014.13065105322, (3222, 6, 11, 3, 8, 8, 251)),
1123 (513203.13834000000, (3305, 2, 5, 3, 19, 12, 576)),
1124 (543391.14563164348, (3387, 10, 1, 3, 29, 42, 574)),
1125 (573579.15105107636, (3470, 5, 27, 3, 37, 30, 813)),
1126 (603768.17683137732, (3553, 1, 21, 4, 14, 38, 231)),
1127 (633956.17810832174, (3635, 9, 16, 4, 16, 28, 559)),
1128 (664145.17914608796, (3718, 5, 13, 4, 17, 58, 222)),
1129 (694333.18173372687, (3801, 1, 6, 4, 21, 41, 794)),
1130 (724522.20596981479, (3883, 9, 2, 4, 56, 35, 792)),
1131 (754710.22586672450, (3966, 4, 28, 5, 25, 14, 885)),
1132 (784898.22645513888, (4048, 12, 21, 5, 26, 5, 724)),
1133 (815087.24078782403, (4131, 8, 18, 5, 46, 44, 68)),
1134 (845275.24167987274, (4214, 4, 13, 5, 48, 1, 141)),
1135 (875464.24574438657, (4296, 12, 7, 5, 53, 52, 315)),
1136 (905652.26028449077, (4379, 8, 3, 6, 14, 48, 580)),
1137 (935840.28212659725, (4462, 3, 28, 6, 46, 15, 738)),
1138 (966029.31343063654, (4544, 11, 22, 7, 31, 20, 407)),
1139 (996217.33233511576, (4627, 7, 19, 7, 58, 33, 754)),
1140 (1026406.3386936343, (4710, 3, 15, 8, 7, 43, 130)),
1141 (1056594.3536005903, (4792, 11, 7, 8, 29, 11, 91)),
1142 (1086783.3807329629, (4875, 7, 4, 9, 8, 15, 328)),
1143 (1116971.3963169097, (4958, 2, 27, 9, 30, 41, 781)),
1144 (1147159.3986627546, (5040, 10, 23, 9, 34, 4, 462)),
1145 (1177348.4009715857, (5123, 6, 20, 9, 37, 23, 945)),
1146 (1207536.4013501736, (5206, 2, 12, 9, 37, 56, 655)),
1147 (1237725.4063915510, (5288, 10, 8, 9, 45, 12, 230)),
1148 (1267913.4126710880, (5371, 6, 4, 9, 54, 14, 782)),
1149 (1298101.4127558796, (5454, 1, 28, 9, 54, 22, 108)),
1150 (1328290.4177795255, (5536, 9, 24, 10, 1, 36, 151)),
1151 (1358478.5068125231, (5619, 5, 20, 12, 9, 48, 602)),
1152 (1388667.5237100578, (5702, 1, 14, 12, 34, 8, 549)),
1153 (1418855.5389640625, (5784, 9, 8, 12, 56, 6, 495)),
1154 (1449044.5409515856, (5867, 5, 6, 12, 58, 58, 217)),
1155 (1479232.5416002662, (5949, 12, 30, 12, 59, 54, 263)),
1156 (1509420.5657561459, (6032, 8, 24, 13, 34, 41, 331)),
1157 (1539609.5822754744, (6115, 4, 21, 13, 58, 28, 601)),
1158 (1569797.5849178126, (6197, 12, 14, 14, 2, 16, 899)),
1159 (1599986.6085352316, (6280, 8, 10, 14, 36, 17, 444)),
1160 (1630174.6096927200, (6363, 4, 6, 14, 37, 57, 451)),
1161 (1660363.6234115392, (6445, 11, 30, 14, 57, 42, 757)),
1162 (1690551.6325035533, (6528, 7, 26, 15, 10, 48, 307)),
1163 (1720739.6351839120, (6611, 3, 22, 15, 14, 39, 890)),
1164 (1750928.6387498612, (6693, 11, 15, 15, 19, 47, 988)),
1165 (1781116.6697262037, (6776, 7, 11, 16, 4, 24, 344)),
1166 (1811305.6822216667, (6859, 3, 7, 16, 22, 23, 952)),
1167 (1841493.6874536921, (6941, 10, 31, 16, 29, 55, 999)),
1168 (1871681.7071789235, (7024, 6, 26, 16, 58, 20, 259)),
1169 (1901870.7111390624, (7107, 2, 21, 17, 4, 2, 415)),
1170 (1932058.7211762732, (7189, 10, 16, 17, 18, 29, 630)),
1171 (1962247.7412190163, (7272, 6, 11, 17, 47, 21, 323)),
1172 (1992435.7454845603, (7355, 2, 5, 17, 53, 29, 866)),
1173 (2022624.7456143056, (7437, 10, 2, 17, 53, 41, 76)),
1174 (2052812.7465977315, (7520, 5, 28, 17, 55, 6, 44)),
1175 (2083000.7602910995, (7603, 1, 21, 18, 14, 49, 151)),
1176 (2113189.7623349307, (7685, 9, 16, 18, 17, 45, 738)),
1177 (2143377.7708298611, (7768, 5, 12, 18, 29, 59, 700)),
1178 (2173566.7731624190, (7851, 1, 7, 18, 33, 21, 233)),
1179 (2203754.8016744559, (7933, 9, 2, 19, 14, 24, 673)),
1180 (2233942.8036205554, (8016, 4, 27, 19, 17, 12, 816)),
1181 (2264131.8080603937, (8098, 12, 22, 19, 23, 36, 418)),
1182 (2294319.8239109721, (8181, 8, 17, 19, 46, 25, 908)),
1183 (2324508.8387420601, (8264, 4, 13, 20, 7, 47, 314)),
1184 (2354696.8552963310, (8346, 12, 8, 20, 31, 37, 603)),
1185 (2384885.8610853008, (8429, 8, 3, 20, 39, 57, 770)),
1186 (2415073.8682530904, (8512, 3, 29, 20, 50, 17, 67)),
1187 (2445261.8770581828, (8594, 11, 22, 21, 2, 57, 827)),
1188 (2475450.8910360998, (8677, 7, 19, 21, 23, 5, 519)),
1189 (2505638.8991848612, (8760, 3, 14, 21, 34, 49, 572)),
1190 (2535827.9021521294, (8842, 11, 8, 21, 39, 5, 944)),
1191 (2566015.9022965971, (8925, 7, 4, 21, 39, 18, 426)),
1192 (2596203.9070343636, (9008, 2, 28, 21, 46, 7, 769)),
1193 (2626392.9152275696, (9090, 10, 24, 21, 57, 55, 662)),
1194 (2656580.9299968979, (9173, 6, 19, 22, 19, 11, 732)),
1195 (2686769.9332335186, (9256, 2, 13, 22, 23, 51, 376)),
1196 (2716957.9360968866, (9338, 10, 9, 22, 27, 58, 771)),
1197 (2747146.9468795368, (9421, 6, 5, 22, 43, 30, 392)),
1198 (2777334.9502990046, (9504, 1, 30, 22, 48, 25, 834)),
1199 (2807522.9540709145, (9586, 9, 24, 22, 53, 51, 727)),
1200 (2837711.9673210187, (9669, 5, 20, 23, 12, 56, 536)),
1201 (2867899.9693762613, (9752, 1, 14, 23, 15, 54, 109)),
1202 (2898088.9702850925, (9834, 9, 10, 23, 17, 12, 632)),
1203 (2958465.9999884260, (9999, 12, 31, 23, 59, 59, 0)),
1204 ];
1205
1206 for test in test_data {
1207 let (excel_serial_datetime, expected) = test;
1208 let datetime =
1209 ExcelDateTime::new(excel_serial_datetime, ExcelDateTimeType::DateTime, false);
1210 let got = datetime.to_ymd_hms_milli();
1211
1212 assert_eq!(expected, got);
1213 }
1214 }
1215
1216 #[test]
1217 fn test_dates_only_1900_epoch() {
1218 let test_data = vec![
1219 (0.0, (1899, 12, 31)),
1220 (1.0, (1900, 1, 1)),
1221 (58.0, (1900, 2, 27)),
1222 (59.0, (1900, 2, 28)),
1223 (60.0, (1900, 2, 29)),
1224 (61.0, (1900, 3, 1)),
1225 (62.0, (1900, 3, 2)),
1226 (71.0, (1900, 3, 11)),
1227 (99.0, (1900, 4, 8)),
1228 (256.0, (1900, 9, 12)),
1229 (364.0, (1900, 12, 29)),
1230 (365.0, (1900, 12, 30)),
1231 (366.0, (1900, 12, 31)),
1232 (367.0, (1901, 1, 1)),
1233 (489.0, (1901, 5, 3)),
1234 (652.0, (1901, 10, 13)),
1235 (777.0, (1902, 2, 15)),
1236 (888.0, (1902, 6, 6)),
1237 (999.0, (1902, 9, 25)),
1238 (1001.0, (1902, 9, 27)),
1239 (1212.0, (1903, 4, 26)),
1240 (1313.0, (1903, 8, 5)),
1241 (1461.0, (1903, 12, 31)),
1242 (1462.0, (1904, 1, 1)),
1243 (1520.0, (1904, 2, 28)),
1244 (1521.0, (1904, 2, 29)),
1245 (1522.0, (1904, 3, 1)),
1246 (2615.0, (1907, 2, 27)),
1247 (2616.0, (1907, 2, 28)),
1248 (2617.0, (1907, 3, 1)),
1249 (2618.0, (1907, 3, 2)),
1250 (2619.0, (1907, 3, 3)),
1251 (2620.0, (1907, 3, 4)),
1252 (2621.0, (1907, 3, 5)),
1253 (2622.0, (1907, 3, 6)),
1254 (36161.0, (1999, 1, 1)),
1255 (36191.0, (1999, 1, 31)),
1256 (36192.0, (1999, 2, 1)),
1257 (36219.0, (1999, 2, 28)),
1258 (36220.0, (1999, 3, 1)),
1259 (36250.0, (1999, 3, 31)),
1260 (36251.0, (1999, 4, 1)),
1261 (36280.0, (1999, 4, 30)),
1262 (36281.0, (1999, 5, 1)),
1263 (36311.0, (1999, 5, 31)),
1264 (36312.0, (1999, 6, 1)),
1265 (36341.0, (1999, 6, 30)),
1266 (36342.0, (1999, 7, 1)),
1267 (36372.0, (1999, 7, 31)),
1268 (36373.0, (1999, 8, 1)),
1269 (36403.0, (1999, 8, 31)),
1270 (36404.0, (1999, 9, 1)),
1271 (36433.0, (1999, 9, 30)),
1272 (36434.0, (1999, 10, 1)),
1273 (36464.0, (1999, 10, 31)),
1274 (36465.0, (1999, 11, 1)),
1275 (36494.0, (1999, 11, 30)),
1276 (36495.0, (1999, 12, 1)),
1277 (36525.0, (1999, 12, 31)),
1278 (36526.0, (2000, 1, 1)),
1279 (36556.0, (2000, 1, 31)),
1280 (36557.0, (2000, 2, 1)),
1281 (36585.0, (2000, 2, 29)),
1282 (36586.0, (2000, 3, 1)),
1283 (36616.0, (2000, 3, 31)),
1284 (36617.0, (2000, 4, 1)),
1285 (36646.0, (2000, 4, 30)),
1286 (36647.0, (2000, 5, 1)),
1287 (36677.0, (2000, 5, 31)),
1288 (36678.0, (2000, 6, 1)),
1289 (36707.0, (2000, 6, 30)),
1290 (36708.0, (2000, 7, 1)),
1291 (36738.0, (2000, 7, 31)),
1292 (36739.0, (2000, 8, 1)),
1293 (36769.0, (2000, 8, 31)),
1294 (36770.0, (2000, 9, 1)),
1295 (36799.0, (2000, 9, 30)),
1296 (36800.0, (2000, 10, 1)),
1297 (36830.0, (2000, 10, 31)),
1298 (36831.0, (2000, 11, 1)),
1299 (36860.0, (2000, 11, 30)),
1300 (36861.0, (2000, 12, 1)),
1301 (36891.0, (2000, 12, 31)),
1302 (36892.0, (2001, 1, 1)),
1303 (36922.0, (2001, 1, 31)),
1304 (36923.0, (2001, 2, 1)),
1305 (36950.0, (2001, 2, 28)),
1306 (36951.0, (2001, 3, 1)),
1307 (36981.0, (2001, 3, 31)),
1308 (36982.0, (2001, 4, 1)),
1309 (37011.0, (2001, 4, 30)),
1310 (37012.0, (2001, 5, 1)),
1311 (37042.0, (2001, 5, 31)),
1312 (37043.0, (2001, 6, 1)),
1313 (37072.0, (2001, 6, 30)),
1314 (37073.0, (2001, 7, 1)),
1315 (37103.0, (2001, 7, 31)),
1316 (37104.0, (2001, 8, 1)),
1317 (37134.0, (2001, 8, 31)),
1318 (37135.0, (2001, 9, 1)),
1319 (37164.0, (2001, 9, 30)),
1320 (37165.0, (2001, 10, 1)),
1321 (37195.0, (2001, 10, 31)),
1322 (37196.0, (2001, 11, 1)),
1323 (37225.0, (2001, 11, 30)),
1324 (37226.0, (2001, 12, 1)),
1325 (37256.0, (2001, 12, 31)),
1326 (182623.0, (2400, 1, 1)),
1327 (182653.0, (2400, 1, 31)),
1328 (182654.0, (2400, 2, 1)),
1329 (182682.0, (2400, 2, 29)),
1330 (182683.0, (2400, 3, 1)),
1331 (182713.0, (2400, 3, 31)),
1332 (182714.0, (2400, 4, 1)),
1333 (182743.0, (2400, 4, 30)),
1334 (182744.0, (2400, 5, 1)),
1335 (182774.0, (2400, 5, 31)),
1336 (182775.0, (2400, 6, 1)),
1337 (182804.0, (2400, 6, 30)),
1338 (182805.0, (2400, 7, 1)),
1339 (182835.0, (2400, 7, 31)),
1340 (182836.0, (2400, 8, 1)),
1341 (182866.0, (2400, 8, 31)),
1342 (182867.0, (2400, 9, 1)),
1343 (182896.0, (2400, 9, 30)),
1344 (182897.0, (2400, 10, 1)),
1345 (182927.0, (2400, 10, 31)),
1346 (182928.0, (2400, 11, 1)),
1347 (182957.0, (2400, 11, 30)),
1348 (182958.0, (2400, 12, 1)),
1349 (182988.0, (2400, 12, 31)),
1350 (767011.0, (4000, 1, 1)),
1351 (767041.0, (4000, 1, 31)),
1352 (767042.0, (4000, 2, 1)),
1353 (767070.0, (4000, 2, 29)),
1354 (767071.0, (4000, 3, 1)),
1355 (767101.0, (4000, 3, 31)),
1356 (767102.0, (4000, 4, 1)),
1357 (767131.0, (4000, 4, 30)),
1358 (767132.0, (4000, 5, 1)),
1359 (767162.0, (4000, 5, 31)),
1360 (767163.0, (4000, 6, 1)),
1361 (767192.0, (4000, 6, 30)),
1362 (767193.0, (4000, 7, 1)),
1363 (767223.0, (4000, 7, 31)),
1364 (767224.0, (4000, 8, 1)),
1365 (767254.0, (4000, 8, 31)),
1366 (767255.0, (4000, 9, 1)),
1367 (767284.0, (4000, 9, 30)),
1368 (767285.0, (4000, 10, 1)),
1369 (767315.0, (4000, 10, 31)),
1370 (767316.0, (4000, 11, 1)),
1371 (767345.0, (4000, 11, 30)),
1372 (767346.0, (4000, 12, 1)),
1373 (767376.0, (4000, 12, 31)),
1374 (884254.0, (4321, 1, 1)),
1375 (884284.0, (4321, 1, 31)),
1376 (884285.0, (4321, 2, 1)),
1377 (884312.0, (4321, 2, 28)),
1378 (884313.0, (4321, 3, 1)),
1379 (884343.0, (4321, 3, 31)),
1380 (884344.0, (4321, 4, 1)),
1381 (884373.0, (4321, 4, 30)),
1382 (884374.0, (4321, 5, 1)),
1383 (884404.0, (4321, 5, 31)),
1384 (884405.0, (4321, 6, 1)),
1385 (884434.0, (4321, 6, 30)),
1386 (884435.0, (4321, 7, 1)),
1387 (884465.0, (4321, 7, 31)),
1388 (884466.0, (4321, 8, 1)),
1389 (884496.0, (4321, 8, 31)),
1390 (884497.0, (4321, 9, 1)),
1391 (884526.0, (4321, 9, 30)),
1392 (884527.0, (4321, 10, 1)),
1393 (884557.0, (4321, 10, 31)),
1394 (884558.0, (4321, 11, 1)),
1395 (884587.0, (4321, 11, 30)),
1396 (884588.0, (4321, 12, 1)),
1397 (884618.0, (4321, 12, 31)),
1398 (2958101.0, (9999, 1, 1)),
1399 (2958131.0, (9999, 1, 31)),
1400 (2958132.0, (9999, 2, 1)),
1401 (2958159.0, (9999, 2, 28)),
1402 (2958160.0, (9999, 3, 1)),
1403 (2958190.0, (9999, 3, 31)),
1404 (2958191.0, (9999, 4, 1)),
1405 (2958220.0, (9999, 4, 30)),
1406 (2958221.0, (9999, 5, 1)),
1407 (2958251.0, (9999, 5, 31)),
1408 (2958252.0, (9999, 6, 1)),
1409 (2958281.0, (9999, 6, 30)),
1410 (2958282.0, (9999, 7, 1)),
1411 (2958312.0, (9999, 7, 31)),
1412 (2958313.0, (9999, 8, 1)),
1413 (2958343.0, (9999, 8, 31)),
1414 (2958344.0, (9999, 9, 1)),
1415 (2958373.0, (9999, 9, 30)),
1416 (2958374.0, (9999, 10, 1)),
1417 (2958404.0, (9999, 10, 31)),
1418 (2958405.0, (9999, 11, 1)),
1419 (2958434.0, (9999, 11, 30)),
1420 (2958435.0, (9999, 12, 1)),
1421 (2958465.0, (9999, 12, 31)),
1422 ];
1423
1424 for test in test_data {
1425 let (excel_serial_datetime, expected) = test;
1426 let datetime =
1427 ExcelDateTime::new(excel_serial_datetime, ExcelDateTimeType::DateTime, false);
1428 let got = datetime.to_ymd_hms_milli();
1429 let got = (got.0, got.1, got.2); assert_eq!(expected, got);
1431 }
1432 }
1433
1434 #[test]
1435 fn test_dates_only_1904_epoch() {
1436 let test_data = vec![(0.0, (1904, 1, 1))];
1437
1438 for test in test_data {
1439 let (excel_serial_datetime, expected) = test;
1440 let datetime =
1441 ExcelDateTime::new(excel_serial_datetime, ExcelDateTimeType::DateTime, true);
1442 let got = datetime.to_ymd_hms_milli();
1443 let got = (got.0, got.1, got.2); assert_eq!(expected, got);
1445 }
1446 }
1447
1448 #[test]
1449 fn test_times_only_both_epochs() {
1450 #[allow(clippy::excessive_precision)]
1451 let test_data = vec![
1452 (0.0, (0, 0, 0, 0)),
1453 (1.0650613425925924e-2, (0, 15, 20, 213)),
1454 (1.1670023148148148e-2, (0, 16, 48, 290)),
1455 (3.8488958333333337e-2, (0, 55, 25, 446)),
1456 (4.3598275462962965e-2, (1, 2, 46, 891)),
1457 (4.4624965277777782e-2, (1, 4, 15, 597)),
1458 (4.8389918981481483e-2, (1, 9, 40, 889)),
1459 (4.9682407407407404e-2, (1, 11, 32, 560)),
1460 (6.2721863425925936e-2, (1, 30, 19, 169)),
1461 (7.5296064814814809e-2, (1, 48, 25, 580)),
1462 (8.5786099537037031e-2, (2, 3, 31, 919)),
1463 (9.1110949074074077e-2, (2, 11, 11, 986)),
1464 (0.10042934027777778, (2, 24, 37, 95)),
1465 (0.10772245370370370, (2, 35, 7, 220)),
1466 (0.11472348379629631, (2, 45, 12, 109)),
1467 (0.12962951388888888, (3, 6, 39, 990)),
1468 (0.13065105324074075, (3, 8, 8, 251)),
1469 (0.13833999999999999, (3, 19, 12, 576)),
1470 (0.14563164351851851, (3, 29, 42, 574)),
1471 (0.15105107638888890, (3, 37, 30, 813)),
1472 (0.17683137731481480, (4, 14, 38, 231)),
1473 (0.17810832175925925, (4, 16, 28, 559)),
1474 (0.17914608796296297, (4, 17, 58, 222)),
1475 (0.18173372685185185, (4, 21, 41, 794)),
1476 (0.20596981481481480, (4, 56, 35, 792)),
1477 (0.22586672453703704, (5, 25, 14, 885)),
1478 (0.22645513888888891, (5, 26, 5, 724)),
1479 (0.24078782407407406, (5, 46, 44, 68)),
1480 (0.24167987268518520, (5, 48, 1, 141)),
1481 (0.24574438657407408, (5, 53, 52, 315)),
1482 (0.26028449074074073, (6, 14, 48, 580)),
1483 (0.28212659722222222, (6, 46, 15, 738)),
1484 (0.31343063657407405, (7, 31, 20, 407)),
1485 (0.33233511574074076, (7, 58, 33, 754)),
1486 (0.33869363425925925, (8, 7, 43, 130)),
1487 (0.35360059027777774, (8, 29, 11, 91)),
1488 (0.38073296296296300, (9, 8, 15, 328)),
1489 (0.39631690972222228, (9, 30, 41, 781)),
1490 (0.39866275462962958, (9, 34, 4, 462)),
1491 (0.40097158564814817, (9, 37, 23, 945)),
1492 (0.40135017361111114, (9, 37, 56, 655)),
1493 (0.40639155092592594, (9, 45, 12, 230)),
1494 (0.41267108796296298, (9, 54, 14, 782)),
1495 (0.41275587962962962, (9, 54, 22, 108)),
1496 (0.41777952546296299, (10, 1, 36, 151)),
1497 (0.50681252314814818, (12, 9, 48, 602)),
1498 (0.52371005787037039, (12, 34, 8, 549)),
1499 (0.53896406249999995, (12, 56, 6, 495)),
1500 (0.54095158564814816, (12, 58, 58, 217)),
1501 (0.54160026620370372, (12, 59, 54, 263)),
1502 (0.56575614583333333, (13, 34, 41, 331)),
1503 (0.58227547453703699, (13, 58, 28, 601)),
1504 (0.58491781249999997, (14, 2, 16, 899)),
1505 (0.60853523148148148, (14, 36, 17, 444)),
1506 (0.60969271990740748, (14, 37, 57, 451)),
1507 (0.62341153935185190, (14, 57, 42, 757)),
1508 (0.63250355324074070, (15, 10, 48, 307)),
1509 (0.63518391203703706, (15, 14, 39, 890)),
1510 (0.63874986111111109, (15, 19, 47, 988)),
1511 (0.66972620370370362, (16, 4, 24, 344)),
1512 (0.68222166666666662, (16, 22, 23, 952)),
1513 (0.68745369212962970, (16, 29, 55, 999)),
1514 (0.70717892361111112, (16, 58, 20, 259)),
1515 (0.71113906250000003, (17, 4, 2, 415)),
1516 (0.72117627314814825, (17, 18, 29, 630)),
1517 (0.74121901620370367, (17, 47, 21, 323)),
1518 (0.74548456018518516, (17, 53, 29, 866)),
1519 (0.74561430555555563, (17, 53, 41, 76)),
1520 (0.74659773148148145, (17, 55, 6, 44)),
1521 (0.76029109953703700, (18, 14, 49, 151)),
1522 (0.76233493055555546, (18, 17, 45, 738)),
1523 (0.77082986111111118, (18, 29, 59, 700)),
1524 (0.77316241898148153, (18, 33, 21, 233)),
1525 (0.80167445601851861, (19, 14, 24, 673)),
1526 (0.80362055555555545, (19, 17, 12, 816)),
1527 (0.80806039351851855, (19, 23, 36, 418)),
1528 (0.82391097222222232, (19, 46, 25, 908)),
1529 (0.83874206018518516, (20, 7, 47, 314)),
1530 (0.85529633101851854, (20, 31, 37, 603)),
1531 (0.86108530092592594, (20, 39, 57, 770)),
1532 (0.86825309027777775, (20, 50, 17, 67)),
1533 (0.87705818287037041, (21, 2, 57, 827)),
1534 (0.89103609953703700, (21, 23, 5, 519)),
1535 (0.89918486111111118, (21, 34, 49, 572)),
1536 (0.90215212962962965, (21, 39, 5, 944)),
1537 (0.90229659722222222, (21, 39, 18, 426)),
1538 (0.90703436342592603, (21, 46, 7, 769)),
1539 (0.91522756944444439, (21, 57, 55, 662)),
1540 (0.92999689814814823, (22, 19, 11, 732)),
1541 (0.93323351851851843, (22, 23, 51, 376)),
1542 (0.93609688657407408, (22, 27, 58, 771)),
1543 (0.94687953703703709, (22, 43, 30, 392)),
1544 (0.95029900462962968, (22, 48, 25, 834)),
1545 (0.95407091435185187, (22, 53, 51, 727)),
1546 (0.96732101851851848, (23, 12, 56, 536)),
1547 (0.96937626157407408, (23, 15, 54, 109)),
1548 (0.97028509259259266, (23, 17, 12, 632)),
1549 (0.99999998842592586, (23, 59, 59, 999)),
1550 ];
1551
1552 for test in test_data {
1553 let (excel_serial_datetime, expected) = test;
1554
1555 let datetime =
1557 ExcelDateTime::new(excel_serial_datetime, ExcelDateTimeType::DateTime, false);
1558 let got = datetime.to_ymd_hms_milli();
1559 let got = (got.3, got.4, got.5, got.6); assert_eq!(expected, got);
1561
1562 let datetime =
1564 ExcelDateTime::new(excel_serial_datetime, ExcelDateTimeType::DateTime, true);
1565 let got = datetime.to_ymd_hms_milli();
1566 let got = (got.3, got.4, got.5, got.6); assert_eq!(expected, got);
1568 }
1569 }
1570}