time 0.3.49

Date and time library. Fully interoperable with the standard library. Mostly compatible with #![no_std].
Documentation
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
use std::cmp::Ordering;

use rstest::rstest;
use time::ext::{NumericalDuration, NumericalStdDuration};
use time::macros::{date, datetime, offset, time};
use time::{Date, Duration, Month, PrimitiveDateTime, Time, UtcOffset, Weekday};

#[rstest]
#[case(PrimitiveDateTime::new(date!(2019-01-01), time!(0:00)), datetime!(2019-01-01 0:00))]
fn new(#[case] input: PrimitiveDateTime, #[case] expected: PrimitiveDateTime) {
    assert_eq!(input, expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), date!(2019-01-01))]
fn date(#[case] datetime: PrimitiveDateTime, #[case] expected: Date) {
    assert_eq!(datetime.date(), expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), time!(0:00))]
fn time_(#[case] datetime: PrimitiveDateTime, #[case] expected: Time) {
    assert_eq!(datetime.time(), expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), 2019)]
#[case(datetime!(2019-12-31 0:00), 2019)]
#[case(datetime!(2020-01-01 0:00), 2020)]
fn year(#[case] datetime: PrimitiveDateTime, #[case] expected: i32) {
    assert_eq!(datetime.year(), expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), Month::January)]
#[case(datetime!(2019-12-31 0:00), Month::December)]
fn month(#[case] datetime: PrimitiveDateTime, #[case] expected: Month) {
    assert_eq!(datetime.month(), expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), 1)]
#[case(datetime!(2019-12-31 0:00), 31)]
fn day(#[case] datetime: PrimitiveDateTime, #[case] expected: u8) {
    assert_eq!(datetime.day(), expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), 1)]
#[case(datetime!(2019-12-31 0:00), 365)]
fn ordinal(#[case] datetime: PrimitiveDateTime, #[case] expected: u16) {
    assert_eq!(datetime.ordinal(), expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), 1)]
#[case(datetime!(2019-10-04 0:00), 40)]
#[case(datetime!(2020-01-01 0:00), 1)]
#[case(datetime!(2020-12-31 0:00), 53)]
#[case(datetime!(2021-01-01 0:00), 53)]
fn iso_week(#[case] datetime: PrimitiveDateTime, #[case] expected: u8) {
    assert_eq!(datetime.iso_week(), expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), 0)]
#[case(datetime!(2020-01-01 0:00), 0)]
#[case(datetime!(2020-12-31 0:00), 52)]
#[case(datetime!(2021-01-01 0:00), 0)]
fn sunday_based_week(#[case] datetime: PrimitiveDateTime, #[case] expected: u8) {
    assert_eq!(datetime.sunday_based_week(), expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), 0)]
#[case(datetime!(2020-01-01 0:00), 0)]
#[case(datetime!(2020-12-31 0:00), 52)]
#[case(datetime!(2021-01-01 0:00), 0)]
fn monday_based_week(#[case] datetime: PrimitiveDateTime, #[case] expected: u8) {
    assert_eq!(datetime.monday_based_week(), expected);
}

#[rstest]
#[case(datetime!(2019-01-02 0:00), (2019, Month::January, 2))]
fn to_calendar_date(#[case] datetime: PrimitiveDateTime, #[case] expected: (i32, Month, u8)) {
    assert_eq!(datetime.to_calendar_date(), expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), (2019, 1))]
fn to_ordinal_date(#[case] datetime: PrimitiveDateTime, #[case] expected: (i32, u16)) {
    assert_eq!(datetime.to_ordinal_date(), expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), (2019, 1, Weekday::Tuesday))]
#[case(datetime!(2019-10-04 0:00), (2019, 40, Weekday::Friday))]
#[case(datetime!(2020-01-01 0:00), (2020, 1, Weekday::Wednesday))]
#[case(datetime!(2020-12-31 0:00), (2020, 53, Weekday::Thursday))]
#[case(datetime!(2021-01-01 0:00), (2020, 53, Weekday::Friday))]
fn to_iso_week_date(#[case] datetime: PrimitiveDateTime, #[case] expected: (i32, u8, Weekday)) {
    assert_eq!(datetime.to_iso_week_date(), expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), Weekday::Tuesday)]
