skedule
A human-friendly alternative to cron.
Designed after GAE's schedule for Kotlin and/or Java 8+.
Features:
- TZ support;
- fluent / immutable / java.time.*-based API;
- zero dependencies.
Usage
<dependency>
<groupId>com.github.shyiko.skedule</groupId>
<artifactId>skedule</artifactId>
<version>0.4.0</version>
<!-- omit classifier below if you plan to use this library in koltin -->
<classifier>kalvanized</classifier>
</dependency>
(java)
// creating schedule from a string
Schedule.parse("every monday 09:00");
// programmatic construction
Schedule.at(LocalTime.of(9, 0)).every(DayOfWeek.MONDAY).toString().equals("every monday 09:00");
ZonedDateTime now = ZonedDateTime.parse("2007-12-03T10:15:30+02:00[Europe/Kiev]");
ZonedDateTime nxt = ZonedDateTime.parse("2007-12-10T09:00:00+02:00[Europe/Kiev]");
// determining "next" time
Schedule.parse("every monday 09:00").next(now).equals(nxt);
// iterating over (infinite) schedule
Schedule.parse("every monday 09:00").iterate(now)/*: Iterator<ZonedDateTime> */.next().equals(nxt);
Format
Schedule format is described in GAE cron.xml reference.
Here are some examples (taken from the official GAE documentation):
every 12 hours
every 5 minutes from 10:00 to 14:00
every day 00:00
every monday 09:00
2nd,third mon,wed,thu of march 17:00
1st monday of sep,oct,nov 17:00
1 of jan,april,july,oct 00:00
Additionally:
hour
can be used in place of1 hours
(same goes for1 minutes
)
(e.g.every hour
,every minute from 10:00 to 14:00
) (since 0.3.0)-
can be used to join consequent days & months (e.g.every mon-fri 09:00
,1-7 of jun-aug 00:00
) (since 0.3.0)
(example) Scheduling using ScheduledThreadPoolExecutor
import com.github.shyiko.skedule.Schedule;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
executor.setRemoveOnCancelPolicy(true);
ZonedDateTime now = ZonedDateTime.now();
executor.schedule(
() -> {
System.out.println("TASK 'every 5 minutes from 12:00 to 12:30' EXECUTED");
// re-schedule if needed
},
Schedule.from(LocalTime.NOON, LocalTime.of(12, 30)).every(5, ChronoUnit.MINUTES)
.next(now).toEpochSecond() - now.toEpochSecond(),
TimeUnit.SECONDS
);
executor.schedule(
() -> {
System.out.println("TASK 'every day 12:00' EXECUTED");
// re-schedule if needed
},
Schedule.at(LocalTime.NOON).everyDay()
.next(now).toEpochSecond() - now.toEpochSecond(),
TimeUnit.SECONDS
);
NOTE #1: Be careful with java.util.TimerTask::cancel() (if you choose to go with java.util.Timer).
NOTE #2: If you are thinking of using java.util.concurrent.DelayQueue - keep in mind that remove() operation is O(n).
NOTE #3: If you have a huge number of scheduled tasks >= 10th of thousands you might want to consider switching to Hierarchical Wheel Timer(s).
Development
git clone https://github.com/shyiko/skedule && cd skedule
./mvnw # shows how to build, test, etc. project
Legal
All code, unless specified otherwise, is licensed under the MIT license.
Copyright (c) 2017 Stanley Shyiko.