1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
use ;
use ToSpan as _;
use cast;
pub const CALENDAR_WINDOWS_1900: &str = "1900";
pub const CALENDAR_MAC_1904: &str = "1904";
pub const DEFAULT_TIMEZONE: &str = "UTC";
/// Converts an Excel timestamp to a [`NaiveDateTime`] object.
///
/// This function takes an Excel timestamp, which is a numeric representation of
/// a date and time, and converts it into a [`NaiveDateTime`] object. The
/// integer part of the timestamp represents the number of days since a base
/// date, while the fractional part represents the time of day.
///
/// # Parameters
///
/// - `excel_timestamp: f64` The Excel timestamp to be converted and it is
/// treated as an Excel date.
///
/// # Returns
///
/// Returns a [`NaiveDateTime`] object representing the converted date and time.
/// This object does not contain any timezone information.
///
/// # Behavior
///
/// - If `excel_timestamp` is between 1 and 60, the function accounts for the
/// 1900 leap year bug in Excel by using December 31, 1899, as the base date.
/// - For `excel_timestamp` values of 60 or greater, it uses December 30, 1899,
/// as the base date.
/// - This uses the Windows 1900 scheme which is more common.
/// - Since 1900-02-29 is not a valid date this function returns 1900-03-01 in
/// that case.
///
/// # Example
///
/// ```rust
/// # use umya_spreadsheet::helper::date::excel_to_date_time_chrono;
/// # use chrono::{Datelike, Timelike};
/// let timestamp = 44197.5; // Represents 2021-01-01 12:00:00
/// let date_time = excel_to_date_time_chrono(timestamp);
/// assert_eq!(date_time.year(), 2021);
/// assert_eq!(date_time.month(), 1);
/// assert_eq!(date_time.day(), 1);
/// assert_eq!(date_time.hour(), 12);
/// assert_eq!(date_time.minute(), 0);
/// ```
/// Converts an Excel timestamp to a three parts: Base Date, Days, Time
/// The function is provided for maximum flexibility but for most use cases
/// you'll want the simpler [`excel_to_date_time_jiff`]
/// which returns a single [`jiff::civil::DateTime`].
///
/// This function takes an Excel timestamp, which is a numeric representation of
/// a date and time, and converts it into the parts needed to create a
/// [`jiff::civil::DateTime`] object. The integer part of the timestamp
/// represents the number of days since a base date, while the fractional part
/// represents the time of day.
///
///
/// # Parameters
///
/// - `excel_timestamp: f64` The Excel timestamp to be converted and it is
/// treated as an Excel date under the Windows 1900 scheme.
///
/// # Returns
///
/// This function returns three pieces that can be used to construct a date/time
/// - The effective base date: as a [`jiff::civil::Date`] object this is not
/// always the same date to account for a compatibility bug in Excel where a
/// it treats 1900 as a leap year while it is not in reality. This object does
/// not contain any timezone information.
/// - The number of days since the base date (The integer part of the input)
/// - The time part which is the fraction of the day (The fractional part of the
/// input)
///
/// # Behavior
///
/// - If `excel_timestamp` is in the range 1 to 60, the function accounts for
/// the 1900 leap year bug in Excel by using December 31, 1899, as the base
/// date.
/// - For `excel_timestamp` values of 60 or greater, it uses December 30, 1899,
/// as the base date.
/// - This uses the Windows 1900 scheme which is more common.
///
/// # Example
///
/// ```rust
/// # use umya_spreadsheet::helper::date::excel_to_date_time_parts;
/// let timestamp = 44197.5; // Represents 2021-01-01 12:00:00
/// let (base_date, days, time) = excel_to_date_time_parts(timestamp);
/// assert_eq!(base_date.year(), 1899);
/// assert_eq!(base_date.month(), 12);
/// assert_eq!(base_date.day(), 30);
/// assert_eq!(days, 44197);
/// assert_eq!(time, 0.5);
///
/// let timestamp = 20.40625; // Represents 1900-01-20 09:45:00
/// let (base_date, days, time) = excel_to_date_time_parts(timestamp);
/// assert_eq!(base_date.year(), 1899);
/// assert_eq!(base_date.month(), 12);
/// assert_eq!(base_date.day(), 31); // Note using 31 because before March 1st
/// assert_eq!(days, 20);
/// assert_eq!(time, 0.40625);
/// ```
/// Converts an Excel timestamp to a [`jiff::civil::DateTime`] object with
/// second precision. If you need millisecond precision use
/// [`excel_to_date_time_jiff_millisecond`]. Note that because of how date
/// formatting is often done. If you plan to only show up to seconds you'll
/// probably want second precision in the value.
///
/// This function takes an Excel timestamp, which is a numeric representation of
/// a date and time, and converts it into a [`jiff::civil::DateTime`] object.
/// The integer part of the timestamp represents the number of days since a base
/// date, while the fractional part represents the time of day.
///
/// # Parameters
///
/// - `excel_timestamp: f64` The Excel timestamp to be converted and it is
/// treated as an Excel date.
///
/// # Returns
///
/// Returns a [`jiff::civil::DateTime`] object representing the converted date
/// and time. This object does not contain any timezone information.
///
/// # Behavior
///
/// - If `excel_timestamp` is between 1 and 60, the function accounts for the
/// 1900 leap year bug in Excel by using December 31, 1899, as the base date.
/// - For `excel_timestamp` values of 60 or greater, it uses December 30, 1899,
/// as the base date.
/// - This uses the Windows 1900 scheme which is more common.
/// - Since 1900-02-29 is not a valid date this function returns 1900-03-01 in
/// that case.
///
/// # Example
///
/// ```rust
/// # use umya_spreadsheet::helper::date::excel_to_date_time_jiff;
/// let timestamp = 44197.5; // Represents 2021-01-01 12:00:00
/// let date_time = excel_to_date_time_jiff(timestamp);
/// assert_eq!(date_time.year(), 2021);
/// assert_eq!(date_time.month(), 1);
/// assert_eq!(date_time.day(), 1);
/// assert_eq!(date_time.hour(), 12);
/// assert_eq!(date_time.minute(), 0);
/// ```
/// Converts an Excel timestamp to a [`jiff::civil::DateTime`] object with
/// millisecond precision. If you don't need millisecond precision you may want
/// to use [`excel_to_date_time_jiff`] as if you only work this seconds this
/// will give you the rounding you probably expect.
///
/// See [`excel_to_date_time_jiff`] for more details as these functions are the
/// same aside for the difference in precision.
///
/// # Example
///
/// ```rust
/// # use umya_spreadsheet::helper::date::excel_to_date_time_jiff_millisecond;
/// let timestamp = 44197.5; // Represents 2021-01-01 12:00:00
/// let date_time = excel_to_date_time_jiff_millisecond(timestamp);
/// assert_eq!(date_time.year(), 2021);
/// assert_eq!(date_time.month(), 1);
/// assert_eq!(date_time.day(), 1);
/// assert_eq!(date_time.hour(), 12);
/// assert_eq!(date_time.minute(), 0);
/// ```
///
/// The following example demonstrates the difference between the two levels of
/// precision
///
/// ```rust
/// # use umya_spreadsheet::helper::date::excel_to_date_time_jiff_millisecond;
/// # use umya_spreadsheet::helper::date::excel_to_date_time_jiff;
/// let timestamp = 44180.584027777775;
/// let rounded_to_seconds = excel_to_date_time_jiff(timestamp);
/// let to_milliseconds = excel_to_date_time_jiff_millisecond(timestamp);
///
/// assert_eq!(
/// rounded_to_seconds.strftime("%F %T%.f").to_string(),
/// "2020-12-15 14:01:00"
/// );
/// assert_eq!(
/// to_milliseconds.strftime("%F %T%.f").to_string(),
/// "2020-12-15 14:00:59.999"
/// );
/// ```
/// Converts a timestamp to a f64
///
/// This function takes a jiff timestamp and converts it into a f64 value that
/// represents an excel timestamp. See [`excel_to_date_time_jiff`] for more
/// details on the format of excel timestamps.
///
/// # Returns
///
/// Returns a f64 representing the an excel timestamp
///
/// # Example
///
/// ```rust
/// # use umya_spreadsheet::helper::date::jiff_date_time_to_excel;
/// // Represents 2021-01-01 12:00:00
/// let value = jiff::civil::datetime(2021, 1, 1, 12, 0, 0, 0);
/// let timestamp = jiff_date_time_to_excel(value);
/// assert!((timestamp - 44197.5).abs() < 0.00001);
/// ```
///
/// # Note
///
/// - Earliest valid date in excel under the Windows 1900 system is 1899-12-31
/// at 00:00. This function will return a negative number for earlier dates
/// which is not valid in excel.
/// See docs for `excel_to_date_time_chrono` for details on how this function
/// works. Note that the `time_zone` is not used and is ignored. Excel doesn't
/// store associated timezone info with the dates.
/// Converts a date and time to an Excel timestamp using the Windows 1900 date
/// system.
///
/// This function takes individual components of a date and time (year, month,
/// day, hours, minutes, and seconds) and converts them into an Excel timestamp.
/// The conversion is based on the Windows 1900 date system, which accounts for
/// the 1900 leap year bug.
///
/// # Parameters
///
/// - `year: i32` The year component of the date.
///
/// - `month: i32` The month component of the date (1-12).
///
/// - `day: i32` The day component of the date (1-31).
///
/// - `hours: i32` The hour component of the time (0-23).
///
/// - `minutes: i32` The minute component of the time (0-59).
///
/// - `seconds: i32` The second component of the time (0-59).
///
/// # Returns
///
/// Returns an `f64` representing the corresponding Excel timestamp.
///
/// # Example
///
/// ```rust
/// # use umya_spreadsheet::helper::date::convert_date;
/// let timestamp = convert_date(2021, 1, 1, 12, 0, 0);
/// assert_eq!(timestamp, 44197.5); // Represents 2021-01-01 12:00:00
/// ```
///
/// # Note
///
/// - Earliest valid date in excel under the Windows 1900 system is 1899-12-31
/// at 00:00. This function will return a negative number for earlier dates
/// which is not valid in excel.
/// - Invalid components are not check and will just return invalid values
/// Converts a date and time to an Excel timestamp using the Windows 1900 date
/// system.
///
/// This function takes individual components of a date and time (year, month,
/// day, hours, minutes, and seconds) and converts them into an Excel timestamp
/// specifically for the Windows 1900 date system, which includes the 1900 leap
/// year bug.
///
/// # Parameters
///
/// - `year: i32` The year component of the date.
///
/// - `month: i32` The month component of the date (1-12).
///
/// - `day: i32` The day component of the date (1-31).
///
/// - `hours: i32` The hour component of the time (0-23).
///
/// - `minutes: i32` The minute component of the time (0-59).
///
/// - `seconds: i32` The second component of the time (0-59).
///
/// # Returns
///
/// Returns an `f64` representing the corresponding Excel timestamp.
///
/// # Example
///
/// ```rust
/// # use umya_spreadsheet::helper::date::convert_date_windows_1900;
/// let timestamp = convert_date_windows_1900(2021, 1, 1, 12, 0, 0);
/// assert_eq!(timestamp, 44197.5); // Represents 2021-01-01 12:00:00
/// ```
///
/// # Note
///
/// - Earliest valid date in excel under the Windows 1900 system is 1899-12-31
/// at 00:00. This function will return a negative number for earlier dates
/// which is not valid in excel.
/// - Invalid components are not check and will just return invalid values
/// Converts a date and time to an Excel timestamp using the Mac 1904 date
/// system.
///
/// This function takes individual components of a date and time (year, month,
/// day, hours, minutes, and seconds) and converts them into an Excel timestamp
/// specifically for the Mac 1904 date system, which has a different base date
/// compared to the Windows 1900 date system.
///
/// # Parameters
///
/// - `year: i32` The year component of the date.
///
/// - `month: i32` The month component of the date (1-12).
///
/// - `day: i32` The day component of the date (1-31).
///
/// - `hours: i32` The hour component of the time (0-23).
///
/// - `minutes: i32` The minute component of the time (0-59).
///
/// - `seconds: i32` The second component of the time (0-59).
///
/// # Returns
///
/// Returns an `f64` representing the corresponding Excel timestamp for the Mac
/// 1904 date system.
///
/// # Example
///
/// ```rust
/// # use umya_spreadsheet::helper::date::convert_date_mac_1904;
/// let timestamp = convert_date_mac_1904(2021, 1, 1, 12, 0, 0);
/// assert_eq!(timestamp, 42735.5); // Represents 2021-01-01 12:00:00
/// ```
///
/// # Note
///
/// - Earliest valid date in excel under the Mac 1904 system is 1904-01-01 at
/// 00:00. This function will return a negative number for earlier dates which
/// is not valid in excel.
/// - Invalid components are not check and will just return invalid values
/// Converts a date and time to an Excel timestamp based on the specified
/// calendar system.
///
/// This function takes individual components of a date and time (year, month,
/// day, hours, minutes, and seconds) and converts them into an Excel timestamp.
/// The conversion can be based on either the Windows 1900 date system or the
/// Mac 1904 date system, depending on the value of the
/// `is_calendar_windows_1900` parameter.
///
/// # Parameters
///
/// - `year: i32` The year component of the date.
///
/// - `month: i32` The month component of the date (1-12).
///
/// - `day: i32` The day component of the date (1-31).
///
/// - `hours: i32` The hour component of the time (0-23).
///
/// - `minutes: i32` The minute component of the time (0-59).
///
/// - `seconds: i32` The second component of the time (0-59).
///
/// - `is_calendar_windows_1900: bool` A boolean indicating whether to use the
/// Windows 1900 date system (`true`) or the Mac 1904 date system (`false`).
///
/// # Returns
///
/// Returns an `f64` representing the corresponding Excel timestamp for the
/// specified calendar system.
///
/// # Example
///
/// ```rust
/// # use umya_spreadsheet::helper::date::convert_date_crate;
/// let timestamp_windows = convert_date_crate(2021, 1, 1, 12, 0, 0, true);
/// assert_eq!(timestamp_windows, 44197.5); // Represents 2021-01-01 12:00:00 in Windows 1900 system
///
/// let timestamp_mac = convert_date_crate(2021, 1, 1, 12, 0, 0, false);
/// assert_eq!(timestamp_mac, 42735.5); // Represents 2021-01-01 12:00:00 in Mac 1904 system
/// ```
///
/// # Note
///
/// - Earliest valid date in excel under the Windows 1900 system is 1899-12-31
/// at 00:00. This function will return a negative number for earlier dates
/// which is not valid in excel.
/// - Earliest valid date in excel under the Mac 1904 system is 1904-01-01 at
/// 00:00. This function will return a negative number for earlier dates which
/// is not valid in excel.
/// - Invalid components are not check and will just return invalid values