#[case(datetime!(2019-02-01 0:00), Weekday::Friday)]
#[case(datetime!(2019-03-01 0:00), Weekday::Friday)]
#[case(datetime!(2019-04-01 0:00), Weekday::Monday)]
#[case(datetime!(2019-05-01 0:00), Weekday::Wednesday)]
#[case(datetime!(2019-06-01 0:00), Weekday::Saturday)]
#[case(datetime!(2019-07-01 0:00), Weekday::Monday)]
#[case(datetime!(2019-08-01 0:00), Weekday::Thursday)]
#[case(datetime!(2019-09-01 0:00), Weekday::Sunday)]
#[case(datetime!(2019-10-01 0:00), Weekday::Tuesday)]
#[case(datetime!(2019-11-01 0:00), Weekday::Friday)]
#[case(datetime!(2019-12-01 0:00), Weekday::Sunday)]
fn weekday(#[case] datetime: PrimitiveDateTime, #[case] expected: Weekday) {
    assert_eq!(datetime.weekday(), expected);
}

#[rstest]
#[case(datetime!(-999_999-01-01 0:00), -363_521_074)]
#[case(datetime!(-4713-11-24 0:00), 0)]
#[case(datetime!(2000-01-01 0:00), 2_451_545)]
#[case(datetime!(2019-01-01 0:00), 2_458_485)]
#[case(datetime!(2019-12-31 0:00), 2_458_849)]
fn to_julian_day(#[case] datetime: PrimitiveDateTime, #[case] expected: i32) {
    assert_eq!(datetime.to_julian_day(), expected);
}

#[rstest]
#[case(datetime!(2020-01-01 1:02:03), (1, 2, 3))]
fn as_hms(#[case] datetime: PrimitiveDateTime, #[case] expected: (u8, u8, u8)) {
    assert_eq!(datetime.as_hms(), expected);
}

#[rstest]
#[case(datetime!(2020-01-01 1:02:03.004), (1, 2, 3, 4))]
fn as_hms_milli(#[case] datetime: PrimitiveDateTime, #[case] expected: (u8, u8, u8, u16)) {
    assert_eq!(datetime.as_hms_milli(), expected);
}

#[rstest]
#[case(datetime!(2020-01-01 1:02:03.004_005), (1, 2, 3, 4_005))]
fn as_hms_micro(#[case] datetime: PrimitiveDateTime, #[case] expected: (u8, u8, u8, u32)) {
    assert_eq!(datetime.as_hms_micro(), expected);
}

#[rstest]
#[case(datetime!(2020-01-01 1:02:03.004_005_006), (1, 2, 3, 4_005_006))]
fn as_hms_nano(#[case] datetime: PrimitiveDateTime, #[case] expected: (u8, u8, u8, u32)) {
    assert_eq!(datetime.as_hms_nano(), expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), 0)]
#[case(datetime!(2019-01-01 23:59:59), 23)]
fn hour(#[case] datetime: PrimitiveDateTime, #[case] expected: u8) {
    assert_eq!(datetime.hour(), expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), 0)]
#[case(datetime!(2019-01-01 23:59:59), 59)]
fn minute(#[case] datetime: PrimitiveDateTime, #[case] expected: u8) {
    assert_eq!(datetime.minute(), expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), 0)]
#[case(datetime!(2019-01-01 23:59:59), 59)]
fn second(#[case] datetime: PrimitiveDateTime, #[case] expected: u8) {
    assert_eq!(datetime.second(), expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), 0)]
#[case(datetime!(2019-01-01 23:59:59.999), 999)]
fn millisecond(#[case] datetime: PrimitiveDateTime, #[case] expected: u16) {
    assert_eq!(datetime.millisecond(), expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), 0)]
