cronli5 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/cronli5.min.js +2 -2
- package/dist/cronli5.cjs +117 -20
- package/dist/cronli5.js +117 -20
- package/dist/lang/de.cjs +94 -19
- package/dist/lang/de.js +94 -19
- package/dist/lang/en.cjs +117 -20
- package/dist/lang/en.js +117 -20
- package/dist/lang/es.cjs +89 -14
- package/dist/lang/es.js +89 -14
- package/dist/lang/fi.cjs +107 -19
- package/dist/lang/fi.js +107 -19
- package/dist/lang/zh.cjs +90 -53
- package/dist/lang/zh.js +90 -53
- package/package.json +2 -2
- package/src/lang/de/index.ts +238 -51
- package/src/lang/en/index.ts +280 -46
- package/src/lang/es/index.ts +222 -31
- package/src/lang/fi/index.ts +245 -39
- package/src/lang/zh/index.ts +209 -94
package/dist/cronli5.js
CHANGED
|
@@ -946,7 +946,17 @@ function renderSecondsWithinMinute(ir, plan, opts) {
|
|
|
946
946
|
}
|
|
947
947
|
function composeHourCadence(ir, plan, opts) {
|
|
948
948
|
const clockRest = plan.rest.kind === "clockTimes" || plan.rest.kind === "compactClockTimes";
|
|
949
|
-
|
|
949
|
+
if (!clockRest || ir.shapes.minute !== "single") {
|
|
950
|
+
return null;
|
|
951
|
+
}
|
|
952
|
+
const minute = +ir.pattern.minute;
|
|
953
|
+
return hourCadence(ir, minute, opts) ?? hourRangeCadence(ir, minute, opts);
|
|
954
|
+
}
|
|
955
|
+
function clockTimesConfinement(ir, rest, opts) {
|
|
956
|
+
if (+rest.times[0].minute === 0 && ir.shapes.minute === "single") {
|
|
957
|
+
return secondsLeadClause(ir, opts) + " for one minute at " + durationHours(ir, rest, opts);
|
|
958
|
+
}
|
|
959
|
+
return secondsLeadClause(ir, opts) + " of " + clockTimesOf(ir, rest, opts);
|
|
950
960
|
}
|
|
951
961
|
function renderComposeSeconds(ir, plan, opts) {
|
|
952
962
|
const cadence = composeHourCadence(ir, plan, opts);
|
|
@@ -954,16 +964,14 @@ function renderComposeSeconds(ir, plan, opts) {
|
|
|
954
964
|
return cadence;
|
|
955
965
|
}
|
|
956
966
|
if (plan.rest.kind === "clockTimes" && (ir.shapes.second === "wildcard" || ir.shapes.second === "step")) {
|
|
957
|
-
|
|
958
|
-
if (+minute === 0) {
|
|
959
|
-
return secondsLeadClause(ir, opts) + " for one minute at " + durationHours(ir, plan.rest, opts);
|
|
960
|
-
}
|
|
961
|
-
return secondsLeadClause(ir, opts) + " of " + clockTimesOf(ir, plan.rest, opts);
|
|
967
|
+
return clockTimesConfinement(ir, plan.rest, opts);
|
|
962
968
|
}
|
|
963
969
|
if (ir.shapes.second === "wildcard" && plan.rest.kind === "minuteFrequency" && plan.rest.hours.kind === "none" && ir.pattern.minute === "*/2") {
|
|
964
970
|
return "every second of every other minute" + trailingQualifier(ir, opts);
|
|
965
971
|
}
|
|
966
|
-
|
|
972
|
+
const restOwnsLead = plan.rest.kind === "compactClockTimes" && ir.analyses.clockSecond;
|
|
973
|
+
const lead = restOwnsLead ? "" : secondsLeadClause(ir, opts) + ", ";
|
|
974
|
+
return lead + render(ir, plan.rest, opts);
|
|
967
975
|
}
|
|
968
976
|
function durationHours(ir, plan, opts) {
|
|
969
977
|
const hours = plan.times.map(function clock(time) {
|
|
@@ -1046,7 +1054,8 @@ function renderMinuteFrequency(ir, plan, opts) {
|
|
|
1046
1054
|
opts
|
|
1047
1055
|
);
|
|
1048
1056
|
if (plan.hours.kind === "during") {
|
|
1049
|
-
|
|
1057
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
1058
|
+
phrase += cadence ? ", " + cadence : " during the " + hourTimesFromPlan(ir, plan.hours.times, false, opts) + " hours";
|
|
1050
1059
|
} else if (plan.hours.kind === "window") {
|
|
1051
1060
|
phrase += " " + hourWindow(plan.hours, opts);
|
|
1052
1061
|
} else if (plan.hours.kind === "step") {
|
|
@@ -1061,10 +1070,13 @@ function renderMinuteSpanInHour(ir, plan, opts) {
|
|
|
1061
1070
|
return "every minute from " + getTime({ hour: plan.hour, minute: plan.span[0] }, opts) + through(opts) + getTime({ hour: plan.hour, minute: plan.span[1] }, opts) + trailingQualifier(ir, opts);
|
|
1062
1071
|
}
|
|
1063
1072
|
function renderMinutesAcrossHours(ir, plan, opts) {
|
|
1073
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
1064
1074
|
if (plan.form === "wildcard") {
|
|
1075
|
+
if (cadence !== null) {
|
|
1076
|
+
return "every minute, " + cadence + trailingQualifier(ir, opts);
|
|
1077
|
+
}
|
|
1065
1078
|
return "every minute during the " + hourTimesFromPlan(ir, plan.times, false, opts) + " hours" + trailingQualifier(ir, opts);
|
|
1066
1079
|
}
|
|
1067
|
-
const times = hourTimesFromPlan(ir, plan.times, true, opts);
|
|
1068
1080
|
const lead = plan.form === "range" ? minuteRangeLead(ir.pattern.minute, opts) : (
|
|
1069
1081
|
// The 'list' form is a minute list, which has segments; an offset/uneven
|
|
1070
1082
|
// step enumerated to that list reads as a stride.
|
|
@@ -1075,6 +1087,10 @@ function renderMinutesAcrossHours(ir, plan, opts) {
|
|
|
1075
1087
|
opts
|
|
1076
1088
|
)
|
|
1077
1089
|
);
|
|
1090
|
+
if (cadence !== null) {
|
|
1091
|
+
return lead + ", " + cadence + trailingQualifier(ir, opts);
|
|
1092
|
+
}
|
|
1093
|
+
const times = hourTimesFromPlan(ir, plan.times, true, opts);
|
|
1078
1094
|
return lead + ", at " + times + trailingQualifier(ir, opts);
|
|
1079
1095
|
}
|
|
1080
1096
|
var stepOrdinals = {
|
|
@@ -1101,7 +1117,8 @@ function renderMinuteSpanAcrossHourStep(ir, plan, opts) {
|
|
|
1101
1117
|
"hour",
|
|
1102
1118
|
opts
|
|
1103
1119
|
) : minuteRangeLead(ir.pattern.minute, opts);
|
|
1104
|
-
|
|
1120
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
1121
|
+
return lead + ", " + (cadence ?? stepHours(segment, opts)) + trailingQualifier(ir, opts);
|
|
1105
1122
|
}
|
|
1106
1123
|
function minuteRangeLead(minuteField, opts) {
|
|
1107
1124
|
const bounds = minuteField.split("-");
|
|
@@ -1138,6 +1155,10 @@ function rangeMinuteLead(ir, opts) {
|
|
|
1138
1155
|
);
|
|
1139
1156
|
}
|
|
1140
1157
|
function renderHourStep(ir, plan, opts) {
|
|
1158
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
1159
|
+
if (cadence !== null) {
|
|
1160
|
+
return cadence + trailingQualifier(ir, opts);
|
|
1161
|
+
}
|
|
1141
1162
|
return stepHours(ir.analyses.segments.hour[0], opts) + trailingQualifier(ir, opts);
|
|
1142
1163
|
}
|
|
1143
1164
|
function boundedWindow(plan) {
|
|
@@ -1148,7 +1169,8 @@ function hourWindow(window, opts) {
|
|
|
1148
1169
|
}
|
|
1149
1170
|
function renderClockTimes(ir, plan, opts) {
|
|
1150
1171
|
if (ir.shapes.minute === "single") {
|
|
1151
|
-
const
|
|
1172
|
+
const minute = +ir.pattern.minute;
|
|
1173
|
+
const cadence = hourCadence(ir, minute, opts) ?? hourRangeCadence(ir, minute, opts);
|
|
1152
1174
|
if (cadence !== null) {
|
|
1153
1175
|
return cadence;
|
|
1154
1176
|
}
|
|
@@ -1166,9 +1188,9 @@ function renderClockTimes(ir, plan, opts) {
|
|
|
1166
1188
|
}
|
|
1167
1189
|
function renderCompactClockTimes(ir, plan, opts) {
|
|
1168
1190
|
if (plan.fold) {
|
|
1169
|
-
const
|
|
1170
|
-
if (
|
|
1171
|
-
return
|
|
1191
|
+
const cadence2 = hourCadence(ir, +plan.minute, opts) ?? hourRangeCadence(ir, +plan.minute, opts);
|
|
1192
|
+
if (cadence2 !== null) {
|
|
1193
|
+
return cadence2;
|
|
1172
1194
|
}
|
|
1173
1195
|
const hasRange = ir.analyses.segments.hour.some(function range(segment) {
|
|
1174
1196
|
return segment.kind === "range";
|
|
@@ -1179,16 +1201,18 @@ function renderCompactClockTimes(ir, plan, opts) {
|
|
|
1179
1201
|
const fold = { minute: plan.minute, second: ir.analyses.clockSecond };
|
|
1180
1202
|
return interpretDayQualifier(ir, opts) + "at " + hourSegmentTimes(ir, fold, true, opts);
|
|
1181
1203
|
}
|
|
1182
|
-
const
|
|
1204
|
+
const minuteLead = (
|
|
1183
1205
|
// The non-fold branch is a minute list, which has segments. An
|
|
1184
1206
|
// offset/uneven step enumerated to that list reads as a stride.
|
|
1185
|
-
|
|
1207
|
+
strideFromSegments(ir.analyses.segments.minute, "minute", "hour", opts) ?? listPastThe(
|
|
1186
1208
|
segmentWords(ir.analyses.segments.minute, opts),
|
|
1187
1209
|
"minute",
|
|
1188
1210
|
"hour",
|
|
1189
1211
|
opts
|
|
1190
|
-
)
|
|
1212
|
+
)
|
|
1191
1213
|
);
|
|
1214
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
1215
|
+
const phrase = cadence ? minuteLead + ", " + cadence + trailingQualifier(ir, opts) : minuteLead + ", at " + hourSegmentTimes(ir, { minute: 0, second: null }, true, opts) + trailingQualifier(ir, opts);
|
|
1192
1216
|
return ir.analyses.clockSecond ? secondsLeadClause(ir, opts) + ", " + phrase : phrase;
|
|
1193
1217
|
}
|
|
1194
1218
|
function foldedHourWindows(ir, plan, opts) {
|
|
@@ -1306,16 +1330,46 @@ function hourStrideCadence(stride, opts) {
|
|
|
1306
1330
|
}
|
|
1307
1331
|
return cadence + " from " + getTime({ hour: start, minute: 0 }, opts) + through(opts) + getTime({ hour: last, minute: 0 }, opts);
|
|
1308
1332
|
}
|
|
1333
|
+
function offsetCleanStride(stride) {
|
|
1334
|
+
return stride.start < stride.interval && 24 % stride.interval === 0;
|
|
1335
|
+
}
|
|
1336
|
+
function unevenHourCadence(ir, opts) {
|
|
1337
|
+
const stride = hourStride(ir);
|
|
1338
|
+
if (!stride || offsetCleanStride(stride)) {
|
|
1339
|
+
return null;
|
|
1340
|
+
}
|
|
1341
|
+
return hourStrideCadence(stride, opts);
|
|
1342
|
+
}
|
|
1343
|
+
function hourListStride(values) {
|
|
1344
|
+
if (values.length < 2) {
|
|
1345
|
+
return null;
|
|
1346
|
+
}
|
|
1347
|
+
const interval = values[1] - values[0];
|
|
1348
|
+
if (interval < 2) {
|
|
1349
|
+
return null;
|
|
1350
|
+
}
|
|
1351
|
+
for (let i = 2; i < values.length; i += 1) {
|
|
1352
|
+
if (values[i] - values[i - 1] !== interval) {
|
|
1353
|
+
return null;
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
if (values[0] !== 0 && values.length < 5) {
|
|
1357
|
+
return null;
|
|
1358
|
+
}
|
|
1359
|
+
return { interval, last: values[values.length - 1], start: values[0] };
|
|
1360
|
+
}
|
|
1309
1361
|
function hourStride(ir) {
|
|
1310
1362
|
const segments = ir.analyses.segments.hour;
|
|
1311
1363
|
if (segments.length === 1 && segments[0].kind === "step") {
|
|
1312
1364
|
const segment = segments[0];
|
|
1365
|
+
if (segment.fires.length < 2) {
|
|
1366
|
+
return null;
|
|
1367
|
+
}
|
|
1313
1368
|
const start = segment.startToken === "*" ? 0 : +segment.startToken.split("-")[0];
|
|
1314
1369
|
return { interval: segment.interval, last: segment.fires[segment.fires.length - 1], start };
|
|
1315
1370
|
}
|
|
1316
1371
|
const values = singleValues(segments);
|
|
1317
|
-
|
|
1318
|
-
return step || null;
|
|
1372
|
+
return values && hourListStride(values);
|
|
1319
1373
|
}
|
|
1320
1374
|
function subMinuteSecond(ir) {
|
|
1321
1375
|
return ir.pattern.second === "*" || ir.shapes.second === "step";
|
|
@@ -1339,13 +1393,16 @@ function hourCadence(ir, minute, opts) {
|
|
|
1339
1393
|
return null;
|
|
1340
1394
|
}
|
|
1341
1395
|
const fires = (stride.last - stride.start) / stride.interval + 1;
|
|
1342
|
-
if (ir.pattern.second === "0" && fires <= maxClockTimes) {
|
|
1396
|
+
if (ir.pattern.second === "0" && fires <= maxClockTimes && offsetCleanStride(stride)) {
|
|
1343
1397
|
return null;
|
|
1344
1398
|
}
|
|
1345
1399
|
const confinement = minute === 0 && subMinuteSecond(ir) && cleanStrideSegment(ir);
|
|
1346
1400
|
if (confinement) {
|
|
1347
1401
|
return secondsClause(ir, "minute", opts) + " for one minute " + everyNthHour(confinement, opts) + trailingQualifier(ir, opts);
|
|
1348
1402
|
}
|
|
1403
|
+
if (minute === 0 && ir.pattern.second === "0") {
|
|
1404
|
+
return hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
|
|
1405
|
+
}
|
|
1349
1406
|
return hourCadenceLead(ir, minute, opts) + ", " + hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
|
|
1350
1407
|
}
|
|
1351
1408
|
function cleanStrideSegment(ir) {
|
|
@@ -1356,6 +1413,46 @@ function cleanStrideSegment(ir) {
|
|
|
1356
1413
|
}
|
|
1357
1414
|
return segment;
|
|
1358
1415
|
}
|
|
1416
|
+
function hasHourWindow(ir) {
|
|
1417
|
+
return ir.analyses.segments.hour.some(function range(segment) {
|
|
1418
|
+
return segment.kind === "range";
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1421
|
+
function hourRangeWindowTail(ir, opts) {
|
|
1422
|
+
const windows = [];
|
|
1423
|
+
const singles = [];
|
|
1424
|
+
ir.analyses.segments.hour.forEach(function classify(segment) {
|
|
1425
|
+
if (segment.kind === "range") {
|
|
1426
|
+
windows.push("from " + getTime(
|
|
1427
|
+
{ hour: +segment.bounds[0], minute: 0 },
|
|
1428
|
+
opts
|
|
1429
|
+
) + through(opts) + getTime({ hour: +segment.bounds[1], minute: 0 }, opts));
|
|
1430
|
+
} else if (segment.kind === "step") {
|
|
1431
|
+
singles.push(...segment.fires);
|
|
1432
|
+
} else {
|
|
1433
|
+
singles.push(+segment.value);
|
|
1434
|
+
}
|
|
1435
|
+
});
|
|
1436
|
+
let phrase = "every hour " + joinList(windows, opts);
|
|
1437
|
+
if (singles.length) {
|
|
1438
|
+
phrase += " and at " + joinList(singles.map(function time(hour) {
|
|
1439
|
+
return getTime({ hour, minute: 0 }, opts);
|
|
1440
|
+
}), opts);
|
|
1441
|
+
}
|
|
1442
|
+
return phrase;
|
|
1443
|
+
}
|
|
1444
|
+
function hourRangeCadence(ir, minute, opts) {
|
|
1445
|
+
if (minute !== 0 || !hasHourWindow(ir)) {
|
|
1446
|
+
return null;
|
|
1447
|
+
}
|
|
1448
|
+
if (ir.pattern.second === "0") {
|
|
1449
|
+
return null;
|
|
1450
|
+
}
|
|
1451
|
+
if (subMinuteSecond(ir)) {
|
|
1452
|
+
return secondsClause(ir, "minute", opts) + " for one minute during the " + hourSegmentTimes(ir, { minute: 0, second: null }, false, opts) + " hours" + trailingQualifier(ir, opts);
|
|
1453
|
+
}
|
|
1454
|
+
return hourCadenceLead(ir, minute, opts) + ", " + hourRangeWindowTail(ir, opts) + trailingQualifier(ir, opts);
|
|
1455
|
+
}
|
|
1359
1456
|
function seriesNumber(values, opts) {
|
|
1360
1457
|
const anyBig = values.some(function big(v) {
|
|
1361
1458
|
return +v > 10;
|
package/dist/lang/de.cjs
CHANGED
|
@@ -458,9 +458,17 @@ function renderMinuteSpanInHour(ir, plan, opts) {
|
|
|
458
458
|
const sep = opts.style.sep;
|
|
459
459
|
return "jede Minute von " + spanTime(plan.hour, plan.span[0], sep) + " bis " + spanTime(plan.hour, plan.span[1], sep) + " Uhr";
|
|
460
460
|
}
|
|
461
|
+
function isEveryOtherMinuteSeconds(ir, plan) {
|
|
462
|
+
if (plan.rest.kind !== "minuteFrequency" || ir.shapes.second !== "wildcard" || ir.shapes.hour !== "wildcard") {
|
|
463
|
+
return false;
|
|
464
|
+
}
|
|
465
|
+
const minuteStep = stepSegment(ir.analyses.segments.minute);
|
|
466
|
+
return minuteStep.startToken === "*" && minuteStep.interval === 2;
|
|
467
|
+
}
|
|
461
468
|
function renderComposeSeconds(ir, plan, opts) {
|
|
462
469
|
if ((plan.rest.kind === "clockTimes" || plan.rest.kind === "compactClockTimes") && ir.shapes.minute === "single") {
|
|
463
|
-
const
|
|
470
|
+
const minute = +ir.pattern.minute;
|
|
471
|
+
const cadence = hourCadence(ir, minute) ?? hourRangeCadence(ir, minute);
|
|
464
472
|
if (cadence !== null) {
|
|
465
473
|
return cadence;
|
|
466
474
|
}
|
|
@@ -468,13 +476,12 @@ function renderComposeSeconds(ir, plan, opts) {
|
|
|
468
476
|
if (composeMinuteZero(ir, plan)) {
|
|
469
477
|
return secondsLead(ir) + " " + clockMinuteGenitive(plan.rest.times, opts.style.sep);
|
|
470
478
|
}
|
|
471
|
-
if (
|
|
472
|
-
|
|
473
|
-
if (minuteStep.startToken === "*" && minuteStep.interval === 2) {
|
|
474
|
-
return secondsLead(ir) + " jeder zweiten Minute";
|
|
475
|
-
}
|
|
479
|
+
if (isEveryOtherMinuteSeconds(ir, plan)) {
|
|
480
|
+
return secondsLead(ir) + " jeder zweiten Minute";
|
|
476
481
|
}
|
|
477
|
-
|
|
482
|
+
const restOwnsLead = plan.rest.kind === "compactClockTimes" && ir.analyses.clockSecond;
|
|
483
|
+
const lead = restOwnsLead ? "" : secondsLead(ir) + ", ";
|
|
484
|
+
return lead + render(ir, plan.rest, opts);
|
|
478
485
|
}
|
|
479
486
|
function composeMinuteZero(ir, plan) {
|
|
480
487
|
return plan.rest.kind === "clockTimes" && plan.rest.times.every((time) => +time.minute === 0);
|
|
@@ -487,31 +494,37 @@ function clockMinuteGenitive(times, sep) {
|
|
|
487
494
|
}
|
|
488
495
|
function renderMinutesAcrossHours(ir, plan, opts) {
|
|
489
496
|
const sep = opts.style.sep;
|
|
497
|
+
const cadence = unevenHourCadence(ir);
|
|
490
498
|
if (plan.form === "wildcard") {
|
|
491
|
-
return "jede Minute " + duringHours(ir, plan.times, sep);
|
|
499
|
+
return cadence ? "jede Minute, " + cadence : "jede Minute " + duringHours(ir, plan.times, sep);
|
|
500
|
+
}
|
|
501
|
+
const minuteLead = strideFromSegments(fieldSegments(ir, "minute"), UNITS.minute, "") ?? countedPhrase(ir, "minute", "Minute", "Minuten");
|
|
502
|
+
if (cadence !== null) {
|
|
503
|
+
return minuteLead + ", " + cadence;
|
|
492
504
|
}
|
|
493
505
|
const hours = plan.times.kind === "fires" ? atHours(plan.times.fires) : joinList(hourSegmentParts(ir, 0, 0, sep));
|
|
494
|
-
return
|
|
506
|
+
return minuteLead + ", " + hours;
|
|
495
507
|
}
|
|
496
508
|
function renderMinuteSpanAcrossHourStep(ir, plan) {
|
|
509
|
+
const cadence = unevenHourCadence(ir);
|
|
497
510
|
if (plan.form === "wildcard") {
|
|
498
511
|
return "jede Minute " + everyNthHour(stepSegment(ir.analyses.segments.hour));
|
|
499
512
|
}
|
|
500
513
|
const segment = stepSegment(ir.analyses.segments.hour);
|
|
501
|
-
const hours = confinedHourStride(segment) ? everyNthHour(segment) : atHours(segment.fires);
|
|
514
|
+
const hours = cadence ?? (confinedHourStride(segment) ? everyNthHour(segment) : atHours(segment.fires));
|
|
502
515
|
return (strideFromSegments(fieldSegments(ir, "minute"), UNITS.minute, "") ?? countedPhrase(ir, "minute", "Minute", "Minuten")) + ", " + hours;
|
|
503
516
|
}
|
|
504
517
|
function renderCompactClockTimes(ir, plan, opts) {
|
|
505
518
|
const sep = opts.style.sep;
|
|
506
519
|
if (plan.fold) {
|
|
507
|
-
const cadence = hourCadence(ir, plan.minute);
|
|
520
|
+
const cadence = hourCadence(ir, plan.minute) ?? hourRangeCadence(ir, plan.minute);
|
|
508
521
|
if (cadence !== null) {
|
|
509
522
|
return cadence;
|
|
510
523
|
}
|
|
511
524
|
const hourly = fieldSegments(ir, "hour").some((segment) => segment.kind === "range");
|
|
512
525
|
return (hourly ? "st\xFCndlich " : "t\xE4glich ") + joinList(hourSegmentParts(ir, plan.minute, ir.analyses.clockSecond, sep));
|
|
513
526
|
}
|
|
514
|
-
const hours = fieldSegments(ir, "hour").some((segment) => segment.kind === "range") ? joinList(hourSegmentParts(ir, 0, 0, sep)) : atHours(hourFires(ir));
|
|
527
|
+
const hours = unevenHourCadence(ir) ?? (fieldSegments(ir, "hour").some((segment) => segment.kind === "range") ? joinList(hourSegmentParts(ir, 0, 0, sep)) : atHours(hourFires(ir)));
|
|
515
528
|
const lead = ir.analyses.clockSecond ? countedPhrase(ir, "second", "Sekunde", "Sekunden") + ", " : "";
|
|
516
529
|
return lead + (strideFromSegments(fieldSegments(ir, "minute"), UNITS.minute, "") ?? countedPhrase(ir, "minute", "Minute", "Minuten")) + ", " + hours;
|
|
517
530
|
}
|
|
@@ -530,7 +543,8 @@ function renderMinuteFrequency(ir, plan, opts) {
|
|
|
530
543
|
return clean ? base + " " + window : base + ", " + window;
|
|
531
544
|
}
|
|
532
545
|
if (plan.hours.kind === "during") {
|
|
533
|
-
|
|
546
|
+
const cadence = unevenHourCadence(ir);
|
|
547
|
+
return cadence ? base + ", " + cadence : base + " " + duringHours(ir, plan.hours.times, sep);
|
|
534
548
|
}
|
|
535
549
|
if (plan.hours.kind === "step") {
|
|
536
550
|
return base + " " + everyNthHour(stepSegment(ir.analyses.segments.hour));
|
|
@@ -538,6 +552,10 @@ function renderMinuteFrequency(ir, plan, opts) {
|
|
|
538
552
|
return base;
|
|
539
553
|
}
|
|
540
554
|
function hourStepPhrase(ir) {
|
|
555
|
+
const cadence = unevenHourCadence(ir);
|
|
556
|
+
if (cadence !== null) {
|
|
557
|
+
return cadence;
|
|
558
|
+
}
|
|
541
559
|
const segment = stepSegment(ir.analyses.segments.hour);
|
|
542
560
|
return cleanStep(segment, 24) ? everyN(segment.interval, UNITS.hour) : atHours(segment.fires);
|
|
543
561
|
}
|
|
@@ -553,6 +571,27 @@ function hourStrideCadence(stride) {
|
|
|
553
571
|
}
|
|
554
572
|
return cadence + " von " + start + " bis " + last + " Uhr";
|
|
555
573
|
}
|
|
574
|
+
function hourListStride(values) {
|
|
575
|
+
if (values.length < 2) {
|
|
576
|
+
return null;
|
|
577
|
+
}
|
|
578
|
+
const interval = values[1] - values[0];
|
|
579
|
+
if (interval < 2) {
|
|
580
|
+
return null;
|
|
581
|
+
}
|
|
582
|
+
for (let i = 2; i < values.length; i += 1) {
|
|
583
|
+
if (values[i] - values[i - 1] !== interval) {
|
|
584
|
+
return null;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
if (values[0] !== 0 && values.length < 5) {
|
|
588
|
+
return null;
|
|
589
|
+
}
|
|
590
|
+
return { interval, last: values[values.length - 1], start: values[0] };
|
|
591
|
+
}
|
|
592
|
+
function offsetCleanStride(stride) {
|
|
593
|
+
return stride.start < stride.interval && 24 % stride.interval === 0;
|
|
594
|
+
}
|
|
556
595
|
function hourStride(ir) {
|
|
557
596
|
const segments = fieldSegments(ir, "hour");
|
|
558
597
|
if (!segments) {
|
|
@@ -560,12 +599,21 @@ function hourStride(ir) {
|
|
|
560
599
|
}
|
|
561
600
|
if (segments.length === 1 && segments[0].kind === "step") {
|
|
562
601
|
const segment = segments[0];
|
|
602
|
+
if (segment.fires.length < 2) {
|
|
603
|
+
return null;
|
|
604
|
+
}
|
|
563
605
|
const start = segment.startToken === "*" ? 0 : +segment.startToken.split("-")[0];
|
|
564
606
|
return { interval: segment.interval, last: segment.fires[segment.fires.length - 1], start };
|
|
565
607
|
}
|
|
566
608
|
const values = singleValues(segments);
|
|
567
|
-
|
|
568
|
-
|
|
609
|
+
return values && hourListStride(values);
|
|
610
|
+
}
|
|
611
|
+
function unevenHourCadence(ir) {
|
|
612
|
+
const stride = hourStride(ir);
|
|
613
|
+
if (!stride || offsetCleanStride(stride)) {
|
|
614
|
+
return null;
|
|
615
|
+
}
|
|
616
|
+
return hourStrideCadence(stride);
|
|
569
617
|
}
|
|
570
618
|
function subMinuteSecond(ir) {
|
|
571
619
|
return ir.pattern.second === "*" || ir.shapes.second === "step";
|
|
@@ -589,7 +637,7 @@ function hourCadence(ir, minute) {
|
|
|
589
637
|
return null;
|
|
590
638
|
}
|
|
591
639
|
const fires = (stride.last - stride.start) / stride.interval + 1;
|
|
592
|
-
if (ir.pattern.second === "0" && fires <= maxClockTimes) {
|
|
640
|
+
if (ir.pattern.second === "0" && fires <= maxClockTimes && offsetCleanStride(stride)) {
|
|
593
641
|
return null;
|
|
594
642
|
}
|
|
595
643
|
const segment = fieldSegments(ir, "hour")[0];
|
|
@@ -597,10 +645,32 @@ function hourCadence(ir, minute) {
|
|
|
597
645
|
if (confined) {
|
|
598
646
|
return secondsClause(ir, "jeder Minute") + " f\xFCr eine Minute " + everyNthHour(segment);
|
|
599
647
|
}
|
|
648
|
+
if (minute === 0 && ir.pattern.second === "0") {
|
|
649
|
+
return hourStrideCadence(stride);
|
|
650
|
+
}
|
|
600
651
|
return hourCadenceLead(ir, minute) + ", " + hourStrideCadence(stride);
|
|
601
652
|
}
|
|
602
653
|
function hourCadenceApplies(ir) {
|
|
603
|
-
|
|
654
|
+
if (ir.shapes.minute !== "single") {
|
|
655
|
+
return false;
|
|
656
|
+
}
|
|
657
|
+
const minute = +ir.pattern.minute;
|
|
658
|
+
return hourCadence(ir, minute) !== null || hourRangeCadence(ir, minute) !== null;
|
|
659
|
+
}
|
|
660
|
+
function hasHourWindow(ir) {
|
|
661
|
+
const segments = fieldSegments(ir, "hour");
|
|
662
|
+
return !!segments && segments.some(function range(segment) {
|
|
663
|
+
return segment.kind === "range";
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
function hourRangeCadence(ir, minute) {
|
|
667
|
+
if (minute !== 0 || !hasHourWindow(ir) || ir.pattern.second === "0") {
|
|
668
|
+
return null;
|
|
669
|
+
}
|
|
670
|
+
return hourCadenceLead(ir, minute) + ", " + hourRangeWindowTail(ir);
|
|
671
|
+
}
|
|
672
|
+
function hourRangeWindowTail(ir) {
|
|
673
|
+
return joinList(hourSegmentParts(ir, 0, 0, ":"));
|
|
604
674
|
}
|
|
605
675
|
function renderHourRange(ir, plan, opts) {
|
|
606
676
|
const window = hourWindow(
|
|
@@ -615,11 +685,16 @@ function renderHourRange(ir, plan, opts) {
|
|
|
615
685
|
if (plan.minuteForm === "lead" && ir.pattern.minute === "0") {
|
|
616
686
|
return "st\xFCndlich " + window;
|
|
617
687
|
}
|
|
618
|
-
return
|
|
688
|
+
return (strideFromSegments(
|
|
689
|
+
fieldSegments(ir, "minute"),
|
|
690
|
+
UNITS.minute,
|
|
691
|
+
"jeder Stunde"
|
|
692
|
+
) ?? countedPhrase(ir, "minute", "Minute", "Minuten") + " jeder Stunde") + ", " + window;
|
|
619
693
|
}
|
|
620
694
|
function renderClockTimes(ir, plan, opts) {
|
|
621
695
|
if (ir.shapes.minute === "single") {
|
|
622
|
-
const
|
|
696
|
+
const minute = +ir.pattern.minute;
|
|
697
|
+
const cadence = hourCadence(ir, minute) ?? hourRangeCadence(ir, minute);
|
|
623
698
|
if (cadence !== null) {
|
|
624
699
|
return cadence;
|
|
625
700
|
}
|