Crates.io | chrono-intervals |
lib.rs | chrono-intervals |
version | 0.3.0 |
source | src |
created_at | 2022-10-31 10:16:08.164335 |
updated_at | 2022-11-05 12:33:04.367032 |
description | Create chrono time intervals as per-day, per-week etc. |
homepage | https://github.com/sgasse/chrono-intervals |
repository | https://github.com/sgasse/chrono-intervals |
max_upload_size | |
id | 702058 |
size | 64,735 |
Create chrono time intervals as "per-day", "per-week" etc.
The most convenient way to get intervals is by creating an
IntervalGenerator
.
use chrono::{DateTime, TimeZone, Utc};
use chrono_intervals::{IntervalGenerator};
let begin = DateTime::parse_from_rfc3339("2022-06-25T08:23:45.000000Z").unwrap();
let end = DateTime::parse_from_rfc3339("2022-06-27T09:31:12.000000Z").unwrap();
let daily_intervals = IntervalGenerator::new().get_intervals(begin, end);
assert_eq!(
daily_intervals,
vec![
(
Utc.ymd(2022, 6, 25).and_hms(0, 0, 0),
Utc.ymd(2022, 6, 25).and_hms_milli(23, 59, 59, 999),
),
(
Utc.ymd(2022, 6, 26).and_hms(0, 0, 0),
Utc.ymd(2022, 6, 26).and_hms_milli(23, 59, 59, 999),
),
(
Utc.ymd(2022, 6, 27).and_hms(0, 0, 0),
Utc.ymd(2022, 6, 27).and_hms_milli(23, 59, 59, 999),
),
]
);
The IntervalGenerator
can be configured in many ways. Let's look at an
example of retrieving monthly intervals but in the Pacific Daylight Time
(PDT) timezone:
use chrono::{DateTime, TimeZone, Utc};
use chrono_intervals::{Grouping, IntervalGenerator};
// We want to obtain monthly intervals for month in PDT instead of in UTC.
let begin = DateTime::parse_from_rfc3339("2022-06-10T12:23:45.000000-07:00").unwrap();
let end = DateTime::parse_from_rfc3339("2022-08-26T12:23:45.000000-07:00").unwrap();
// PDT is 7h behind of UTC (towards the **west**), thus the
// `offset_west_seconds` are 7*3600
let pdt_offset_west_seconds = 7 * 3600;
let monthly_intervals = IntervalGenerator::new()
.with_grouping(Grouping::PerMonth)
.with_offset_west_secs(pdt_offset_west_seconds)
.get_intervals(begin, end);
// In UTC, we expect the intervals to start 7h after the month boundary.
assert_eq!(
monthly_intervals,
vec![
(
Utc.ymd(2022, 6, 1).and_hms(7, 0, 0),
Utc.ymd(2022, 7, 1).and_hms_milli(6, 59, 59, 999),
),
(
Utc.ymd(2022, 7, 1).and_hms(7, 0, 0),
Utc.ymd(2022, 8, 1).and_hms_milli(6, 59, 59, 999),
),
(
Utc.ymd(2022, 8, 1).and_hms(7, 0, 0),
Utc.ymd(2022, 9, 1).and_hms_milli(6, 59, 59, 999),
),
]
);
Here is an overview of configurable options and their defaults:
Grouping
, the default is Grouping::PerDay
.chrono::Duration
. We do not check that the precision is
reasonable. You probably want to set it to the smallest duration that you
still consider, e.g. milliseconds or microseconds.begin
or not: By default,
the first interval will start on the boundary before begin
. You can
switch this off if you want only full intervals that are strickly after
begin
.end
or not: By default, the
last interval will end at the boundary after end
. You can switch this
off if you want only full intervals that are strickly before end
.Let's look at an example with all configuration options used:
use chrono::{DateTime, Duration, TimeZone, Utc};
use chrono_intervals::{Grouping, IntervalGenerator};
let begin = DateTime::parse_from_rfc3339("2022-10-02T08:23:45.000000Z").unwrap();
let end = DateTime::parse_from_rfc3339("2022-10-18T08:23:45.000000Z").unwrap();
let inter_gen = IntervalGenerator::new()
.with_grouping(Grouping::PerWeek)
.with_precision(Duration::microseconds(1))
.with_offset_west_secs(-3600)
.without_extended_begin()
.without_extended_end();
let weekly_intervals = inter_gen.get_intervals(begin, end);
assert_eq!(
weekly_intervals,
vec![
(
Utc.ymd(2022, 10, 2).and_hms(23, 0, 0),
Utc.ymd(2022, 10, 9).and_hms_micro(22, 59, 59, 999999),
),
(
Utc.ymd(2022, 10, 9).and_hms(23, 0, 0),
Utc.ymd(2022, 10, 16).and_hms_micro(22, 59, 59, 999999),
),
]
);
The generator is the most convenient way. However you can also use two different functions to obtain intervals:
get_extended_utc_intervals
returns grouped intervals which enclose the
begin
and end
and have a precision of 1ms. This is pretty close to
the default IntervalGenerator
behavior, just that you have to
specify a Grouping
.get_utc_intervals_opts
returns grouped intervals and allows to specify
all options that the generator also accepts.Get daily intervals between two times with default options:
use chrono::{DateTime, TimeZone, Utc};
use chrono_intervals::{Grouping, get_extended_utc_intervals};
let begin = DateTime::parse_from_rfc3339("2022-06-25T08:23:45.000000Z").unwrap();
let end = DateTime::parse_from_rfc3339("2022-06-27T09:31:12.000000Z").unwrap();
let daily_intervals =
get_extended_utc_intervals(begin, end, &Grouping::PerDay, 0);
assert_eq!(
daily_intervals,
vec![
(
Utc.ymd(2022, 6, 25).and_hms(0, 0, 0),
Utc.ymd(2022, 6, 25).and_hms_milli(23, 59, 59, 999),
),
(
Utc.ymd(2022, 6, 26).and_hms(0, 0, 0),
Utc.ymd(2022, 6, 26).and_hms_milli(23, 59, 59, 999),
),
(
Utc.ymd(2022, 6, 27).and_hms(0, 0, 0),
Utc.ymd(2022, 6, 27).and_hms_milli(23, 59, 59, 999),
),
]
);
Get monthly intervals with default options in the Pacific Daylight Time (PDT) timezone:
use chrono::{DateTime, TimeZone, Utc};
use chrono_intervals::{Grouping, get_extended_utc_intervals};
// We want to obtain monthly intervals for months in PDT instead of in UTC.
let begin = DateTime::parse_from_rfc3339("2022-06-10T12:23:45.000000-07:00").unwrap();
let end = DateTime::parse_from_rfc3339("2022-08-26T12:23:45.000000-07:00").unwrap();
// PDT is 7h behind of UTC (towards the **west**), thus the
// `offset_west_seconds` are 7*3600
let pdt_offset_west_seconds = 7 * 3600;
let monthly_intervals =
get_extended_utc_intervals(begin, end, &Grouping::PerMonth, pdt_offset_west_seconds);
// In UTC, we expect the intervals to start 7h after the day boundary.
assert_eq!(
monthly_intervals,
vec![
(
Utc.ymd(2022, 6, 1).and_hms(7, 0, 0),
Utc.ymd(2022, 7, 1).and_hms_milli(6, 59, 59, 999),
),
(
Utc.ymd(2022, 7, 1).and_hms(7, 0, 0),
Utc.ymd(2022, 8, 1).and_hms_milli(6, 59, 59, 999),
),
(
Utc.ymd(2022, 8, 1).and_hms(7, 0, 0),
Utc.ymd(2022, 9, 1).and_hms_milli(6, 59, 59, 999),
),
]
);
Specify options for get_utc_intervals_opts
:
use chrono::{DateTime, Duration, TimeZone, Utc};
use chrono_intervals::{Grouping, get_utc_intervals_opts};
let begin = DateTime::parse_from_rfc3339("2022-06-15T08:23:45.000000Z").unwrap();
let end = DateTime::parse_from_rfc3339("2022-06-30T09:31:12.000000Z").unwrap();
let weekly_intervals =
get_utc_intervals_opts(
begin,
end,
&Grouping::PerWeek,
0,
Duration::microseconds(1), // interval end is 1µs before the next
false, // start on the boundary after `start`
true, // end at the boundary after `end`
);
assert_eq!(
weekly_intervals,
vec![
(
// First interval begins **after** `begin`
Utc.ymd(2022, 6, 20).and_hms(0, 0, 0),
Utc.ymd(2022, 6, 26).and_hms_micro(23, 59, 59, 999999),
),
(
Utc.ymd(2022, 6, 27).and_hms(0, 0, 0),
// Last interval ends **after** `end`
Utc.ymd(2022, 7, 3).and_hms_micro(23, 59, 59, 999999),
),
]
);