#[case(datetime!(2019-01-01 23:59:59.999_999), 999_999)]
fn microsecond(#[case] datetime: PrimitiveDateTime, #[case] expected: u32) {
    assert_eq!(datetime.microsecond(), expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), 0)]
#[case(datetime!(2019-01-01 23:59:59.999_999_999), 999_999_999)]
fn nanosecond(#[case] datetime: PrimitiveDateTime, #[case] expected: u32) {
    assert_eq!(datetime.nanosecond(), expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), offset!(UTC), 1_546_300_800)]
#[case(datetime!(2019-01-01 0:00), offset!(-1), 1_546_304_400)]
fn assume_offset(
    #[case] datetime: PrimitiveDateTime,
    #[case] offset: UtcOffset,
    #[case] expected: i64,
) {
    assert_eq!(datetime.assume_offset(offset).unix_timestamp(), expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), 1_546_300_800)]
fn assume_utc(#[case] datetime: PrimitiveDateTime, #[case] expected: i64) {
    assert_eq!(datetime.assume_utc().unix_timestamp(), expected);
}

#[rstest]
#[case(datetime!(2020-01-01 12:00), time!(5:00), datetime!(2020-01-01 5:00))]
fn replace_time(
    #[case] datetime: PrimitiveDateTime,
    #[case] replacement: Time,
    #[case] expected: PrimitiveDateTime,
) {
    assert_eq!(datetime.replace_time(replacement), expected);
}

#[rstest]
#[case(datetime!(2020-01-01 12:00), date!(2020-01-30), datetime!(2020-01-30 12:00))]
fn replace_date(
    #[case] datetime: PrimitiveDateTime,
    #[case] replacement: Date,
    #[case] expected: PrimitiveDateTime,
) {
    assert_eq!(datetime.replace_date(replacement), expected);
}

#[rstest]
#[case(datetime!(2022-02-18 12:00), 2019, datetime!(2019-02-18 12:00))]
#[case(datetime!(2022-02-18 12:00), -1_000_000_000, None)]
#[case(datetime!(2022-02-18 12:00), 1_000_000_000, None)]
fn replace_year(
    #[case] datetime: PrimitiveDateTime,
    #[case] year: i32,
    #[case] expected: impl Into<Option<PrimitiveDateTime>>,
) {
    assert_eq!(datetime.replace_year(year).ok(), expected.into());
}

#[rstest]
#[case(datetime!(2022-02-18 12:00), Month::January, datetime!(2022-01-18 12:00))]
#[case(datetime!(2022-01-30 12:00), Month::February, None)]
fn replace_month(
    #[case] datetime: PrimitiveDateTime,
    #[case] month: Month,
    #[case] expected: impl Into<Option<PrimitiveDateTime>>,
) {
    assert_eq!(datetime.replace_month(month).ok(), expected.into());
}

#[rstest]
#[case(datetime!(2022-02-18 12:00), 1, datetime!(2022-02-01 12:00))]
#[case(datetime!(2022-02-18 12:00), 0, None)]
#[case(datetime!(2022-02-18 12:00), 30, None)]
fn replace_day(
    #[case] datetime: PrimitiveDateTime,
    #[case] day: u8,
    #[case] expected: impl Into<Option<PrimitiveDateTime>>,
) {
    assert_eq!(datetime.replace_day(day).ok(), expected.into());
}

#[rstest]
#[case(datetime!(2022-02-18 12:00), 1, datetime!(2022-001 12:00))]
#[case(datetime!(2024-02-29 12:00), 366, datetime!(2024-366 12:00))]
#[case(datetime!(2022-049 12:00), 0, None)]
#[case(datetime!(2022-049 12:00), 366, None)]
#[case(datetime!(2022-049 12:00), 367, None)]
fn replace_ordinal(
    #[case] datetime: PrimitiveDateTime,
    #[case] ordinal: u16,
    #[case] expected: impl Into<Option<PrimitiveDateTime>>,
) {
    assert_eq!(datetime.replace_ordinal(ordinal).ok(), expected.into());
}

