Repository: remi-dupre/opening-hours-rs (language: python)

Issue:
opening_hours.intervals(start, end) does not include intervals after last midnight in the specified range
Hello `opening-hours-rs` 👋🏾 
I found an issue where `opening_hours.intervals(start, end)` does not include intervals after last midnight between `start` and `end`.

Current behaviour is:
```
>>> list(OpeningHours('Mo-Su 00:00-06:00, 23:00-00:00').intervals(datetime(2024, 11, 11, 1, 0),datetime(2024, 11, 12, 1, 0)))
[
  (datetime.datetime(2024, 11, 11, 1, 0), datetime.datetime(2024, 11, 11, 6, 0), 'open', []),
  (datetime.datetime(2024, 11, 11, 6, 0), datetime.datetime(2024, 11, 11, 23, 0), 'closed', []),
  (datetime.datetime(2024, 11, 11, 23, 0), datetime.datetime(2024, 11, 12, 0, 0), 'open', [])
]
```
We would expect to see a fourth interval:
```(datetime.datetime(2024, 11, 12, 0, 0), datetime.datetime(2024, 11, 12, 1, 0), 'open', [])```
or maybe a longer third interval:
```(datetime.datetime(2024, 11, 11, 23, 0), datetime.datetime(2024, 11, 12, 1, 0), 'open', [])```

More broadly `intervals` seems to run up to the last midnight included between `start` and `end`.
This example works fine because end is at a midnight:
```
>>> list(OpeningHours('Mo-Su 23:00-06:00').intervals(datetime(2024, 11, 11, 1, 0),datetime(2024, 11, 13, 0, 0)))
[
  (datetime.datetime(2024, 11, 11, 1, 0), datetime.datetime(2024, 11, 11, 6, 0), 'open', []),
  (datetime.datetime(2024, 11, 11, 6, 0), datetime.datetime(2024, 11, 11, 23, 0), 'closed', []),
  (datetime.datetime(2024, 11, 11, 23, 0), datetime.datetime(2024, 11, 12, 6, 0), 'open', []),
  (datetime.datetime(2024, 11, 12, 6, 0), datetime.datetime(2024, 11, 12, 23, 0), 'closed', []),
  (datetime.datetime(2024, 11, 12, 23, 0), datetime.datetime(2024, 11, 13, 0, 0), 'open', [])
]
```
This example again misses out the final interval because `end` runs into the next day:
```
>>> list(OpeningHours('Mo-Su 23:00-06:00').intervals(datetime(2024, 11, 11, 1, 0),datetime(2024, 11, 13, 5, 0)))
[
  (datetime.datetime(2024, 11, 11, 1, 0), datetime.datetime(2024, 11, 11, 6, 0), 'open', []),
  (datetime.datetime(2024, 11, 11, 6, 0), datetime.datetime(2024, 11, 11, 23, 0), 'closed', []),
  (datetime.datetime(2024, 11, 11, 23, 0), datetime.datetime(2024, 11, 12, 6, 0), 'open', []),
  (datetime.datetime(2024, 11, 12, 6, 0), datetime.datetime(2024, 11, 12, 23, 0), 'closed', []),
  (datetime.datetime(2024, 11, 12, 23, 0), datetime.datetime(2024, 11, 13, 0, 0), 'open', [])
]
```

