Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pola-rs
GitHub Repository: pola-rs/polars
Path: blob/main/crates/polars-time/src/windows/test.rs
6939 views
1
use arrow::temporal_conversions::timestamp_ns_to_datetime;
2
use chrono::prelude::*;
3
use polars_core::prelude::*;
4
5
use crate::prelude::*;
6
7
#[test]
8
fn test_date_range() {
9
// Test month as interval in date range
10
let start = NaiveDate::from_ymd_opt(2022, 1, 1)
11
.unwrap()
12
.and_hms_opt(0, 0, 0)
13
.unwrap();
14
let end = NaiveDate::from_ymd_opt(2022, 4, 1)
15
.unwrap()
16
.and_hms_opt(0, 0, 0)
17
.unwrap();
18
let dates = datetime_range_i64(
19
start.and_utc().timestamp_nanos_opt().unwrap(),
20
end.and_utc().timestamp_nanos_opt().unwrap(),
21
Duration::parse("1mo"),
22
ClosedWindow::Both,
23
TimeUnit::Nanoseconds,
24
None,
25
)
26
.unwrap(); // unwrapping as we pass None as the time zone
27
let expected = [
28
NaiveDate::from_ymd_opt(2022, 1, 1).unwrap(),
29
NaiveDate::from_ymd_opt(2022, 2, 1).unwrap(),
30
NaiveDate::from_ymd_opt(2022, 3, 1).unwrap(),
31
NaiveDate::from_ymd_opt(2022, 4, 1).unwrap(),
32
]
33
.iter()
34
.map(|d| {
35
d.and_hms_opt(0, 0, 0)
36
.unwrap()
37
.and_utc()
38
.timestamp_nanos_opt()
39
.unwrap()
40
})
41
.collect::<Vec<_>>();
42
assert_eq!(dates, expected);
43
}
44
45
#[test]
46
fn test_feb_date_range() {
47
let start = NaiveDate::from_ymd_opt(2022, 2, 1)
48
.unwrap()
49
.and_hms_opt(0, 0, 0)
50
.unwrap();
51
let end = NaiveDate::from_ymd_opt(2022, 3, 1)
52
.unwrap()
53
.and_hms_opt(0, 0, 0)
54
.unwrap();
55
let dates = datetime_range_i64(
56
start.and_utc().timestamp_nanos_opt().unwrap(),
57
end.and_utc().timestamp_nanos_opt().unwrap(),
58
Duration::parse("1mo"),
59
ClosedWindow::Both,
60
TimeUnit::Nanoseconds,
61
None,
62
)
63
.unwrap(); // unwrapping as we pass None as the time zone
64
let expected = [
65
NaiveDate::from_ymd_opt(2022, 2, 1).unwrap(),
66
NaiveDate::from_ymd_opt(2022, 3, 1).unwrap(),
67
]
68
.iter()
69
.map(|d| {
70
d.and_hms_opt(0, 0, 0)
71
.unwrap()
72
.and_utc()
73
.timestamp_nanos_opt()
74
.unwrap()
75
})
76
.collect::<Vec<_>>();
77
assert_eq!(dates, expected);
78
}
79
80
fn print_ns(ts: &[i64]) {
81
for ts in ts {
82
println!("{}", timestamp_ns_to_datetime(*ts));
83
}
84
}
85
86
fn take_groups_slice<'a>(groups: &'a GroupsSlice, idx: usize, ts: &'a [i64]) -> &'a [i64] {
87
let [first, len] = groups[idx];
88
let first = first as usize;
89
let len = len as usize;
90
&ts[first..first + len]
91
}
92
93
#[test]
94
fn test_groups_large_interval() {
95
let dates = &[
96
NaiveDate::from_ymd_opt(2020, 1, 1).unwrap(),
97
NaiveDate::from_ymd_opt(2020, 1, 11).unwrap(),
98
NaiveDate::from_ymd_opt(2020, 1, 12).unwrap(),
99
NaiveDate::from_ymd_opt(2020, 1, 13).unwrap(),
100
];
101
let ts = dates
102
.iter()
103
.map(|d| {
104
d.and_hms_opt(0, 0, 0)
105
.unwrap()
106
.and_utc()
107
.timestamp_nanos_opt()
108
.unwrap()
109
})
110
.collect::<Vec<_>>();
111
112
let dur = Duration::parse("2d");
113
let w = Window::new(Duration::parse("2d"), dur, Duration::from_nsecs(0));
114
let (groups, _, _) = group_by_windows(
115
w,
116
&ts,
117
ClosedWindow::Both,
118
TimeUnit::Nanoseconds,
119
&None,
120
false,
121
false,
122
Default::default(),
123
)
124
.unwrap();
125
assert_eq!(groups.len(), 4);
126
assert_eq!(groups[0], [0, 1]);
127
assert_eq!(groups[1], [1, 1]);
128
assert_eq!(groups[2], [1, 3]);
129
assert_eq!(groups[3], [3, 1]);
130
let (groups, _, _) = group_by_windows(
131
w,
132
&ts,
133
ClosedWindow::Left,
134
TimeUnit::Nanoseconds,
135
&None,
136
false,
137
false,
138
Default::default(),
139
)
140
.unwrap();
141
assert_eq!(groups.len(), 3);
142
assert_eq!(groups[2], [3, 1]);
143
let (groups, _, _) = group_by_windows(
144
w,
145
&ts,
146
ClosedWindow::Right,
147
TimeUnit::Nanoseconds,
148
&None,
149
false,
150
false,
151
Default::default(),
152
)
153
.unwrap();
154
assert_eq!(groups.len(), 3);
155
assert_eq!(groups[1], [1, 1]);
156
}
157
158
#[test]
159
fn test_offset() {
160
let t = NaiveDate::from_ymd_opt(2020, 1, 2)
161
.unwrap()
162
.and_hms_opt(0, 0, 0)
163
.unwrap()
164
.and_utc()
165
.timestamp_nanos_opt()
166
.unwrap();
167
let w = Window::new(
168
Duration::parse("5m"),
169
Duration::parse("5m"),
170
Duration::parse("-2m"),
171
);
172
173
let b = w
174
.get_earliest_bounds_ns(t, ClosedWindow::Left, None)
175
.unwrap();
176
let start = NaiveDate::from_ymd_opt(2020, 1, 1)
177
.unwrap()
178
.and_hms_opt(23, 58, 0)
179
.unwrap()
180
.and_utc()
181
.timestamp_nanos_opt()
182
.unwrap();
183
assert_eq!(b.start, start);
184
}
185
186
#[test]
187
fn test_boundaries() {
188
let start = NaiveDate::from_ymd_opt(2021, 12, 16)
189
.unwrap()
190
.and_hms_opt(0, 0, 0)
191
.unwrap();
192
let stop = NaiveDate::from_ymd_opt(2021, 12, 16)
193
.unwrap()
194
.and_hms_opt(3, 0, 0)
195
.unwrap();
196
197
let ts = datetime_range_i64(
198
start.and_utc().timestamp_nanos_opt().unwrap(),
199
stop.and_utc().timestamp_nanos_opt().unwrap(),
200
Duration::parse("30m"),
201
ClosedWindow::Both,
202
TimeUnit::Nanoseconds,
203
None,
204
)
205
.unwrap(); // unwrapping as we pass None as the time zone
206
207
// window:
208
// every 2h
209
// period 1h
210
let w = Window::new(
211
Duration::parse("1h"),
212
Duration::parse("1h"),
213
Duration::parse("0ns"),
214
);
215
216
// earliest bound is first datapoint: 2021-12-16 00:00:00
217
let b = w
218
.get_earliest_bounds_ns(ts[0], ClosedWindow::Both, None)
219
.unwrap();
220
assert_eq!(b.start, start.and_utc().timestamp_nanos_opt().unwrap());
221
222
// test closed: "both" (includes both ends of the interval)
223
let (groups, lower, higher) = group_by_windows(
224
w,
225
&ts,
226
ClosedWindow::Both,
227
TimeUnit::Nanoseconds,
228
&None,
229
true,
230
true,
231
Default::default(),
232
)
233
.unwrap();
234
235
// 1st group
236
// expected boundary:
237
// 2021-12-16 00:00:00 -> 2021-12-16 01:00:00
238
// expected members:
239
// 2021-12-16 00:00:00
240
// 2021-12-16 00:30:00
241
// 2021-12-16 01:00:00
242
let g = take_groups_slice(&groups, 0, &ts);
243
let t0 = NaiveDate::from_ymd_opt(2021, 12, 16)
244
.unwrap()
245
.and_hms_opt(0, 0, 0)
246
.unwrap();
247
let t1 = NaiveDate::from_ymd_opt(2021, 12, 16)
248
.unwrap()
249
.and_hms_opt(0, 30, 0)
250
.unwrap();
251
let t2 = NaiveDate::from_ymd_opt(2021, 12, 16)
252
.unwrap()
253
.and_hms_opt(1, 0, 0)
254
.unwrap();
255
assert_eq!(
256
g,
257
&[
258
t0.and_utc().timestamp_nanos_opt().unwrap(),
259
t1.and_utc().timestamp_nanos_opt().unwrap(),
260
t2.and_utc().timestamp_nanos_opt().unwrap()
261
]
262
);
263
let b_start = NaiveDate::from_ymd_opt(2021, 12, 16)
264
.unwrap()
265
.and_hms_opt(0, 0, 0)
266
.unwrap();
267
let b_end = NaiveDate::from_ymd_opt(2021, 12, 16)
268
.unwrap()
269
.and_hms_opt(1, 0, 0)
270
.unwrap();
271
assert_eq!(
272
&[lower[0], higher[0]],
273
&[
274
b_start.and_utc().timestamp_nanos_opt().unwrap(),
275
b_end.and_utc().timestamp_nanos_opt().unwrap()
276
]
277
);
278
279
// 2nd group
280
// expected boundary:
281
// 2021-12-16 01:0:00 -> 2021-12-16 02:00:00
282
// expected members:
283
// 2021-12-16 01:00:00
284
// 2021-12-16 01:30:00
285
// 2021-12-16 02:00:00
286
let g = take_groups_slice(&groups, 1, &ts);
287
let t0 = NaiveDate::from_ymd_opt(2021, 12, 16)
288
.unwrap()
289
.and_hms_opt(1, 0, 0)
290
.unwrap();
291
let t1 = NaiveDate::from_ymd_opt(2021, 12, 16)
292
.unwrap()
293
.and_hms_opt(1, 30, 0)
294
.unwrap();
295
let t2 = NaiveDate::from_ymd_opt(2021, 12, 16)
296
.unwrap()
297
.and_hms_opt(2, 0, 0)
298
.unwrap();
299
assert_eq!(
300
g,
301
&[
302
t0.and_utc().timestamp_nanos_opt().unwrap(),
303
t1.and_utc().timestamp_nanos_opt().unwrap(),
304
t2.and_utc().timestamp_nanos_opt().unwrap()
305
]
306
);
307
let b_start = NaiveDate::from_ymd_opt(2021, 12, 16)
308
.unwrap()
309
.and_hms_opt(1, 0, 0)
310
.unwrap();
311
let b_end = NaiveDate::from_ymd_opt(2021, 12, 16)
312
.unwrap()
313
.and_hms_opt(2, 0, 0)
314
.unwrap();
315
assert_eq!(
316
&[lower[1], higher[1]],
317
&[
318
b_start.and_utc().timestamp_nanos_opt().unwrap(),
319
b_end.and_utc().timestamp_nanos_opt().unwrap()
320
]
321
);
322
323
assert_eq!(groups[2], [4, 3]);
324
325
// test closed: "left" (should not include right end of interval)
326
let (groups, _, _) = group_by_windows(
327
w,
328
&ts,
329
ClosedWindow::Left,
330
TimeUnit::Nanoseconds,
331
&None,
332
false,
333
false,
334
Default::default(),
335
)
336
.unwrap();
337
assert_eq!(groups[0], [0, 2]); // 00:00:00 -> 00:30:00
338
assert_eq!(groups[1], [2, 2]); // 01:00:00 -> 01:30:00
339
assert_eq!(groups[2], [4, 2]); // 02:00:00 -> 02:30:00
340
341
// test closed: "right" (should not include left end of interval)
342
let (groups, _, _) = group_by_windows(
343
w,
344
&ts,
345
ClosedWindow::Right,
346
TimeUnit::Nanoseconds,
347
&None,
348
false,
349
false,
350
Default::default(),
351
)
352
.unwrap();
353
assert_eq!(groups[0], [0, 1]); // (2021-12-15 23:30, 2021-12-16 00:00]
354
assert_eq!(groups[1], [1, 2]); // (2021-12-16 00:00, 2021-12-16 00:30]
355
assert_eq!(groups[2], [3, 2]); // (2021-12-16 00:30, 2021-12-16 01:00]
356
assert_eq!(groups[3], [5, 2]); // (2021-12-16 01:00, 2021-12-16 01:30]
357
358
// test closed: "none" (should not include left or right end of interval)
359
let (groups, _, _) = group_by_windows(
360
w,
361
&ts,
362
ClosedWindow::None,
363
TimeUnit::Nanoseconds,
364
&None,
365
false,
366
false,
367
Default::default(),
368
)
369
.unwrap();
370
assert_eq!(groups[0], [1, 1]); // 00:00:00 -> 00:30:00
371
assert_eq!(groups[1], [3, 1]); // 01:00:00 -> 01:30:00
372
assert_eq!(groups[2], [5, 1]); // 02:00:00 -> 02:30:00
373
}
374
375
#[test]
376
fn test_boundaries_2() {
377
let start = NaiveDate::from_ymd_opt(2021, 12, 16)
378
.unwrap()
379
.and_hms_opt(0, 0, 0)
380
.unwrap();
381
let stop = NaiveDate::from_ymd_opt(2021, 12, 16)
382
.unwrap()
383
.and_hms_opt(4, 0, 0)
384
.unwrap();
385
386
let ts = datetime_range_i64(
387
start.and_utc().timestamp_nanos_opt().unwrap(),
388
stop.and_utc().timestamp_nanos_opt().unwrap(),
389
Duration::parse("30m"),
390
ClosedWindow::Both,
391
TimeUnit::Nanoseconds,
392
None,
393
)
394
.unwrap(); // unwrapping as we pass None as the time zone
395
396
print_ns(&ts);
397
398
// window:
399
// every 2h
400
// period 1h
401
// offset 30m
402
let offset = Duration::parse("30m");
403
let every = Duration::parse("2h");
404
let w = Window::new(every, Duration::parse("1h"), offset);
405
406
// earliest bound is first datapoint: 2021-12-16 00:00:00 + 30m offset: 2021-12-16 00:30:00
407
// We then shift back by `every` (2h): 2021-12-15 22:30:00
408
let b = w
409
.get_earliest_bounds_ns(ts[0], ClosedWindow::Both, None)
410
.unwrap();
411
412
assert_eq!(
413
b.start,
414
start.and_utc().timestamp_nanos_opt().unwrap() + offset.duration_ns() - every.duration_ns()
415
);
416
417
let (groups, lower, higher) = group_by_windows(
418
w,
419
&ts,
420
ClosedWindow::Left,
421
TimeUnit::Nanoseconds,
422
&None,
423
true,
424
true,
425
Default::default(),
426
)
427
.unwrap();
428
429
// 1st group
430
// expected boundary:
431
// 2021-12-16 00:30:00 -> 2021-12-16 01:30:00
432
// expected members:
433
// 2021-12-16 00:30:00
434
// 2021-12-16 01:00:00
435
// (note that we don't expect 01:30:00 because we close left (and thus open interval right))
436
// see: https://pandas.pydata.org/docs/reference/api/pandas.Interval.html
437
let g = take_groups_slice(&groups, 0, &ts);
438
let t0 = NaiveDate::from_ymd_opt(2021, 12, 16)
439
.unwrap()
440
.and_hms_opt(0, 30, 0)
441
.unwrap();
442
let t1 = NaiveDate::from_ymd_opt(2021, 12, 16)
443
.unwrap()
444
.and_hms_opt(1, 0, 0)
445
.unwrap();
446
assert_eq!(
447
g,
448
&[
449
t0.and_utc().timestamp_nanos_opt().unwrap(),
450
t1.and_utc().timestamp_nanos_opt().unwrap()
451
]
452
);
453
let b_start = NaiveDate::from_ymd_opt(2021, 12, 16)
454
.unwrap()
455
.and_hms_opt(0, 30, 0)
456
.unwrap();
457
let b_end = NaiveDate::from_ymd_opt(2021, 12, 16)
458
.unwrap()
459
.and_hms_opt(1, 30, 0)
460
.unwrap();
461
assert_eq!(
462
&[lower[0], higher[0]],
463
&[
464
b_start.and_utc().timestamp_nanos_opt().unwrap(),
465
b_end.and_utc().timestamp_nanos_opt().unwrap()
466
]
467
);
468
469
// 2nd group
470
// expected boundary:
471
// 2021-12-16 02:30:00 -> 2021-12-16 03:30:00
472
// expected members:
473
// 2021-12-16 02:30:00
474
// 2021-12-16 03:00:00
475
// (note that we don't expect 03:30:00 because we close left)
476
let g = take_groups_slice(&groups, 1, &ts);
477
let t0 = NaiveDate::from_ymd_opt(2021, 12, 16)
478
.unwrap()
479
.and_hms_opt(2, 30, 0)
480
.unwrap();
481
let t1 = NaiveDate::from_ymd_opt(2021, 12, 16)
482
.unwrap()
483
.and_hms_opt(3, 0, 0)
484
.unwrap();
485
assert_eq!(
486
g,
487
&[
488
t0.and_utc().timestamp_nanos_opt().unwrap(),
489
t1.and_utc().timestamp_nanos_opt().unwrap()
490
]
491
);
492
let b_start = NaiveDate::from_ymd_opt(2021, 12, 16)
493
.unwrap()
494
.and_hms_opt(2, 30, 0)
495
.unwrap();
496
let b_end = NaiveDate::from_ymd_opt(2021, 12, 16)
497
.unwrap()
498
.and_hms_opt(3, 30, 0)
499
.unwrap();
500
assert_eq!(
501
&[lower[1], higher[1]],
502
&[
503
b_start.and_utc().timestamp_nanos_opt().unwrap(),
504
b_end.and_utc().timestamp_nanos_opt().unwrap()
505
]
506
);
507
}
508
509
#[test]
510
fn test_boundaries_ms() {
511
let start = NaiveDate::from_ymd_opt(2021, 12, 16)
512
.unwrap()
513
.and_hms_opt(0, 0, 0)
514
.unwrap();
515
let stop = NaiveDate::from_ymd_opt(2021, 12, 16)
516
.unwrap()
517
.and_hms_opt(3, 0, 0)
518
.unwrap();
519
520
let ts = datetime_range_i64(
521
start.and_utc().timestamp_millis(),
522
stop.and_utc().timestamp_millis(),
523
Duration::parse("30m"),
524
ClosedWindow::Both,
525
TimeUnit::Milliseconds,
526
None,
527
)
528
.unwrap(); // unwrapping as we pass None as the time zone
529
530
// window:
531
// every 2h
532
// period 1h
533
let w = Window::new(
534
Duration::parse("1h"),
535
Duration::parse("1h"),
536
Duration::parse("0ns"),
537
);
538
539
// earliest bound is first datapoint: 2021-12-16 00:00:00
540
let b = w
541
.get_earliest_bounds_ms(ts[0], ClosedWindow::Both, None)
542
.unwrap();
543
assert_eq!(b.start, start.and_utc().timestamp_millis());
544
545
// test closed: "both" (includes both ends of the interval)
546
let (groups, lower, higher) = group_by_windows(
547
w,
548
&ts,
549
ClosedWindow::Both,
550
TimeUnit::Milliseconds,
551
&None,
552
true,
553
true,
554
Default::default(),
555
)
556
.unwrap();
557
558
// 1st group
559
// expected boundary:
560
// 2021-12-16 00:00:00 -> 2021-12-16 01:00:00
561
// expected members:
562
// 2021-12-16 00:00:00
563
// 2021-12-16 00:30:00
564
// 2021-12-16 01:00:00
565
let g = take_groups_slice(&groups, 0, &ts);
566
let t0 = NaiveDate::from_ymd_opt(2021, 12, 16)
567
.unwrap()
568
.and_hms_opt(0, 0, 0)
569
.unwrap();
570
let t1 = NaiveDate::from_ymd_opt(2021, 12, 16)
571
.unwrap()
572
.and_hms_opt(0, 30, 0)
573
.unwrap();
574
let t2 = NaiveDate::from_ymd_opt(2021, 12, 16)
575
.unwrap()
576
.and_hms_opt(1, 0, 0)
577
.unwrap();
578
assert_eq!(
579
g,
580
&[
581
t0.and_utc().timestamp_millis(),
582
t1.and_utc().timestamp_millis(),
583
t2.and_utc().timestamp_millis()
584
]
585
);
586
let b_start = NaiveDate::from_ymd_opt(2021, 12, 16)
587
.unwrap()
588
.and_hms_opt(0, 0, 0)
589
.unwrap();
590
let b_end = NaiveDate::from_ymd_opt(2021, 12, 16)
591
.unwrap()
592
.and_hms_opt(1, 0, 0)
593
.unwrap();
594
assert_eq!(
595
&[lower[0], higher[0]],
596
&[
597
b_start.and_utc().timestamp_millis(),
598
b_end.and_utc().timestamp_millis()
599
]
600
);
601
602
// 2nd group
603
// expected boundary:
604
// 2021-12-16 01:0:00 -> 2021-12-16 02:00:00
605
// expected members:
606
// 2021-12-16 01:00:00
607
// 2021-12-16 01:30:00
608
// 2021-12-16 02:00:00
609
let g = take_groups_slice(&groups, 1, &ts);
610
let t0 = NaiveDate::from_ymd_opt(2021, 12, 16)
611
.unwrap()
612
.and_hms_opt(1, 0, 0)
613
.unwrap();
614
let t1 = NaiveDate::from_ymd_opt(2021, 12, 16)
615
.unwrap()
616
.and_hms_opt(1, 30, 0)
617
.unwrap();
618
let t2 = NaiveDate::from_ymd_opt(2021, 12, 16)
619
.unwrap()
620
.and_hms_opt(2, 0, 0)
621
.unwrap();
622
assert_eq!(
623
g,
624
&[
625
t0.and_utc().timestamp_millis(),
626
t1.and_utc().timestamp_millis(),
627
t2.and_utc().timestamp_millis()
628
]
629
);
630
let b_start = NaiveDate::from_ymd_opt(2021, 12, 16)
631
.unwrap()
632
.and_hms_opt(1, 0, 0)
633
.unwrap();
634
let b_end = NaiveDate::from_ymd_opt(2021, 12, 16)
635
.unwrap()
636
.and_hms_opt(2, 0, 0)
637
.unwrap();
638
assert_eq!(
639
&[lower[1], higher[1]],
640
&[
641
b_start.and_utc().timestamp_millis(),
642
b_end.and_utc().timestamp_millis()
643
]
644
);
645
646
assert_eq!(groups[2], [4, 3]);
647
648
// test closed: "left" (should not include right end of interval)
649
let (groups, _, _) = group_by_windows(
650
w,
651
&ts,
652
ClosedWindow::Left,
653
TimeUnit::Milliseconds,
654
&None,
655
false,
656
false,
657
Default::default(),
658
)
659
.unwrap();
660
assert_eq!(groups[0], [0, 2]); // 00:00:00 -> 00:30:00
661
assert_eq!(groups[1], [2, 2]); // 01:00:00 -> 01:30:00
662
assert_eq!(groups[2], [4, 2]); // 02:00:00 -> 02:30:00
663
664
// test closed: "right" (should not include left end of interval)
665
let (groups, _, _) = group_by_windows(
666
w,
667
&ts,
668
ClosedWindow::Right,
669
TimeUnit::Milliseconds,
670
&None,
671
false,
672
false,
673
Default::default(),
674
)
675
.unwrap();
676
assert_eq!(groups[0], [0, 1]); // (2021-12-15 23:30, 2021-12-16 00:00]
677
assert_eq!(groups[1], [1, 2]); // (2021-12-16 00:00, 2021-12-16 00:30]
678
assert_eq!(groups[2], [3, 2]); // (2021-12-16 00:30, 2021-12-16 01:00]
679
assert_eq!(groups[3], [5, 2]); // (2021-12-16 01:00, 2021-12-16 01:30]
680
681
// test closed: "none" (should not include left or right end of interval)
682
let (groups, _, _) = group_by_windows(
683
w,
684
&ts,
685
ClosedWindow::None,
686
TimeUnit::Milliseconds,
687
&None,
688
false,
689
false,
690
Default::default(),
691
)
692
.unwrap();
693
assert_eq!(groups[0], [1, 1]); // 00:00:00 -> 00:30:00
694
assert_eq!(groups[1], [3, 1]); // 01:00:00 -> 01:30:00
695
assert_eq!(groups[2], [5, 1]); // 02:00:00 -> 02:30:00
696
}
697
698
#[test]
699
fn test_rolling_lookback() {
700
// Test month as interval in date range
701
let start = NaiveDate::from_ymd_opt(1970, 1, 16)
702
.unwrap()
703
.and_hms_opt(0, 0, 0)
704
.unwrap();
705
let end = NaiveDate::from_ymd_opt(1970, 1, 16)
706
.unwrap()
707
.and_hms_opt(4, 0, 0)
708
.unwrap();
709
let dates = datetime_range_i64(
710
start.and_utc().timestamp_millis(),
711
end.and_utc().timestamp_millis(),
712
Duration::parse("30m"),
713
ClosedWindow::Both,
714
TimeUnit::Milliseconds,
715
None,
716
)
717
.unwrap(); // unwrapping as we pass None as the time zone
718
719
// full lookbehind
720
let groups = group_by_values(
721
Duration::parse("2h"),
722
Duration::parse("-2h"),
723
&dates,
724
ClosedWindow::Right,
725
TimeUnit::Milliseconds,
726
None,
727
)
728
.unwrap();
729
assert_eq!(dates.len(), groups.len());
730
assert_eq!(groups[0], [0, 1]); // bound: 22:00 -> 24:00 time: 24:00
731
assert_eq!(groups[1], [0, 2]); // bound: 22:30 -> 00:30 time: 00:30
732
assert_eq!(groups[2], [0, 3]); // bound: 23:00 -> 01:00 time: 01:00
733
assert_eq!(groups[3], [0, 4]); // bound: 23:30 -> 01:30 time: 01:30
734
assert_eq!(groups[4], [1, 4]); // bound: 24:00 -> 02:00 time: 02:00
735
assert_eq!(groups[5], [2, 4]); // bound: 00:30 -> 02:30 time: 02:30
736
assert_eq!(groups[6], [3, 4]); // bound: 01:00 -> 03:00 time: 03:00
737
assert_eq!(groups[7], [4, 4]); // bound: 01:30 -> 03:30 time: 03:30
738
assert_eq!(groups[8], [5, 4]); // bound: 02:00 -> 04:00 time: 04:00
739
740
// partial lookbehind
741
let groups = group_by_values(
742
Duration::parse("2h"),
743
Duration::parse("-1h"),
744
&dates,
745
ClosedWindow::Right,
746
TimeUnit::Milliseconds,
747
None,
748
)
749
.unwrap();
750
assert_eq!(dates.len(), groups.len());
751
assert_eq!(groups[0], [0, 3]);
752
assert_eq!(groups[1], [0, 4]);
753
assert_eq!(groups[2], [1, 4]);
754
assert_eq!(groups[3], [2, 4]);
755
assert_eq!(groups[4], [3, 4]);
756
assert_eq!(groups[5], [4, 4]);
757
assert_eq!(groups[6], [5, 4]);
758
assert_eq!(groups[7], [6, 3]);
759
assert_eq!(groups[8], [7, 2]);
760
761
// no lookbehind
762
let groups = group_by_values(
763
Duration::parse("2h"),
764
Duration::parse("0h"),
765
&dates,
766
ClosedWindow::Right,
767
TimeUnit::Milliseconds,
768
None,
769
)
770
.unwrap();
771
assert_eq!(dates.len(), groups.len());
772
assert_eq!(groups[0], [1, 4]); // (00:00, 02:00]
773
assert_eq!(groups[1], [2, 4]); // (00:30, 02:30]
774
assert_eq!(groups[2], [3, 4]); // (01:00, 03:00]
775
assert_eq!(groups[3], [4, 4]); // (01:30, 03:30]
776
assert_eq!(groups[4], [5, 4]); // (02:00, 04:00]
777
assert_eq!(groups[5], [6, 3]); // (02:30, 04:30]
778
assert_eq!(groups[6], [7, 2]); // (03:00, 05:00]
779
assert_eq!(groups[7], [8, 1]); // (03:30, 05:30]
780
assert_eq!(groups[8], [9, 0]); // (04:00, 06:00]
781
782
let period = Duration::parse("2h");
783
let tu = TimeUnit::Milliseconds;
784
for closed_window in [
785
ClosedWindow::Left,
786
ClosedWindow::Right,
787
ClosedWindow::Both,
788
ClosedWindow::None,
789
] {
790
let offset = Duration::parse("-2h");
791
let g0 = group_by_values_iter_lookbehind(
792
period,
793
offset,
794
&dates,
795
closed_window,
796
tu,
797
None,
798
0,
799
None,
800
)
801
.unwrap()
802
.collect::<PolarsResult<Vec<_>>>()
803
.unwrap();
804
let g1 = group_by_values_iter_partial_lookbehind(
805
period,
806
offset,
807
&dates,
808
closed_window,
809
tu,
810
None,
811
)
812
.collect::<PolarsResult<Vec<_>>>()
813
.unwrap();
814
assert_eq!(g0, g1);
815
}
816
}
817
818
#[test]
819
fn test_end_membership() {
820
let time = [
821
NaiveDate::from_ymd_opt(2021, 2, 1)
822
.unwrap()
823
.and_hms_opt(0, 0, 0)
824
.unwrap()
825
.and_utc()
826
.timestamp_millis(),
827
NaiveDate::from_ymd_opt(2021, 5, 1)
828
.unwrap()
829
.and_hms_opt(0, 0, 0)
830
.unwrap()
831
.and_utc()
832
.timestamp_millis(),
833
];
834
let window = Window::new(
835
Duration::parse("1mo"),
836
Duration::parse("2mo"),
837
Duration::parse("-2mo"),
838
);
839
// windows
840
// 2020-12-01 -> 2021-02-01 members: None
841
// 2021-01-01 -> 2021-03-01 members: [0]
842
// 2021-02-01 -> 2021-04-01 members: [0]
843
// 2021-03-01 -> 2021-05-01 members: None
844
// 2021-04-01 -> 2021-06-01 members: [1]
845
// 2021-05-01 -> 2021-07-01 members: [1]
846
let (groups, _, _) = group_by_windows(
847
window,
848
&time,
849
ClosedWindow::Left,
850
TimeUnit::Milliseconds,
851
&None,
852
false,
853
false,
854
Default::default(),
855
)
856
.unwrap();
857
assert_eq!(groups[0], [0, 1]);
858
assert_eq!(groups[1], [0, 1]);
859
assert_eq!(groups[2], [1, 1]);
860
assert_eq!(groups[3], [1, 1]);
861
}
862
863
#[test]
864
fn test_group_by_windows_membership_2791() {
865
let dates = [0, 0, 2, 2];
866
let window = Window::new(
867
Duration::parse("1ms"),
868
Duration::parse("1ms"),
869
Duration::parse("0ns"),
870
);
871
let (groups, _, _) = group_by_windows(
872
window,
873
&dates,
874
ClosedWindow::Left,
875
TimeUnit::Milliseconds,
876
&None,
877
false,
878
false,
879
Default::default(),
880
)
881
.unwrap();
882
assert_eq!(groups[0], [0, 2]);
883
assert_eq!(groups[1], [2, 2]);
884
}
885
886
#[test]
887
fn test_group_by_windows_duplicates_2931() {
888
let dates = [0, 3, 3, 5, 5];
889
let window = Window::new(
890
Duration::parse("1ms"),
891
Duration::parse("1ms"),
892
Duration::parse("0ns"),
893
);
894
895
let (groups, _, _) = group_by_windows(
896
window,
897
&dates,
898
ClosedWindow::Left,
899
TimeUnit::Milliseconds,
900
&None,
901
false,
902
false,
903
Default::default(),
904
)
905
.unwrap();
906
assert_eq!(groups, [[0, 1], [1, 2], [3, 2]]);
907
}
908
909
#[test]
910
fn test_group_by_windows_offsets_3776() {
911
let dates = &[
912
NaiveDate::from_ymd_opt(2020, 12, 1).unwrap(),
913
NaiveDate::from_ymd_opt(2021, 2, 1).unwrap(),
914
NaiveDate::from_ymd_opt(2021, 5, 1).unwrap(),
915
];
916
let ts = dates
917
.iter()
918
.map(|d| {
919
d.and_hms_opt(0, 0, 0)
920
.unwrap()
921
.and_utc()
922
.timestamp_nanos_opt()
923
.unwrap()
924
})
925
.collect::<Vec<_>>();
926
927
let window = Window::new(
928
Duration::parse("2d"),
929
Duration::parse("2d"),
930
Duration::parse("-2d"),
931
);
932
let (groups, _, _) = group_by_windows(
933
window,
934
&ts,
935
ClosedWindow::Right,
936
TimeUnit::Nanoseconds,
937
&None,
938
false,
939
false,
940
Default::default(),
941
)
942
.unwrap();
943
assert_eq!(groups, [[0, 1], [1, 1], [2, 1]]);
944
}
945
946