#[rstest]
#[case(datetime!(2022-02-18 01:02:03.004_005_006), 7, datetime!(2022-02-18 07:02:03.004_005_006))]
#[case(datetime!(2022-02-18 01:02:03.004_005_006), 24, None)]
fn replace_hour(
    #[case] datetime: PrimitiveDateTime,
    #[case] value: u8,
    #[case] expected: impl Into<Option<PrimitiveDateTime>>,
) {
    assert_eq!(datetime.replace_hour(value).ok(), expected.into());
}

#[rstest]
#[case(datetime!(2022-02-18 01:02:03.004_005_006), 7, datetime!(2022-02-18 01:07:03.004_005_006))]
#[case(datetime!(2022-02-18 01:02:03.004_005_006), 60, None)]
fn replace_minute(
    #[case] datetime: PrimitiveDateTime,
    #[case] value: u8,
    #[case] expected: impl Into<Option<PrimitiveDateTime>>,
) {
    assert_eq!(datetime.replace_minute(value).ok(), expected.into());
}

#[rstest]
#[case(datetime!(2022-02-18 01:02:03.004_005_006), 7, datetime!(2022-02-18 01:02:07.004_005_006))]
#[case(datetime!(2022-02-18 01:02:03.004_005_006), 60, None)]
fn replace_second(
    #[case] datetime: PrimitiveDateTime,
    #[case] value: u8,
    #[case] expected: impl Into<Option<PrimitiveDateTime>>,
) {
    assert_eq!(datetime.replace_second(value).ok(), expected.into());
}

#[rstest]
#[case(datetime!(2022-02-18 01:02:03.004_005_006), 7, datetime!(2022-02-18 01:02:03.007))]
#[case(datetime!(2022-02-18 01:02:03.004_005_006), 1_000, None)]
fn replace_millisecond(
    #[case] datetime: PrimitiveDateTime,
    #[case] value: u16,
    #[case] expected: impl Into<Option<PrimitiveDateTime>>,
) {
    assert_eq!(datetime.replace_millisecond(value).ok(), expected.into());
}

#[rstest]
#[case(datetime!(2022-02-18 01:02:03.004_005_006), 7_008, datetime!(2022-02-18 01:02:03.007_008))]
#[case(datetime!(2022-02-18 01:02:03.004_005_006), 1_000_000, None)]
fn replace_microsecond(
    #[case] datetime: PrimitiveDateTime,
    #[case] value: u32,
    #[case] expected: impl Into<Option<PrimitiveDateTime>>,
) {
    assert_eq!(datetime.replace_microsecond(value).ok(), expected.into());
}

#[rstest]
#[case(
    datetime!(2022-02-18 01:02:03.004_005_006),
    7_008_009,
    datetime!(2022-02-18 01:02:03.007_008_009),
)]
#[case(datetime!(2022-02-18 01:02:03.004_005_006), 1_000_000_000, None)]
fn replace_nanosecond(
    #[case] datetime: PrimitiveDateTime,
    #[case] value: u32,
    #[case] expected: impl Into<Option<PrimitiveDateTime>>,
) {
    assert_eq!(datetime.replace_nanosecond(value).ok(), expected.into());
}

#[rstest]
#[case(datetime!(2021-11-12 17:47:53.123_456_789), datetime!(2021-11-12 0:00))]
#[case(datetime!(2021-11-12 0:00), datetime!(2021-11-12 0:00))]
fn truncate_to_day(#[case] datetime: PrimitiveDateTime, #[case] expected: PrimitiveDateTime) {
    assert_eq!(datetime.truncate_to_day(), expected);
}

#[rstest]
#[case(datetime!(2021-11-12 17:47:53.123_456_789), datetime!(2021-11-12 17:00))]
#[case(datetime!(2021-11-12 0:00), datetime!(2021-11-12 0:00))]
fn truncate_to_hour(#[case] datetime: PrimitiveDateTime, #[case] expected: PrimitiveDateTime) {
    assert_eq!(datetime.truncate_to_hour(), expected);
}