(Note for the above examples I've also tested with a couple different tariff formats like 'Mo-Su 00:00-06:00, 23:00-24:00' or 'Mo-Su 23:00-06:00' and got the same results)

It would be great to fix this so that `intervals` can return correct values
Thanks for your time


Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 45e3b59..4a9a1c2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
 # Changelog
 
+## 0.8.3
+
+### Fixes
+
+- Fix [#52](https://github.com/remi-dupre/opening-hours-rs/pull/52): intervals
+  were stopping at midnight before the last day.
+
 
 ## 0.8.2
 
diff --git a/Cargo.lock b/Cargo.lock
index c5b1136..3f414a1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -171,7 +171,7 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
 
 [[package]]
 name = "compact-calendar"
-version = "0.8.2"
+version = "0.8.3"
 dependencies = [
  "chrono",
 ]
@@ -499,7 +499,7 @@ checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9"
 
 [[package]]
 name = "opening-hours"
-version = "0.8.2"
+version = "0.8.3"
 dependencies = [
  "chrono",
  "compact-calendar",
@@ -511,7 +511,7 @@ dependencies = [
 
 [[package]]
 name = "opening-hours-py"
-version = "0.8.2"
+version = "0.8.3"
 dependencies = [
  "chrono",
  "opening-hours",
@@ -522,7 +522,7 @@ dependencies = [
 
 [[package]]
 name = "opening-hours-syntax"
-version = "0.8.2"
+version = "0.8.3"
 dependencies = [
  "chrono",
  "log",
diff --git a/Cargo.toml b/Cargo.toml
index 4bbffab..0fbab8d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "opening-hours"
-version = "0.8.2"
+version = "0.8.3"
 authors = ["Rémi Dupré <remi@dupre.io>"]
 license = "MIT OR Apache-2.0"
 readme = "README.md"
diff --git a/compact-calendar/Cargo.toml b/compact-calendar/Cargo.toml
index 2230951..1a9a7b2 100644
--- a/compact-calendar/Cargo.toml
+++ b/compact-calendar/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "compact-calendar"
-version = "0.8.2"
+version = "0.8.3"
 authors = ["Rémi Dupré <remi@dupre.io>"]
 license = "MIT OR Apache-2.0"
 readme = "README.md"
diff --git a/opening-hours-syntax/Cargo.toml b/opening-hours-syntax/Cargo.toml
index 5a49a7c..97028da 100644
--- a/opening-hours-syntax/Cargo.toml
+++ b/opening-hours-syntax/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "opening-hours-syntax"
-version = "0.8.2"
+version = "0.8.3"
 authors = ["Rémi Dupré <remi@dupre.io>"]
 license = "MIT OR Apache-2.0"
 readme = "README.md"
diff --git a/pyproject.toml b/pyproject.toml
index f40a8c0..d17a333 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "opening-hours-py"
-version = "0.8.2"
+version = "0.8.3"
 description = "A parser for the opening_hours fields from OpenStreetMap."
 authors = ["Rémi Dupré <remi@dupre.io>"]
 
diff --git a/python/Cargo.toml b/python/Cargo.toml
index f60794b..68ff345 100644
--- a/python/Cargo.toml
+++ b/python/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "opening-hours-py"
-version = "0.8.2"
+version = "0.8.3"
 authors = ["Rémi Dupré <remi@dupre.io>"]
 license = "MIT OR Apache-2.0"
 readme = "README.md"
diff --git a/src/opening_hours.rs b/src/opening_hours.rs
index f221c6e..0a220a5 100644
--- a/src/opening_hours.rs
+++ b/src/opening_hours.rs
@@ -315,7 +315,8 @@ impl<'d> TimeDomainIterator<'d> {
                 assert!(next_change_hint > self.curr_date);
                 self.curr_date = next_change_hint;
 
-                if self.curr_date < self.end_datetime.date() {
+                if self.curr_date <= self.end_datetime.date() && self.curr_date < DATE_LIMIT.date()
+                {
                     self.curr_schedule = self
                         .opening_hours
                         .schedule_at(self.curr_date)


Test patch:
diff --git a/src/tests/issues.rs b/src/tests/issues.rs
index 96c2fae..c28f41f 100644
--- a/src/tests/issues.rs
+++ b/src/tests/issues.rs
@@ -2,8 +2,9 @@
 //! See https://github.com/remi-dupre/opening-hours-rs/issues
 
 use opening_hours_syntax::error::Error;
+use opening_hours_syntax::rules::RuleKind;
 
-use crate::{datetime, OpeningHours};
+use crate::{datetime, DateTimeRange, OpeningHours};
 
 /// https://github.com/remi-dupre/opening-hours-rs/issues/23
 #[test]
@@ -33,3 +34,51 @@ fn gh45_infinite_loop() -> Result<(), Error> {
     assert!(oh.next_change(start).is_ok());
     Ok(())
 }
+
+/// https://github.com/remi-dupre/opening-hours-rs/issues/52
+//
+//     November 2024
+// Su Mo Tu We Th Fr Sa
+//                 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
+#[test]
+fn gh52_no_interval_after_last_midnight() -> Result<(), Error> {
+    let oh = OpeningHours::parse("Mo-Su 00:00-06:00, 23:00-00:00")?;
+
+    let mut intervals = oh
+        .iter_range(datetime!("2024-11-11 01:00"), datetime!("2024-11-12 01:00"))
+        .unwrap();
+
+    assert_eq!(
+        intervals.next(),
+        Some(DateTimeRange {
+            range: datetime!("2024-11-11 01:00")..datetime!("2024-11-11 06:00"),
+            kind: RuleKind::Open,
+            comments: Default::default()
+        })
+    );
+
+    assert_eq!(
+        intervals.next(),
+        Some(DateTimeRange {
+            range: datetime!("2024-11-11 06:00")..datetime!("2024-11-11 23:00"),
+            kind: RuleKind::Closed,
+            comments: Default::default()
+        })
+    );
+
+    assert_eq!(
+        intervals.next(),
+        Some(DateTimeRange {
+            range: datetime!("2024-11-11 23:00")..datetime!("2024-11-12 01:00"),
+            kind: RuleKind::Open,
+            comments: Default::default()
+        })
+    );
+
+    assert_eq!(intervals.next(), None);
+    Ok(())
+}