dvCronToOnCalendar function
A five-field cron line as a systemd OnCalendar= expression.
Numbers, *, lists, ranges and steps. Names and @daily are refused
rather than guessed at. A line restricting both day of month and day of
week is refused too: cron fires when either matches and systemd only
when both do, so the same text would back up on different days.
Implementation
String dvCronToOnCalendar(String line) {
final List<String> fields = line.trim().split(RegExp(r'\s+'));
if (fields.length != 5) {
throw FormatException('"$line" is not a five-field cron line');
}
final _CronField minute = _CronField.parse(fields[0], 0, 59, 'minute');
final _CronField hour = _CronField.parse(fields[1], 0, 23, 'hour');
final _CronField dom = _CronField.parse(fields[2], 1, 31, 'day of month');
final _CronField month = _CronField.parse(fields[3], 1, 12, 'month');
final _CronField dow = _CronField.parse(fields[4], 0, 7, 'day of week');
if (!dom.any && !dow.any) {
throw FormatException(
'"$line" restricts both day of month and day of week; cron matches '
'either and a systemd timer would need both, so it is refused rather '
'than translated into a different schedule',
);
}
final StringBuffer out = StringBuffer();
if (!dow.any) {
final List<int> days = <int>{
for (final int d in dow.values) d == 0 ? 7 : d,
}.toList()..sort();
final List<String> parts = <String>[];
int i = 0;
while (i < days.length) {
int j = i;
while (j + 1 < days.length && days[j + 1] == days[j] + 1) {
j++;
}
String name(int d) => _weekdays[d % 7];
if (j - i >= 2) {
parts.add('${name(days[i])}..${name(days[j])}');
} else {
for (int k = i; k <= j; k++) {
parts.add(name(days[k]));
}
}
i = j + 1;
}
out.write('${parts.join(',')} ');
}
out.write('*-${month.render(1)}-${dom.render(1)} ');
out.write('${hour.render(0)}:${minute.render(0)}:00');
return out.toString();
}