#[rstest]
#[case(datetime!(2021-11-12 17:47:53.123_456_789), datetime!(2021-11-12 17:47))]
#[case(datetime!(2021-11-12 0:00), datetime!(2021-11-12 0:00))]
fn truncate_to_minute(#[case] datetime: PrimitiveDateTime, #[case] expected: PrimitiveDateTime) {
    assert_eq!(datetime.truncate_to_minute(), expected);
}

#[rstest]
#[case(datetime!(2021-11-12 17:47:53.123_456_789), datetime!(2021-11-12 17:47:53))]
#[case(datetime!(2021-11-12 0:00), datetime!(2021-11-12 0:00))]
fn truncate_to_second(#[case] datetime: PrimitiveDateTime, #[case] expected: PrimitiveDateTime) {
    assert_eq!(datetime.truncate_to_second(), expected);
}

#[rstest]
#[case(datetime!(2021-11-12 17:47:53.123_456_789), datetime!(2021-11-12 17:47:53.123))]
#[case(datetime!(2021-11-12 0:00), datetime!(2021-11-12 0:00))]
fn truncate_to_millisecond(
    #[case] datetime: PrimitiveDateTime,
    #[case] expected: PrimitiveDateTime,
) {
    assert_eq!(datetime.truncate_to_millisecond(), expected);
}

#[rstest]
#[case(datetime!(2021-11-12 17:47:53.123_456_789), datetime!(2021-11-12 17:47:53.123_456))]
#[case(datetime!(2021-11-12 0:00), datetime!(2021-11-12 0:00))]
fn truncate_to_microsecond(
    #[case] datetime: PrimitiveDateTime,
    #[case] expected: PrimitiveDateTime,
) {
    assert_eq!(datetime.truncate_to_microsecond(), expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), 5.days(), datetime!(2019-01-06 0:00))]
#[case(datetime!(2019-12-31 0:00), 1.days(), datetime!(2020-01-01 0:00))]
#[case(datetime!(2019-12-31 23:59:59), 2.seconds(), datetime!(2020-01-01 0:00:01))]
#[case(datetime!(2020-01-01 0:00:01), (-2).seconds(), datetime!(2019-12-31 23:59:59))]
#[case(datetime!(1999-12-31 23:00), 1.hours(), datetime!(2000-01-01 0:00))]
fn add_duration(
    #[case] datetime: PrimitiveDateTime,
    #[case] duration: Duration,
    #[case] expected: PrimitiveDateTime,
) {
    assert_eq!(datetime + duration, expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), 5.std_days(), datetime!(2019-01-06 0:00))]
#[case(datetime!(2019-12-31 0:00), 1.std_days(), datetime!(2020-01-01 0:00))]
#[case(datetime!(2019-12-31 23:59:59), 2.std_seconds(), datetime!(2020-01-01 0:00:01))]
fn add_std_duration(
    #[case] datetime: PrimitiveDateTime,
    #[case] duration: std::time::Duration,
    #[case] expected: PrimitiveDateTime,
) {
    assert_eq!(datetime + duration, expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), 5.days(), datetime!(2019-01-06 0:00))]
#[case(datetime!(2019-12-31 0:00), 1.days(), datetime!(2020-01-01 0:00))]
#[case(datetime!(2019-12-31 23:59:59), 2.seconds(), datetime!(2020-01-01 0:00:01))]
#[case(datetime!(2020-01-01 0:00:01), (-2).seconds(), datetime!(2019-12-31 23:59:59))]
fn add_assign_duration(
    #[case] mut datetime: PrimitiveDateTime,
    #[case] duration: Duration,
    #[case] expected: PrimitiveDateTime,
) {
    datetime += duration;
    assert_eq!(datetime, expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), 5.std_days(), datetime!(2019-01-06 0:00))]
