cronToHuman function
Convert a cron expression to a human-readable string. Covers common patterns; falls through to the raw cron string for anything else.
The utc option exists for remote triggers which run on servers and always
use UTC cron strings -- that path translates UTC -> local for display.
Implementation
String cronToHuman(String cron, {bool utc = false}) {
final parts = cron.trim().split(RegExp(r'\s+'));
if (parts.length != 5) return cron;
final minute = parts[0];
final hour = parts[1];
final dayOfMonth = parts[2];
final month = parts[3];
final dayOfWeek = parts[4];
// Every N minutes: */N * * * *
final everyMinMatch = RegExp(r'^\*/(\d+)$').firstMatch(minute);
if (everyMinMatch != null &&
hour == '*' &&
dayOfMonth == '*' &&
month == '*' &&
dayOfWeek == '*') {
final n = int.parse(everyMinMatch.group(1)!);
return n == 1 ? 'Every minute' : 'Every $n minutes';
}
// Every hour: N * * * *
if (RegExp(r'^\d+$').hasMatch(minute) &&
hour == '*' &&
dayOfMonth == '*' &&
month == '*' &&
dayOfWeek == '*') {
final m = int.parse(minute);
if (m == 0) return 'Every hour';
return 'Every hour at :${m.toString().padLeft(2, '0')}';
}
// Every N hours: M */N * * *
final everyHourMatch = RegExp(r'^\*/(\d+)$').firstMatch(hour);
if (RegExp(r'^\d+$').hasMatch(minute) &&
everyHourMatch != null &&
dayOfMonth == '*' &&
month == '*' &&
dayOfWeek == '*') {
final n = int.parse(everyHourMatch.group(1)!);
final m = int.parse(minute);
final suffix = m == 0 ? '' : ' at :${m.toString().padLeft(2, '0')}';
return n == 1 ? 'Every hour$suffix' : 'Every $n hours$suffix';
}
// Remaining cases reference hour+minute.
if (!RegExp(r'^\d+$').hasMatch(minute) || !RegExp(r'^\d+$').hasMatch(hour)) {
return cron;
}
final m = int.parse(minute);
final h = int.parse(hour);
final fmtTime = utc ? _formatUtcTimeAsLocal : _formatLocalTime;
// Daily at specific time: M H * * *
if (dayOfMonth == '*' && month == '*' && dayOfWeek == '*') {
return 'Every day at ${fmtTime(m, h)}';
}
// Specific day of week: M H * * D
if (dayOfMonth == '*' &&
month == '*' &&
RegExp(r'^\d$').hasMatch(dayOfWeek)) {
final dayIndex = int.parse(dayOfWeek) % 7;
String? dayName;
if (utc) {
final ref = DateTime.now().toUtc();
final daysToAdd = (dayIndex - (ref.weekday % 7) + 7) % 7;
final target = ref.add(Duration(days: daysToAdd));
final local = DateTime.utc(
target.year,
target.month,
target.day,
h,
m,
).toLocal();
dayName = _dayNames[local.weekday % 7];
} else {
dayName = _dayNames[dayIndex];
}
return 'Every $dayName at ${fmtTime(m, h)}';
}
// Weekdays: M H * * 1-5
if (dayOfMonth == '*' && month == '*' && dayOfWeek == '1-5') {
return 'Weekdays at ${fmtTime(m, h)}';
}
return cron;
}