mirror of
https://github.com/chirpstack/chirpstack.git
synced 2025-05-03 09:33:08 +00:00
Fix metrics per day interval calculation.
This fixes the issue where after a from DST to non-DST, the timstamp was not incremented by a full day. As the ts was then truncated to day precision, this would create a never ending loop. Example, incrementing 2022-10-30 00:00:00 by days(1) would result in 2022-10-30 23:00:00, trucated to day precision would result in 2022-10-30 00:00:00. If the date (30) is the same after incrementing by days(1), we increment by days(2), which in the above example results in 2022-10-31 23:00:00, truncated to day precision results in 2022-10-31 00:00:00 which is the desired result.
This commit is contained in:
parent
42d6f62509
commit
6b1cf4f8ba
@ -214,8 +214,18 @@ pub async fn get(
|
|||||||
while ts.le(&end) {
|
while ts.le(&end) {
|
||||||
timestamps.push(ts);
|
timestamps.push(ts);
|
||||||
keys.push(get_key(name, a, ts));
|
keys.push(get_key(name, a, ts));
|
||||||
// Make sure that the timestamp stays at midnight at daylight saving change.
|
ts = {
|
||||||
ts = (ts + ChronoDuration::days(1)).date().and_hms(0, 0, 0);
|
if (ts + ChronoDuration::days(1)).day() == ts.day() {
|
||||||
|
// In case of DST to non-DST transition, the ts is incremented with less
|
||||||
|
// than 24h and we end up with the same day. Therefore we increment by two
|
||||||
|
// days.
|
||||||
|
(ts + ChronoDuration::days(2)).date().and_hms(0, 0, 0)
|
||||||
|
} else {
|
||||||
|
// Make sure that the timestamp stays at midnight in case of non-DST to DST
|
||||||
|
// change.
|
||||||
|
(ts + ChronoDuration::days(1)).date().and_hms(0, 0, 0)
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Aggregation::MONTH => {
|
Aggregation::MONTH => {
|
||||||
@ -431,6 +441,75 @@ pub mod test {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_day_dst_transition() {
|
||||||
|
let _guard = test::prepare().await;
|
||||||
|
|
||||||
|
let records = vec![
|
||||||
|
Record {
|
||||||
|
time: Local.ymd(2022, 10, 30).and_hms(1, 0, 0),
|
||||||
|
kind: Kind::ABSOLUTE,
|
||||||
|
metrics: [("foo".into(), 1f64), ("bar".into(), 2f64)]
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect(),
|
||||||
|
},
|
||||||
|
Record {
|
||||||
|
time: Local.ymd(2022, 10, 30).and_hms(5, 0, 0),
|
||||||
|
kind: Kind::ABSOLUTE,
|
||||||
|
metrics: [("foo".into(), 3f64), ("bar".into(), 4f64)]
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect(),
|
||||||
|
},
|
||||||
|
Record {
|
||||||
|
time: Local.ymd(2022, 10, 31).and_hms(1, 0, 0),
|
||||||
|
kind: Kind::ABSOLUTE,
|
||||||
|
metrics: [("foo".into(), 5f64), ("bar".into(), 6f64)]
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
for r in &records {
|
||||||
|
save_for_interval(Aggregation::DAY, "test", r)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let resp = get(
|
||||||
|
"test",
|
||||||
|
Kind::ABSOLUTE,
|
||||||
|
Aggregation::DAY,
|
||||||
|
Local.ymd(2022, 10, 30).and_hms(1, 0, 0),
|
||||||
|
Local.ymd(2022, 10, 31).and_hms(1, 0, 0),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
vec![
|
||||||
|
Record {
|
||||||
|
time: Local.ymd(2022, 10, 30).and_hms(0, 0, 0),
|
||||||
|
kind: Kind::ABSOLUTE,
|
||||||
|
metrics: [("foo".into(), 4f64), ("bar".into(), 6f64)]
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect(),
|
||||||
|
},
|
||||||
|
Record {
|
||||||
|
time: Local.ymd(2022, 10, 31).and_hms(0, 0, 0),
|
||||||
|
kind: Kind::ABSOLUTE,
|
||||||
|
metrics: [("foo".into(), 5f64), ("bar".into(), 6f64)]
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
],
|
||||||
|
resp
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_month() {
|
async fn test_month() {
|
||||||
let _guard = test::prepare().await;
|
let _guard = test::prepare().await;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user