#[case(datetime!(2019-12-31 0:00), 1.std_days(), datetime!(2020-01-01 0:00))]
#[case(datetime!(2019-12-31 23:59:59), 2.std_seconds(), datetime!(2020-01-01 0:00:01))]
fn add_assign_std_duration(
    #[case] mut datetime: PrimitiveDateTime,
    #[case] duration: std::time::Duration,
    #[case] expected: PrimitiveDateTime,
) {
    datetime += duration;
    assert_eq!(datetime, expected);
}

#[rstest]
#[case(datetime!(2019-01-06 0:00), 5.days(), datetime!(2019-01-01 0:00))]
#[case(datetime!(2020-01-01 0:00), 1.days(), datetime!(2019-12-31 0:00))]
#[case(datetime!(2020-01-01 0:00:01), 2.seconds(), datetime!(2019-12-31 23:59:59))]
#[case(datetime!(2019-12-31 23:59:59), (-2).seconds(), datetime!(2020-01-01 0:00:01))]
#[case(datetime!(1999-12-31 23:00), (-1).hours(), datetime!(2000-01-01 0:00))]
fn sub_duration(
    #[case] datetime: PrimitiveDateTime,
    #[case] duration: Duration,
    #[case] expected: PrimitiveDateTime,
) {
    assert_eq!(datetime - duration, expected);
}

#[rstest]
#[case(datetime!(2019-01-06 0:00), 5.std_days(), datetime!(2019-01-01 0:00))]
#[case(datetime!(2020-01-01 0:00), 1.std_days(), datetime!(2019-12-31 0:00))]
#[case(datetime!(2020-01-01 0:00:01), 2.std_seconds(), datetime!(2019-12-31 23:59:59))]
fn sub_std_duration(
    #[case] datetime: PrimitiveDateTime,
    #[case] duration: std::time::Duration,
    #[case] expected: PrimitiveDateTime,
) {
    assert_eq!(datetime - duration, expected);
}

#[rstest]
#[case(datetime!(2019-01-06 0:00), 5.days(), datetime!(2019-01-01 0:00))]
#[case(datetime!(2020-01-01 0:00), 1.days(), datetime!(2019-12-31 0:00))]
#[case(datetime!(2020-01-01 0:00:01), 2.seconds(), datetime!(2019-12-31 23:59:59))]
#[case(datetime!(2019-12-31 23:59:59), (-2).seconds(), datetime!(2020-01-01 0:00:01))]
fn sub_assign_duration(
    #[case] mut datetime: PrimitiveDateTime,
    #[case] duration: Duration,
    #[case] expected: PrimitiveDateTime,
) {
    datetime -= duration;
    assert_eq!(datetime, expected);
}

#[rstest]
#[case(datetime!(2019-01-06 0:00), 5.std_days(), datetime!(2019-01-01 0:00))]
#[case(datetime!(2020-01-01 0:00), 1.std_days(), datetime!(2019-12-31 0:00))]
#[case(datetime!(2020-01-01 0:00:01), 2.std_seconds(), datetime!(2019-12-31 23:59:59))]
fn sub_assign_std_duration(
    #[case] mut datetime: PrimitiveDateTime,
    #[case] duration: std::time::Duration,
    #[case] expected: PrimitiveDateTime,
) {
    datetime -= duration;
    assert_eq!(datetime, expected);
}

#[rstest]
#[case(datetime!(2019-01-02 0:00), datetime!(2019-01-01 0:00), 1.days())]
#[case(datetime!(2019-01-01 0:00), datetime!(2019-01-02 0:00), (-1).days())]
#[case(datetime!(2020-01-01 0:00), datetime!(2019-12-31 0:00), 1.days())]
#[case(datetime!(2019-12-31 0:00), datetime!(2020-01-01 0:00), (-1).days())]
fn sub_datetime(
    #[case] lhs: PrimitiveDateTime,
    #[case] rhs: PrimitiveDateTime,
    #[case] expected: Duration,
) {
    assert_eq!(lhs - rhs, expected);
}

