11use crate :: config:: { Job , RunnerConfig , TimezoneConfig } ;
22use chrono:: { DateTime , Local , TimeZone , Utc } ;
3- use chrono_tz:: Tz ;
43use croner:: Cron ;
54
65/// Returns the next scheduled time for a job, or None if no future occurrence.
@@ -22,11 +21,6 @@ pub fn next_occurrence_from(
2221 }
2322}
2423
25- /// Pure function: calculates next occurrence for a cron schedule in a given timezone.
26- pub fn schedule_next_from ( schedule : & Cron , tz : Tz , now : DateTime < Utc > ) -> Option < DateTime < Utc > > {
27- find_next_from ( schedule, tz, now)
28- }
29-
3024fn find_next_from < Z : TimeZone > (
3125 schedule : & Cron ,
3226 tz : Z ,
@@ -67,7 +61,7 @@ mod tests {
6761 let schedule = parse_schedule ( "* * * * *" ) ;
6862 // 2025-01-15 10:30:00 UTC
6963 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 15 , 10 , 30 , 0 ) . unwrap ( ) ;
70- let next = schedule_next_from ( & schedule, UTC , now) . unwrap ( ) ;
64+ let next = find_next_from ( & schedule, UTC , now) . unwrap ( ) ;
7165 // Should be 10:31:00
7266 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 1 , 15 , 10 , 31 , 0 ) . unwrap( ) ) ;
7367 }
@@ -77,7 +71,7 @@ mod tests {
7771 let schedule = parse_schedule ( "*/5 * * * *" ) ;
7872 // 2025-01-15 10:32:00 UTC
7973 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 15 , 10 , 32 , 0 ) . unwrap ( ) ;
80- let next = schedule_next_from ( & schedule, UTC , now) . unwrap ( ) ;
74+ let next = find_next_from ( & schedule, UTC , now) . unwrap ( ) ;
8175 // Should be 10:35:00
8276 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 1 , 15 , 10 , 35 , 0 ) . unwrap( ) ) ;
8377 }
@@ -87,7 +81,7 @@ mod tests {
8781 let schedule = parse_schedule ( "0 8 * * *" ) ;
8882 // 2025-01-15 10:00:00 UTC (already past 8am)
8983 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 15 , 10 , 0 , 0 ) . unwrap ( ) ;
90- let next = schedule_next_from ( & schedule, UTC , now) . unwrap ( ) ;
84+ let next = find_next_from ( & schedule, UTC , now) . unwrap ( ) ;
9185 // Should be next day 8:00:00
9286 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 1 , 16 , 8 , 0 , 0 ) . unwrap( ) ) ;
9387 }
@@ -97,7 +91,7 @@ mod tests {
9791 let schedule = parse_schedule ( "0 8 * * *" ) ;
9892 // 2025-01-15 05:00:00 UTC (before 8am)
9993 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 15 , 5 , 0 , 0 ) . unwrap ( ) ;
100- let next = schedule_next_from ( & schedule, UTC , now) . unwrap ( ) ;
94+ let next = find_next_from ( & schedule, UTC , now) . unwrap ( ) ;
10195 // Should be same day 8:00:00
10296 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 1 , 15 , 8 , 0 , 0 ) . unwrap( ) ) ;
10397 }
@@ -111,7 +105,7 @@ mod tests {
111105 let schedule = parse_schedule ( "every 5 minutes" ) ;
112106 // 2025-01-15 10:32:00 UTC
113107 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 15 , 10 , 32 , 0 ) . unwrap ( ) ;
114- let next = schedule_next_from ( & schedule, UTC , now) . unwrap ( ) ;
108+ let next = find_next_from ( & schedule, UTC , now) . unwrap ( ) ;
115109 // Should be 10:35:00
116110 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 1 , 15 , 10 , 35 , 0 ) . unwrap( ) ) ;
117111 }
@@ -120,15 +114,15 @@ mod tests {
120114 fn english_every_minute ( ) {
121115 let schedule = parse_schedule ( "every minute" ) ;
122116 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 15 , 10 , 30 , 0 ) . unwrap ( ) ;
123- let next = schedule_next_from ( & schedule, UTC , now) . unwrap ( ) ;
117+ let next = find_next_from ( & schedule, UTC , now) . unwrap ( ) ;
124118 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 1 , 15 , 10 , 31 , 0 ) . unwrap( ) ) ;
125119 }
126120
127121 #[ test]
128122 fn english_every_hour ( ) {
129123 let schedule = parse_schedule ( "every hour" ) ;
130124 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 15 , 10 , 30 , 0 ) . unwrap ( ) ;
131- let next = schedule_next_from ( & schedule, UTC , now) . unwrap ( ) ;
125+ let next = find_next_from ( & schedule, UTC , now) . unwrap ( ) ;
132126 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 1 , 15 , 11 , 0 , 0 ) . unwrap( ) ) ;
133127 }
134128
@@ -137,7 +131,7 @@ mod tests {
137131 let schedule = parse_schedule ( "every day at 4:00 pm" ) ;
138132 // 2025-01-15 10:00:00 UTC (before 4pm)
139133 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 15 , 10 , 0 , 0 ) . unwrap ( ) ;
140- let next = schedule_next_from ( & schedule, UTC , now) . unwrap ( ) ;
134+ let next = find_next_from ( & schedule, UTC , now) . unwrap ( ) ;
141135 // Should be same day 16:00:00
142136 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 1 , 15 , 16 , 0 , 0 ) . unwrap( ) ) ;
143137 }
@@ -147,7 +141,7 @@ mod tests {
147141 let schedule = parse_schedule ( "every day at 4:00 pm" ) ;
148142 // 2025-01-15 18:00:00 UTC (after 4pm)
149143 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 15 , 18 , 0 , 0 ) . unwrap ( ) ;
150- let next = schedule_next_from ( & schedule, UTC , now) . unwrap ( ) ;
144+ let next = find_next_from ( & schedule, UTC , now) . unwrap ( ) ;
151145 // Should be next day 16:00:00
152146 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 1 , 16 , 16 , 0 , 0 ) . unwrap( ) ) ;
153147 }
@@ -156,15 +150,15 @@ mod tests {
156150 fn english_at_10am ( ) {
157151 let schedule = parse_schedule ( "at 10:00 am" ) ;
158152 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 15 , 8 , 0 , 0 ) . unwrap ( ) ;
159- let next = schedule_next_from ( & schedule, UTC , now) . unwrap ( ) ;
153+ let next = find_next_from ( & schedule, UTC , now) . unwrap ( ) ;
160154 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 1 , 15 , 10 , 0 , 0 ) . unwrap( ) ) ;
161155 }
162156
163157 #[ test]
164158 fn english_12am_is_midnight ( ) {
165159 let schedule = parse_schedule ( "every day at 12:00 am" ) ;
166160 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 15 , 10 , 0 , 0 ) . unwrap ( ) ;
167- let next = schedule_next_from ( & schedule, UTC , now) . unwrap ( ) ;
161+ let next = find_next_from ( & schedule, UTC , now) . unwrap ( ) ;
168162 // 12 am = midnight = 00:00, so next occurrence is next day
169163 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 1 , 16 , 0 , 0 , 0 ) . unwrap( ) ) ;
170164 }
@@ -173,7 +167,7 @@ mod tests {
173167 fn english_12pm_is_noon ( ) {
174168 let schedule = parse_schedule ( "every day at 12:00 pm" ) ;
175169 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 15 , 10 , 0 , 0 ) . unwrap ( ) ;
176- let next = schedule_next_from ( & schedule, UTC , now) . unwrap ( ) ;
170+ let next = find_next_from ( & schedule, UTC , now) . unwrap ( ) ;
177171 // 12 pm = noon = 12:00
178172 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 1 , 15 , 12 , 0 , 0 ) . unwrap( ) ) ;
179173 }
@@ -182,7 +176,7 @@ mod tests {
182176 fn english_24h_format ( ) {
183177 let schedule = parse_schedule ( "every day at 16:00" ) ;
184178 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 15 , 10 , 0 , 0 ) . unwrap ( ) ;
185- let next = schedule_next_from ( & schedule, UTC , now) . unwrap ( ) ;
179+ let next = find_next_from ( & schedule, UTC , now) . unwrap ( ) ;
186180 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 1 , 15 , 16 , 0 , 0 ) . unwrap( ) ) ;
187181 }
188182
@@ -215,7 +209,7 @@ mod tests {
215209 let schedule = parse_schedule ( "7pm every Thursday" ) ;
216210 // 2025-01-15 is Wednesday
217211 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 15 , 10 , 0 , 0 ) . unwrap ( ) ;
218- let next = schedule_next_from ( & schedule, UTC , now) . unwrap ( ) ;
212+ let next = find_next_from ( & schedule, UTC , now) . unwrap ( ) ;
219213 // Next Thursday is 2025-01-16 at 19:00
220214 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 1 , 16 , 19 , 0 , 0 ) . unwrap( ) ) ;
221215 }
@@ -225,7 +219,7 @@ mod tests {
225219 let schedule = parse_schedule ( "Sunday at 12:00" ) ;
226220 // 2025-01-15 is Wednesday
227221 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 15 , 10 , 0 , 0 ) . unwrap ( ) ;
228- let next = schedule_next_from ( & schedule, UTC , now) . unwrap ( ) ;
222+ let next = find_next_from ( & schedule, UTC , now) . unwrap ( ) ;
229223 // Next Sunday is 2025-01-19 at 12:00
230224 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 1 , 19 , 12 , 0 , 0 ) . unwrap( ) ) ;
231225 }
@@ -239,7 +233,7 @@ mod tests {
239233 let schedule = parse_schedule ( "0 8 * * *" ) ;
240234 // 2025-01-15 00:00:00 UTC = 2025-01-15 09:00:00 Tokyo (past 8am Tokyo)
241235 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 15 , 0 , 0 , 0 ) . unwrap ( ) ;
242- let next = schedule_next_from ( & schedule, Tokyo , now) . unwrap ( ) ;
236+ let next = find_next_from ( & schedule, Tokyo , now) . unwrap ( ) ;
243237 // Next 8am Tokyo = 2025-01-15 23:00:00 UTC (8am - 9h offset)
244238 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 1 , 15 , 23 , 0 , 0 ) . unwrap( ) ) ;
245239 }
@@ -249,7 +243,7 @@ mod tests {
249243 let schedule = parse_schedule ( "0 8 * * *" ) ;
250244 // 2025-01-14 20:00:00 UTC = 2025-01-15 05:00:00 Tokyo (before 8am Tokyo)
251245 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 14 , 20 , 0 , 0 ) . unwrap ( ) ;
252- let next = schedule_next_from ( & schedule, Tokyo , now) . unwrap ( ) ;
246+ let next = find_next_from ( & schedule, Tokyo , now) . unwrap ( ) ;
253247 // Same day 8am Tokyo = 2025-01-14 23:00:00 UTC
254248 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 1 , 14 , 23 , 0 , 0 ) . unwrap( ) ) ;
255249 }
@@ -259,7 +253,7 @@ mod tests {
259253 let schedule = parse_schedule ( "0 9 * * *" ) ;
260254 // 2025-01-15 10:00:00 UTC = 2025-01-15 05:00:00 New York (EST, UTC-5)
261255 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 15 , 10 , 0 , 0 ) . unwrap ( ) ;
262- let next = schedule_next_from ( & schedule, New_York , now) . unwrap ( ) ;
256+ let next = find_next_from ( & schedule, New_York , now) . unwrap ( ) ;
263257 // 9am New York = 14:00:00 UTC
264258 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 1 , 15 , 14 , 0 , 0 ) . unwrap( ) ) ;
265259 }
@@ -269,7 +263,7 @@ mod tests {
269263 let schedule = parse_schedule ( "0 0 * * *" ) ;
270264 // 2025-01-15 01:00:00 UTC = 2025-01-15 01:00:00 London (GMT, same as UTC in winter)
271265 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 15 , 1 , 0 , 0 ) . unwrap ( ) ;
272- let next = schedule_next_from ( & schedule, London , now) . unwrap ( ) ;
266+ let next = find_next_from ( & schedule, London , now) . unwrap ( ) ;
273267 // Next midnight London = 2025-01-16 00:00:00 UTC
274268 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 1 , 16 , 0 , 0 , 0 ) . unwrap( ) ) ;
275269 }
@@ -279,9 +273,9 @@ mod tests {
279273 let schedule = parse_schedule ( "0 12 * * *" ) ; // noon
280274 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 15 , 0 , 0 , 0 ) . unwrap ( ) ;
281275
282- let next_utc = schedule_next_from ( & schedule, UTC , now) . unwrap ( ) ;
283- let next_tokyo = schedule_next_from ( & schedule, Tokyo , now) . unwrap ( ) ;
284- let next_ny = schedule_next_from ( & schedule, New_York , now) . unwrap ( ) ;
276+ let next_utc = find_next_from ( & schedule, UTC , now) . unwrap ( ) ;
277+ let next_tokyo = find_next_from ( & schedule, Tokyo , now) . unwrap ( ) ;
278+ let next_ny = find_next_from ( & schedule, New_York , now) . unwrap ( ) ;
285279
286280 // Noon UTC = 12:00 UTC
287281 assert_eq ! ( next_utc, Utc . with_ymd_and_hms( 2025 , 1 , 15 , 12 , 0 , 0 ) . unwrap( ) ) ;
@@ -387,7 +381,7 @@ jobs:
387381 let schedule = parse_schedule ( "0 12 * * *" ) ;
388382 // Exactly at noon
389383 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 15 , 12 , 0 , 0 ) . unwrap ( ) ;
390- let next = schedule_next_from ( & schedule, UTC , now) . unwrap ( ) ;
384+ let next = find_next_from ( & schedule, UTC , now) . unwrap ( ) ;
391385 // Should return next day's noon (not the same time)
392386 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 1 , 16 , 12 , 0 , 0 ) . unwrap( ) ) ;
393387 }
@@ -396,15 +390,15 @@ jobs:
396390 fn year_boundary ( ) {
397391 let schedule = parse_schedule ( "0 0 1 1 *" ) ; // Jan 1st midnight
398392 let now = Utc . with_ymd_and_hms ( 2025 , 12 , 31 , 23 , 0 , 0 ) . unwrap ( ) ;
399- let next = schedule_next_from ( & schedule, UTC , now) . unwrap ( ) ;
393+ let next = find_next_from ( & schedule, UTC , now) . unwrap ( ) ;
400394 assert_eq ! ( next, Utc . with_ymd_and_hms( 2026 , 1 , 1 , 0 , 0 , 0 ) . unwrap( ) ) ;
401395 }
402396
403397 #[ test]
404398 fn month_boundary ( ) {
405399 let schedule = parse_schedule ( "0 0 1 * *" ) ; // 1st of every month
406400 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 31 , 12 , 0 , 0 ) . unwrap ( ) ;
407- let next = schedule_next_from ( & schedule, UTC , now) . unwrap ( ) ;
401+ let next = find_next_from ( & schedule, UTC , now) . unwrap ( ) ;
408402 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 2 , 1 , 0 , 0 , 0 ) . unwrap( ) ) ;
409403 }
410404
@@ -413,7 +407,7 @@ jobs:
413407 let schedule = parse_schedule ( "0 7 * * 0" ) ; // Sunday 7am
414408 // 2025-01-15 is Wednesday
415409 let now = Utc . with_ymd_and_hms ( 2025 , 1 , 15 , 10 , 0 , 0 ) . unwrap ( ) ;
416- let next = schedule_next_from ( & schedule, UTC , now) . unwrap ( ) ;
410+ let next = find_next_from ( & schedule, UTC , now) . unwrap ( ) ;
417411 // Next Sunday is 2025-01-19
418412 assert_eq ! ( next, Utc . with_ymd_and_hms( 2025 , 1 , 19 , 7 , 0 , 0 ) . unwrap( ) ) ;
419413 }
0 commit comments