Skip to main content

calamine/
datatype.rs

1// SPDX-License-Identifier: MIT
2//
3// Copyright 2016-2025, Johann Tuffe.
4
5use std::fmt;
6#[cfg(feature = "chrono")]
7use std::sync::OnceLock;
8
9use serde::de::Visitor;
10use serde::Deserialize;
11
12use super::CellErrorType;
13
14// Constants used in Excel date calculations.
15const 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")]
27// https://learn.microsoft.com/en-us/office/troubleshoot/excel/1900-and-1904-date-system
28const EXCEL_1900_1904_DIFF: f64 = 1462.;
29
30#[cfg(feature = "chrono")]
31const MS_MULTIPLIER: f64 = 24f64 * 60f64 * 60f64 * 1e+3f64;
32
33/// An enum to represent all different data types that can appear as
34/// a value in a worksheet cell
35#[derive(Debug, Clone, PartialEq, Default)]
36pub enum Data {
37    /// Signed integer
38    Int(i64),
39    /// Float
40    Float(f64),
41    /// String
42    String(String),
43    /// Boolean
44    Bool(bool),
45    /// Date or Time
46    DateTime(ExcelDateTime),
47    /// Date, Time or Date/Time in ISO 8601
48    DateTimeIso(String),
49    /// Duration in ISO 8601
50    DurationIso(String),
51    /// Error
52    Error(CellErrorType),
53    /// Empty cell
54    #[default]
55    Empty,
56}
57
58/// An enum to represent all different data types that can appear as
59/// a value in a worksheet cell
60impl 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/// An enum to represent all different data types that can appear as
338/// a value in a worksheet cell
339#[derive(Debug, Clone, PartialEq, Default)]
340pub enum DataRef<'a> {
341    /// Signed integer
342    Int(i64),
343    /// Float
344    Float(f64),
345    /// String
346    String(String),
347    /// Shared String
348    SharedString(&'a str),
349    /// Boolean
350    Bool(bool),
351    /// Date or Time
352    DateTime(ExcelDateTime),
353    /// Date, Time or Date/Time in ISO 8601
354    DateTimeIso(String),
355    /// Duration in ISO 8601
356    DurationIso(String),
357    /// Error
358    Error(CellErrorType),
359    /// Empty cell
360    #[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
524/// A trait to represent all different data types that can appear as
525/// a value in a worksheet cell
526pub trait DataType {
527    /// Assess if datatype is empty
528    fn is_empty(&self) -> bool;
529
530    /// Assess if datatype is a int
531    fn is_int(&self) -> bool;
532
533    /// Assess if datatype is a float
534    fn is_float(&self) -> bool;
535
536    /// Assess if datatype is a bool
537    fn is_bool(&self) -> bool;
538
539    /// Assess if datatype is a string
540    fn is_string(&self) -> bool;
541
542    /// Assess if datatype is a `CellErrorType`
543    fn is_error(&self) -> bool;
544
545    /// Assess if datatype is an ISO8601 duration
546    fn is_duration_iso(&self) -> bool;
547
548    /// Assess if datatype is a datetime
549    fn is_datetime(&self) -> bool;
550
551    /// Assess if datatype is an ISO8601 datetime
552    fn is_datetime_iso(&self) -> bool;
553
554    /// Try getting int value
555    fn get_int(&self) -> Option<i64>;
556
557    /// Try getting float value
558    fn get_float(&self) -> Option<f64>;
559
560    /// Try getting bool value
561    fn get_bool(&self) -> Option<bool>;
562
563    /// Try getting string value
564    fn get_string(&self) -> Option<&str>;
565
566    /// Try getting datetime value
567    fn get_datetime(&self) -> Option<ExcelDateTime>;
568
569    /// Try getting datetime ISO8601 value
570    fn get_datetime_iso(&self) -> Option<&str>;
571
572    /// Try getting duration ISO8601 value
573    fn get_duration_iso(&self) -> Option<&str>;
574
575    /// Try getting Error value
576    fn get_error(&self) -> Option<&CellErrorType>;
577
578    /// Try converting data type into a string
579    fn as_string(&self) -> Option<String>;
580
581    /// Try converting data type into an int
582    fn as_i64(&self) -> Option<i64>;
583
584    /// Try converting data type into a float
585    fn as_f64(&self) -> Option<f64>;
586
587    /// Try converting data type into a date
588    #[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    /// Try converting data type into a time
603    #[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    /// Try converting data type into a duration
621    #[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            // need replace in the future to something like chrono::Duration::from_str()
630            // https://github.com/chronotope/chrono/issues/579
631            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    // Try converting data type into a datetime.
642    #[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/// Excel datetime type. Possible: date, time, datetime, duration.
679/// At this time we can only determine datetime (date and time are datetime too) and duration.
680#[derive(Debug, Clone, Copy, PartialEq)]
681pub enum ExcelDateTimeType {
682    /// `DateTime`
683    DateTime,
684    /// `TimeDelta` (Duration)
685    TimeDelta,
686}
687
688/// Structure for Excel date and time representation.
689#[derive(Debug, Clone, Copy, PartialEq)]
690pub struct ExcelDateTime {
691    value: f64,
692    datetime_type: ExcelDateTimeType,
693    is_1904: bool,
694}
695
696impl ExcelDateTime {
697    /// Creates a new `ExcelDateTime`
698    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    // Is used only for converting excel value to chrono.
707    #[cfg(feature = "chrono")]
708    fn from_value_only(value: f64) -> Self {
709        ExcelDateTime {
710            value,
711            ..Default::default()
712        }
713    }
714
715    /// True if excel datetime has duration format (`[hh]:mm:ss`, for example)
716    pub fn is_duration(&self) -> bool {
717        matches!(self.datetime_type, ExcelDateTimeType::TimeDelta)
718    }
719
720    /// True if excel datetime has datetime format (not duration)
721    pub fn is_datetime(&self) -> bool {
722        matches!(self.datetime_type, ExcelDateTimeType::DateTime)
723    }
724
725    /// Converting data type into a float
726    pub fn as_f64(&self) -> f64 {
727        self.value
728    }
729
730    /// Convert an Excel serial datetime to standard date components.
731    ///
732    /// Datetimes in Excel are serial dates with days counted from an epoch
733    /// (usually 1900-01-01) and where the time is a percentage/decimal of the
734    /// milliseconds in the day. Both the date and time are stored in the same
735    /// f64 value. For example, 2025/10/13 12:00:00 is stored as 45943.5.
736    ///
737    /// This function returns a tuple of (year, month, day, hour, minutes,
738    /// seconds, milliseconds). It works for serial dates in both the 1900 and
739    /// 1904 epochs.
740    ///
741    /// This function always returns a date, even if the serial value is outside
742    /// of Excel's range of `0.0 <= datetime < 10000.0`. It also returns, as
743    /// Excel does, the invalid date 1900/02/29 due to the [Excel 1900 leap year
744    /// bug](https://en.wikipedia.org/wiki/Leap_year_problem#Occurrences).
745    ///
746    /// Excel only supports millisecond precision and it also doesn't use or
747    /// encode timezone information in any way.
748    ///
749    /// # Examples
750    ///
751    /// An example of converting an Excel date/time to standard components.
752    ///
753    /// ```
754    /// use calamine::{ExcelDateTime, ExcelDateTimeType};
755    ///
756    /// // Create an Excel datetime from the serial value 45943.541 which is
757    /// // equivalent to the date "2025/10/13 12:59:02.400".
758    /// let excel_datetime = ExcelDateTime::new(
759    ///     45943.541,
760    ///     ExcelDateTimeType::DateTime,
761    ///     false, // Using 1900 epoch (not 1904).
762    /// );
763    ///
764    /// // Convert to standard date/time components.
765    /// let (year, month, day, hour, min, sec, milli) = excel_datetime.to_ymd_hms_milli();
766    ///
767    /// assert_eq!(year, 2025);
768    /// assert_eq!(month, 10);
769    /// assert_eq!(day, 13);
770    /// assert_eq!(hour, 12);
771    /// assert_eq!(min, 59);
772    /// assert_eq!(sec, 2);
773    /// assert_eq!(milli, 400);
774    /// ```
775    ///
776    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    /// Try converting data type into a duration.
781    #[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    /// Try converting data type into a datetime.
789    #[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    // Convert an Excel serial datetime to its date components.
809    //
810    // Datetimes in Excel are serial dates with days counted from an epoch and
811    // where the time is a percentage/decimal of the milliseconds in the day.
812    // Both the date and time are stored in the same f64 value.
813    //
814    // The calculation back to standard date and time components is deceptively
815    // tricky since simple division doesn't work due to the 4/100/400 year leap
816    // day changes. The basic approach is to divide the range into 400 year
817    // blocks, 100 year blocks, 4 year blocks and 1 year blocks to calculate the
818    // year (relative to the epoch). The remaining days and seconds are used to
819    // calculate the year day and time. To make the leap year calculations
820    // easier we move the effective epoch back to 1600-01-01 which is the
821    // closest 400 year epoch before 1900/1904.
822    //
823    // In addition we need to handle both a 1900 and 1904 epoch and we need to
824    // account for the Excel date bug where it treats 1900 as a leap year.
825    //
826    // Works in the range 1899-12-31/1904-01-01 to 9999-12-31.
827    //
828    // Leap seconds and the timezone aren't taken into account since Excel
829    // doesn't handle them.
830    //
831    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        // Convert the seconds to a whole number of days.
838        let mut days = excel_datetime.floor() as u64;
839
840        // Move the epoch to 1600-01-01 to make the leap calculations easier.
841        if is_1904 {
842            // 1904 epoch dates.
843            days += 111_033;
844        } else if days > YEAR_DAYS {
845            // 1900 epoch years other than 1900.
846            days += 109_571;
847        } else {
848            // Adjust for the Excel 1900 leap year bug.
849            days += 109_572;
850        }
851
852        // Get the number of 400 year blocks.
853        let year_days_400 = days / YEAR_DAYS_400;
854        let mut days = days % YEAR_DAYS_400;
855
856        // Get the number of 100 year blocks. There are 2 kinds: those starting
857        // from a %400 year with an extra leap day (36,525 days) and those
858        // starting from other 100 year intervals with 1 day less (36,524 days).
859        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        // Get the number of 4 year blocks. There are 2 kinds: a 4 year block
869        // with a leap day (1461 days) and a 4 year block starting from non-leap
870        // %100 years without a leap day (1460 days). We also need to account
871        // for whether a 1461 day block was preceded by a 1460 day block at the
872        // start of the 100 year block.
873        let year_days_4;
874        let mut non_leap_year_block = false;
875        if year_days_100 == 0 {
876            // Any 4 year block in a 36,525 day 100 year block. Has extra leap.
877            year_days_4 = days / YEAR_DAYS_4;
878            days %= YEAR_DAYS_4;
879        } else if days < YEAR_DAYS_4 {
880            // A 4 year block at the start of a 36,524 day 100 year block.
881            year_days_4 = days / (YEAR_DAYS_4 - 1);
882            days %= YEAR_DAYS_4 - 1;
883            non_leap_year_block = true;
884        } else {
885            // A non-initial 4 year block in a 36,524 day 100 year block.
886            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        // Get the number of 1 year blocks. We need to account for leap years
891        // and non-leap years and whether the non-leap occurs after a leap year.
892        let year_days_1;
893        if non_leap_year_block {
894            // A non-leap block not preceded by a leap block.
895            year_days_1 = days / YEAR_DAYS;
896            days %= YEAR_DAYS;
897        } else if days < YEAR_DAYS + 1 {
898            // A leap year block.
899            year_days_1 = days / (YEAR_DAYS + 1);
900            days %= YEAR_DAYS + 1;
901        } else {
902            // A non-leap block preceded by a leap block.
903            year_days_1 = 1 + (days - (YEAR_DAYS + 1)) / YEAR_DAYS;
904            days = (days - (YEAR_DAYS + 1)) % YEAR_DAYS;
905        }
906
907        // Calculate the year as the number of blocks*days since the epoch.
908        let year = 1600 + year_days_400 * 400 + year_days_100 * 100 + year_days_4 * 4 + year_days_1;
909
910        // Convert from 0 indexed to 1 indexed days.
911        days += 1;
912
913        // Adjust February day count for leap years.
914        if Self::is_leap_year(year) {
915            months[1] = 29;
916        }
917
918        // Handle edge cases due to Excel erroneously treating 1900 as a leap year.
919        if !is_1904 && year == 1900 {
920            months[1] = 29;
921
922            // Adjust last day of 1900.
923            if excel_datetime.trunc() == 366.0 {
924                days += 1;
925            }
926        }
927
928        // Calculate the relevant month based on the sequential number of days.
929        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        // The final remainder is the day of the month.
940        let day = days;
941
942        // Get the time part of the Excel datetime.
943        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        // Handle millisecond overflow due to rounding.
948        if milli == 1000 {
949            day_as_seconds += 1;
950            milli = 0;
951        }
952
953        // Calculate the hours, minutes and seconds in the day.
954        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        // Return the date and time components.
959        (
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    // Check if a year is a leap year.
971    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        // test for https://github.com/tafia/calamine/issues/251
1011        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        // test rounding
1021        #[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        // test overflow
1036        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); // Date parts only.
1430            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); // Date parts only.
1444            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            // 1900 epoch.
1556            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); // Time parts only.
1560            assert_eq!(expected, got);
1561
1562            // 1904 epoch.
1563            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); // Time parts only.
1567            assert_eq!(expected, got);
1568        }
1569    }
1570}