#[rstest]
#[case(datetime!(2019-01-01 0:00), datetime!(2019-01-01 0:00), Ordering::Equal)]
#[case(datetime!(2019-01-01 0:00), datetime!(2020-01-01 0:00), Ordering::Less)]
#[case(datetime!(2019-01-01 0:00), datetime!(2019-02-01 0:00), Ordering::Less)]
#[case(datetime!(2019-01-01 0:00), datetime!(2019-01-02 0:00), Ordering::Less)]
#[case(datetime!(2019-01-01 0:00), datetime!(2019-01-01 1:00), Ordering::Less)]
#[case(datetime!(2019-01-01 0:00), datetime!(2019-01-01 0:01), Ordering::Less)]
#[case(datetime!(2019-01-01 0:00), datetime!(2019-01-01 0:00:01), Ordering::Less)]
#[case(datetime!(2019-01-01 0:00), datetime!(2019-01-01 0:00:00.000_000_001), Ordering::Less)]
#[case(datetime!(2020-01-01 0:00), datetime!(2019-01-01 0:00), Ordering::Greater)]
#[case(datetime!(2019-02-01 0:00), datetime!(2019-01-01 0:00), Ordering::Greater)]
#[case(datetime!(2019-01-02 0:00), datetime!(2019-01-01 0:00), Ordering::Greater)]
#[case(datetime!(2019-01-01 1:00), datetime!(2019-01-01 0:00), Ordering::Greater)]
#[case(datetime!(2019-01-01 0:01), datetime!(2019-01-01 0:00), Ordering::Greater)]
#[case(datetime!(2019-01-01 0:00:01), datetime!(2019-01-01 0:00), Ordering::Greater)]
#[case(datetime!(2019-01-01 0:00:00.000_000_001), datetime!(2019-01-01 0:00), Ordering::Greater)]
#[case(datetime!(-0001-01-01 0:00), datetime!(0001-01-01 0:00), Ordering::Less)]
fn ord(
    #[case] lhs: PrimitiveDateTime,
    #[case] rhs: PrimitiveDateTime,
    #[case] expected: impl Into<Option<Ordering>>,
) {
    assert_eq!(lhs.partial_cmp(&rhs), expected.into());
}

#[rstest]
#[case(
    datetime!(2021-10-25 14:01:53.45),
    5.nanoseconds(),
    datetime!(2021-10-25 14:01:53.450_000_005),
)]
#[case(datetime!(2021-10-25 14:01:53.45), 4.seconds(), datetime!(2021-10-25 14:01:57.45))]
#[case(datetime!(2021-10-25 14:01:53.45), 2.days(), datetime!(2021-10-27 14:01:53.45))]
#[case(datetime!(2021-10-25 14:01:53.45), 1.weeks(), datetime!(2021-11-01 14:01:53.45))]
#[case(
    datetime!(2021-10-25 14:01:53.45),
    (-5).nanoseconds(),
    datetime!(2021-10-25 14:01:53.449_999_995),
)]
#[case(datetime!(2021-10-25 14:01:53.45), (-4).seconds(), datetime!(2021-10-25 14:01:49.45))]
#[case(datetime!(2021-10-25 14:01:53.45), (-2).days(), datetime!(2021-10-23 14:01:53.45))]
#[case(datetime!(2021-10-25 14:01:53.45), (-1).weeks(), datetime!(2021-10-18 14:01:53.45))]
#[case::underflow(PrimitiveDateTime::MIN, (-1).nanoseconds(), None)]
#[case::underflow(PrimitiveDateTime::MIN, Duration::MIN, None)]
#[case::underflow(PrimitiveDateTime::MIN, (-530).weeks(), None)]
#[case::overflow(PrimitiveDateTime::MAX, 1.nanoseconds(), None)]
#[case::overflow(PrimitiveDateTime::MAX, Duration::MAX, None)]
#[case::overflow(PrimitiveDateTime::MAX, 530.weeks(), None)]
fn checked_add_duration(
    #[case] datetime: PrimitiveDateTime,
    #[case] duration: Duration,
    #[case] expected: impl Into<Option<PrimitiveDateTime>>,
) {
    assert_eq!(datetime.checked_add(duration), expected.into());
}

