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