#[rstest]
#[case(
    datetime!(2021-10-25 14:01:53.45),
    (-5).nanoseconds(),
    datetime!(2021-10-25 14:01:53.450_000_005),
)]
#[case(datetime!(2021-10-25 14:01:53.45), (-4).seconds(), datetime!(2021-10-25 14:01:57.45))]
#[case(datetime!(2021-10-25 14:01:53.45), (-2).days(), datetime!(2021-10-27 14:01:53.45))]
#[case(datetime!(2021-10-25 14:01:53.45), (-1).weeks(), datetime!(2021-11-01 14:01:53.45))]
#[case(
    datetime!(2021-10-25 14:01:53.45),
    5.nanoseconds(),
    datetime!(2021-10-25 14:01:53.449_999_995),
)]
#[case(datetime!(2021-10-25 14:01:53.45), 4.seconds(), datetime!(2021-10-25 14:01:49.45))]
#[case(datetime!(2021-10-25 14:01:53.45), 2.days(), datetime!(2021-10-23 14:01:53.45))]
#[case(datetime!(2021-10-25 14:01:53.45), 1.weeks(), datetime!(2021-10-18 14:01:53.45))]
#[case::underflow(PrimitiveDateTime::MIN, 1.nanoseconds(), None)]
#[case::underflow(PrimitiveDateTime::MIN, Duration::MIN, None)]
#[case::underflow(PrimitiveDateTime::MIN, 530.weeks(), None)]
#[case::overflow(PrimitiveDateTime::MAX, (-1).nanoseconds(), None)]
#[case::overflow(PrimitiveDateTime::MAX, Duration::MAX, None)]
#[case::overflow(PrimitiveDateTime::MAX, (-530).weeks(), None)]
fn checked_sub_duration(
    #[case] datetime: PrimitiveDateTime,
    #[case] duration: Duration,
    #[case] expected: impl Into<Option<PrimitiveDateTime>>,
) {
    assert_eq!(datetime.checked_sub(duration), expected.into());
}

#[rstest]
#[case(datetime!(2021-11-12 17:47), 2.days(), datetime!(2021-11-14 17:47))]
#[case(datetime!(2021-11-12 17:47), (-2).days(), datetime!(2021-11-10 17:47))]
#[case::underflow(PrimitiveDateTime::MIN, (-10).days(), PrimitiveDateTime::MIN)]
#[case::overflow(PrimitiveDateTime::MAX, 10.days(), PrimitiveDateTime::MAX)]
#[case::zero_duration_min(PrimitiveDateTime::MIN, Duration::ZERO, PrimitiveDateTime::MIN)]
#[case::zero_duration_max(PrimitiveDateTime::MAX, Duration::ZERO, PrimitiveDateTime::MAX)]
fn saturating_add_duration(
    #[case] datetime: PrimitiveDateTime,
    #[case] duration: Duration,
    #[case] expected: PrimitiveDateTime,
) {
    assert_eq!(datetime.saturating_add(duration), expected);
}

#[rstest]
#[case(datetime!(2021-11-12 17:47), 2.days(), datetime!(2021-11-10 17:47))]
#[case(datetime!(2021-11-12 17:47), (-2).days(), datetime!(2021-11-14 17:47))]
#[case::underflow(PrimitiveDateTime::MIN, 10.days(), PrimitiveDateTime::MIN)]
#[case::overflow(PrimitiveDateTime::MAX, (-10).days(), PrimitiveDateTime::MAX)]
#[case::zero_duration_min(PrimitiveDateTime::MIN, Duration::ZERO, PrimitiveDateTime::MIN)]
#[case::zero_duration_max(PrimitiveDateTime::MAX, Duration::ZERO, PrimitiveDateTime::MAX)]
fn saturating_sub_duration(
    #[case] datetime: PrimitiveDateTime,
    #[case] duration: Duration,
    #[case] expected: PrimitiveDateTime,
) {
    assert_eq!(datetime.saturating_sub(duration), expected);
}