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/lang/de.js
CHANGED
|
@@ -432,9 +432,17 @@ function renderMinuteSpanInHour(ir, plan, opts) {
|
|
|
432
432
|
const sep = opts.style.sep;
|
|
433
433
|
return "jede Minute von " + spanTime(plan.hour, plan.span[0], sep) + " bis " + spanTime(plan.hour, plan.span[1], sep) + " Uhr";
|
|
434
434
|
}
|
|
435
|
+
function isEveryOtherMinuteSeconds(ir, plan) {
|
|
436
|
+
if (plan.rest.kind !== "minuteFrequency" || ir.shapes.second !== "wildcard" || ir.shapes.hour !== "wildcard") {
|
|
437
|
+
return false;
|
|
438
|
+
}
|
|
439
|
+
const minuteStep = stepSegment(ir.analyses.segments.minute);
|
|
440
|
+
return minuteStep.startToken === "*" && minuteStep.interval === 2;
|
|
441
|
+
}
|
|
435
442
|
function renderComposeSeconds(ir, plan, opts) {
|
|
436
443
|
if ((plan.rest.kind === "clockTimes" || plan.rest.kind === "compactClockTimes") && ir.shapes.minute === "single") {
|
|
437
|
-
const
|
|
444
|
+
const minute = +ir.pattern.minute;
|
|
445
|
+
const cadence = hourCadence(ir, minute) ?? hourRangeCadence(ir, minute);
|
|
438
446
|
if (cadence !== null) {
|
|
439
447
|
return cadence;
|
|
440
448
|
}
|
|
@@ -442,13 +450,12 @@ function renderComposeSeconds(ir, plan, opts) {
|
|
|
442
450
|
if (composeMinuteZero(ir, plan)) {
|
|
443
451
|
return secondsLead(ir) + " " + clockMinuteGenitive(plan.rest.times, opts.style.sep);
|
|
444
452
|
}
|
|
445
|
-
if (
|
|
446
|
-
|
|
447
|
-
if (minuteStep.startToken === "*" && minuteStep.interval === 2) {
|
|
448
|
-
return secondsLead(ir) + " jeder zweiten Minute";
|
|
449
|
-
}
|
|
453
|
+
if (isEveryOtherMinuteSeconds(ir, plan)) {
|
|
454
|
+
return secondsLead(ir) + " jeder zweiten Minute";
|
|
450
455
|
}
|
|
451
|
-
|
|
456
|
+
const restOwnsLead = plan.rest.kind === "compactClockTimes" && ir.analyses.clockSecond;
|
|
457
|
+
const lead = restOwnsLead ? "" : secondsLead(ir) + ", ";
|
|
458
|
+
return lead + render(ir, plan.rest, opts);
|
|
452
459
|
}
|
|
453
460
|
function composeMinuteZero(ir, plan) {
|
|
454
461
|
return plan.rest.kind === "clockTimes" && plan.rest.times.every((time) => +time.minute === 0);
|
|
@@ -461,31 +468,37 @@ function clockMinuteGenitive(times, sep) {
|
|
|
461
468
|
}
|
|
462
469
|
function renderMinutesAcrossHours(ir, plan, opts) {
|
|
463
470
|
const sep = opts.style.sep;
|
|
471
|
+
const cadence = unevenHourCadence(ir);
|
|
464
472
|
if (plan.form === "wildcard") {
|
|
465
|
-
return "jede Minute " + duringHours(ir, plan.times, sep);
|
|
473
|
+
return cadence ? "jede Minute, " + cadence : "jede Minute " + duringHours(ir, plan.times, sep);
|
|
474
|
+
}
|
|
475
|
+
const minuteLead = strideFromSegments(fieldSegments(ir, "minute"), UNITS.minute, "") ?? countedPhrase(ir, "minute", "Minute", "Minuten");
|
|
476
|
+
if (cadence !== null) {
|
|
477
|
+
return minuteLead + ", " + cadence;
|
|
466
478
|
}
|
|
467
479
|
const hours = plan.times.kind === "fires" ? atHours(plan.times.fires) : joinList(hourSegmentParts(ir, 0, 0, sep));
|
|
468
|
-
return
|
|
480
|
+
return minuteLead + ", " + hours;
|
|
469
481
|
}
|
|
470
482
|
function renderMinuteSpanAcrossHourStep(ir, plan) {
|
|
483
|
+
const cadence = unevenHourCadence(ir);
|
|
471
484
|
if (plan.form === "wildcard") {
|
|
472
485
|
return "jede Minute " + everyNthHour(stepSegment(ir.analyses.segments.hour));
|
|
473
486
|
}
|
|
474
487
|
const segment = stepSegment(ir.analyses.segments.hour);
|
|
475
|
-
const hours = confinedHourStride(segment) ? everyNthHour(segment) : atHours(segment.fires);
|
|
488
|
+
const hours = cadence ?? (confinedHourStride(segment) ? everyNthHour(segment) : atHours(segment.fires));
|
|
476
489
|
return (strideFromSegments(fieldSegments(ir, "minute"), UNITS.minute, "") ?? countedPhrase(ir, "minute", "Minute", "Minuten")) + ", " + hours;
|
|
477
490
|
}
|
|
478
491
|
function renderCompactClockTimes(ir, plan, opts) {
|
|
479
492
|
const sep = opts.style.sep;
|
|
480
493
|
if (plan.fold) {
|
|
481
|
-
const cadence = hourCadence(ir, plan.minute);
|
|
494
|
+
const cadence = hourCadence(ir, plan.minute) ?? hourRangeCadence(ir, plan.minute);
|
|
482
495
|
if (cadence !== null) {
|
|
483
496
|
return cadence;
|
|
484
497
|
}
|
|
485
498
|
const hourly = fieldSegments(ir, "hour").some((segment) => segment.kind === "range");
|
|
486
499
|
return (hourly ? "st\xFCndlich " : "t\xE4glich ") + joinList(hourSegmentParts(ir, plan.minute, ir.analyses.clockSecond, sep));
|
|
487
500
|
}
|
|
488
|
-
const hours = fieldSegments(ir, "hour").some((segment) => segment.kind === "range") ? joinList(hourSegmentParts(ir, 0, 0, sep)) : atHours(hourFires(ir));
|
|
501
|
+
const hours = unevenHourCadence(ir) ?? (fieldSegments(ir, "hour").some((segment) => segment.kind === "range") ? joinList(hourSegmentParts(ir, 0, 0, sep)) : atHours(hourFires(ir)));
|
|
489
502
|
const lead = ir.analyses.clockSecond ? countedPhrase(ir, "second", "Sekunde", "Sekunden") + ", " : "";
|
|
490
503
|
return lead + (strideFromSegments(fieldSegments(ir, "minute"), UNITS.minute, "") ?? countedPhrase(ir, "minute", "Minute", "Minuten")) + ", " + hours;
|
|
491
504
|
}
|
|
@@ -504,7 +517,8 @@ function renderMinuteFrequency(ir, plan, opts) {
|
|
|
504
517
|
return clean ? base + " " + window : base + ", " + window;
|
|
505
518
|
}
|
|
506
519
|
if (plan.hours.kind === "during") {
|
|
507
|
-
|
|
520
|
+
const cadence = unevenHourCadence(ir);
|
|
521
|
+
return cadence ? base + ", " + cadence : base + " " + duringHours(ir, plan.hours.times, sep);
|
|
508
522
|
}
|
|
509
523
|
if (plan.hours.kind === "step") {
|
|
510
524
|
return base + " " + everyNthHour(stepSegment(ir.analyses.segments.hour));
|
|
@@ -512,6 +526,10 @@ function renderMinuteFrequency(ir, plan, opts) {
|
|
|
512
526
|
return base;
|
|
513
527
|
}
|
|
514
528
|
function hourStepPhrase(ir) {
|
|
529
|
+
const cadence = unevenHourCadence(ir);
|
|
530
|
+
if (cadence !== null) {
|
|
531
|
+
return cadence;
|
|
532
|
+
}
|
|
515
533
|
const segment = stepSegment(ir.analyses.segments.hour);
|
|
516
534
|
return cleanStep(segment, 24) ? everyN(segment.interval, UNITS.hour) : atHours(segment.fires);
|
|
517
535
|
}
|
|
@@ -527,6 +545,27 @@ function hourStrideCadence(stride) {
|
|
|
527
545
|
}
|
|
528
546
|
return cadence + " von " + start + " bis " + last + " Uhr";
|
|
529
547
|
}
|
|
548
|
+
function hourListStride(values) {
|
|
549
|
+
if (values.length < 2) {
|
|
550
|
+
return null;
|
|
551
|
+
}
|
|
552
|
+
const interval = values[1] - values[0];
|
|
553
|
+
if (interval < 2) {
|
|
554
|
+
return null;
|
|
555
|
+
}
|
|
556
|
+
for (let i = 2; i < values.length; i += 1) {
|
|
557
|
+
if (values[i] - values[i - 1] !== interval) {
|
|
558
|
+
return null;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
if (values[0] !== 0 && values.length < 5) {
|
|
562
|
+
return null;
|
|
563
|
+
}
|
|
564
|
+
return { interval, last: values[values.length - 1], start: values[0] };
|
|
565
|
+
}
|
|
566
|
+
function offsetCleanStride(stride) {
|
|
567
|
+
return stride.start < stride.interval && 24 % stride.interval === 0;
|
|
568
|
+
}
|
|
530
569
|
function hourStride(ir) {
|
|
531
570
|
const segments = fieldSegments(ir, "hour");
|
|
532
571
|
if (!segments) {
|
|
@@ -534,12 +573,21 @@ function hourStride(ir) {
|
|
|
534
573
|
}
|
|
535
574
|
if (segments.length === 1 && segments[0].kind === "step") {
|
|
536
575
|
const segment = segments[0];
|
|
576
|
+
if (segment.fires.length < 2) {
|
|
577
|
+
return null;
|
|
578
|
+
}
|
|
537
579
|
const start = segment.startToken === "*" ? 0 : +segment.startToken.split("-")[0];
|
|
538
580
|
return { interval: segment.interval, last: segment.fires[segment.fires.length - 1], start };
|
|
539
581
|
}
|
|
540
582
|
const values = singleValues(segments);
|
|
541
|
-
|
|
542
|
-
|
|
583
|
+
return values && hourListStride(values);
|
|
584
|
+
}
|
|
585
|
+
function unevenHourCadence(ir) {
|
|
586
|
+
const stride = hourStride(ir);
|
|
587
|
+
if (!stride || offsetCleanStride(stride)) {
|
|
588
|
+
return null;
|
|
589
|
+
}
|
|
590
|
+
return hourStrideCadence(stride);
|
|
543
591
|
}
|
|
544
592
|
function subMinuteSecond(ir) {
|
|
545
593
|
return ir.pattern.second === "*" || ir.shapes.second === "step";
|
|
@@ -563,7 +611,7 @@ function hourCadence(ir, minute) {
|
|
|
563
611
|
return null;
|
|
564
612
|
}
|
|
565
613
|
const fires = (stride.last - stride.start) / stride.interval + 1;
|
|
566
|
-
if (ir.pattern.second === "0" && fires <= maxClockTimes) {
|
|
614
|
+
if (ir.pattern.second === "0" && fires <= maxClockTimes && offsetCleanStride(stride)) {
|
|
567
615
|
return null;
|
|
568
616
|
}
|
|
569
617
|
const segment = fieldSegments(ir, "hour")[0];
|
|
@@ -571,10 +619,32 @@ function hourCadence(ir, minute) {
|
|
|
571
619
|
if (confined) {
|
|
572
620
|
return secondsClause(ir, "jeder Minute") + " f\xFCr eine Minute " + everyNthHour(segment);
|
|
573
621
|
}
|
|
622
|
+
if (minute === 0 && ir.pattern.second === "0") {
|
|
623
|
+
return hourStrideCadence(stride);
|
|
624
|
+
}
|
|
574
625
|
return hourCadenceLead(ir, minute) + ", " + hourStrideCadence(stride);
|
|
575
626
|
}
|
|
576
627
|
function hourCadenceApplies(ir) {
|
|
577
|
-
|
|
628
|
+
if (ir.shapes.minute !== "single") {
|
|
629
|
+
return false;
|
|
630
|
+
}
|
|
631
|
+
const minute = +ir.pattern.minute;
|
|
632
|
+
return hourCadence(ir, minute) !== null || hourRangeCadence(ir, minute) !== null;
|
|
633
|
+
}
|
|
634
|
+
function hasHourWindow(ir) {
|
|
635
|
+
const segments = fieldSegments(ir, "hour");
|
|
636
|
+
return !!segments && segments.some(function range(segment) {
|
|
637
|
+
return segment.kind === "range";
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
function hourRangeCadence(ir, minute) {
|
|
641
|
+
if (minute !== 0 || !hasHourWindow(ir) || ir.pattern.second === "0") {
|
|
642
|
+
return null;
|
|
643
|
+
}
|
|
644
|
+
return hourCadenceLead(ir, minute) + ", " + hourRangeWindowTail(ir);
|
|
645
|
+
}
|
|
646
|
+
function hourRangeWindowTail(ir) {
|
|
647
|
+
return joinList(hourSegmentParts(ir, 0, 0, ":"));
|
|
578
648
|
}
|
|
579
649
|
function renderHourRange(ir, plan, opts) {
|
|
580
650
|
const window = hourWindow(
|
|
@@ -589,11 +659,16 @@ function renderHourRange(ir, plan, opts) {
|
|
|
589
659
|
if (plan.minuteForm === "lead" && ir.pattern.minute === "0") {
|
|
590
660
|
return "st\xFCndlich " + window;
|
|
591
661
|
}
|
|
592
|
-
return
|
|
662
|
+
return (strideFromSegments(
|
|
663
|
+
fieldSegments(ir, "minute"),
|
|
664
|
+
UNITS.minute,
|
|
665
|
+
"jeder Stunde"
|
|
666
|
+
) ?? countedPhrase(ir, "minute", "Minute", "Minuten") + " jeder Stunde") + ", " + window;
|
|
593
667
|
}
|
|
594
668
|
function renderClockTimes(ir, plan, opts) {
|
|
595
669
|
if (ir.shapes.minute === "single") {
|
|
596
|
-
const
|
|
670
|
+
const minute = +ir.pattern.minute;
|
|
671
|
+
const cadence = hourCadence(ir, minute) ?? hourRangeCadence(ir, minute);
|
|
597
672
|
if (cadence !== null) {
|
|
598
673
|
return cadence;
|
|
599
674
|
}
|
package/dist/lang/en.cjs
CHANGED
|
@@ -201,7 +201,17 @@ function renderSecondsWithinMinute(ir, plan, opts) {
|
|
|
201
201
|
}
|
|
202
202
|
function composeHourCadence(ir, plan, opts) {
|
|
203
203
|
const clockRest = plan.rest.kind === "clockTimes" || plan.rest.kind === "compactClockTimes";
|
|
204
|
-
|
|
204
|
+
if (!clockRest || ir.shapes.minute !== "single") {
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
const minute = +ir.pattern.minute;
|
|
208
|
+
return hourCadence(ir, minute, opts) ?? hourRangeCadence(ir, minute, opts);
|
|
209
|
+
}
|
|
210
|
+
function clockTimesConfinement(ir, rest, opts) {
|
|
211
|
+
if (+rest.times[0].minute === 0 && ir.shapes.minute === "single") {
|
|
212
|
+
return secondsLeadClause(ir, opts) + " for one minute at " + durationHours(ir, rest, opts);
|
|
213
|
+
}
|
|
214
|
+
return secondsLeadClause(ir, opts) + " of " + clockTimesOf(ir, rest, opts);
|
|
205
215
|
}
|
|
206
216
|
function renderComposeSeconds(ir, plan, opts) {
|
|
207
217
|
const cadence = composeHourCadence(ir, plan, opts);
|
|
@@ -209,16 +219,14 @@ function renderComposeSeconds(ir, plan, opts) {
|
|
|
209
219
|
return cadence;
|
|
210
220
|
}
|
|
211
221
|
if (plan.rest.kind === "clockTimes" && (ir.shapes.second === "wildcard" || ir.shapes.second === "step")) {
|
|
212
|
-
|
|
213
|
-
if (+minute === 0) {
|
|
214
|
-
return secondsLeadClause(ir, opts) + " for one minute at " + durationHours(ir, plan.rest, opts);
|
|
215
|
-
}
|
|
216
|
-
return secondsLeadClause(ir, opts) + " of " + clockTimesOf(ir, plan.rest, opts);
|
|
222
|
+
return clockTimesConfinement(ir, plan.rest, opts);
|
|
217
223
|
}
|
|
218
224
|
if (ir.shapes.second === "wildcard" && plan.rest.kind === "minuteFrequency" && plan.rest.hours.kind === "none" && ir.pattern.minute === "*/2") {
|
|
219
225
|
return "every second of every other minute" + trailingQualifier(ir, opts);
|
|
220
226
|
}
|
|
221
|
-
|
|
227
|
+
const restOwnsLead = plan.rest.kind === "compactClockTimes" && ir.analyses.clockSecond;
|
|
228
|
+
const lead = restOwnsLead ? "" : secondsLeadClause(ir, opts) + ", ";
|
|
229
|
+
return lead + render(ir, plan.rest, opts);
|
|
222
230
|
}
|
|
223
231
|
function durationHours(ir, plan, opts) {
|
|
224
232
|
const hours = plan.times.map(function clock(time) {
|
|
@@ -301,7 +309,8 @@ function renderMinuteFrequency(ir, plan, opts) {
|
|
|
301
309
|
opts
|
|
302
310
|
);
|
|
303
311
|
if (plan.hours.kind === "during") {
|
|
304
|
-
|
|
312
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
313
|
+
phrase += cadence ? ", " + cadence : " during the " + hourTimesFromPlan(ir, plan.hours.times, false, opts) + " hours";
|
|
305
314
|
} else if (plan.hours.kind === "window") {
|
|
306
315
|
phrase += " " + hourWindow(plan.hours, opts);
|
|
307
316
|
} else if (plan.hours.kind === "step") {
|
|
@@ -316,10 +325,13 @@ function renderMinuteSpanInHour(ir, plan, opts) {
|
|
|
316
325
|
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);
|
|
317
326
|
}
|
|
318
327
|
function renderMinutesAcrossHours(ir, plan, opts) {
|
|
328
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
319
329
|
if (plan.form === "wildcard") {
|
|
330
|
+
if (cadence !== null) {
|
|
331
|
+
return "every minute, " + cadence + trailingQualifier(ir, opts);
|
|
332
|
+
}
|
|
320
333
|
return "every minute during the " + hourTimesFromPlan(ir, plan.times, false, opts) + " hours" + trailingQualifier(ir, opts);
|
|
321
334
|
}
|
|
322
|
-
const times = hourTimesFromPlan(ir, plan.times, true, opts);
|
|
323
335
|
const lead = plan.form === "range" ? minuteRangeLead(ir.pattern.minute, opts) : (
|
|
324
336
|
// The 'list' form is a minute list, which has segments; an offset/uneven
|
|
325
337
|
// step enumerated to that list reads as a stride.
|
|
@@ -330,6 +342,10 @@ function renderMinutesAcrossHours(ir, plan, opts) {
|
|
|
330
342
|
opts
|
|
331
343
|
)
|
|
332
344
|
);
|
|
345
|
+
if (cadence !== null) {
|
|
346
|
+
return lead + ", " + cadence + trailingQualifier(ir, opts);
|
|
347
|
+
}
|
|
348
|
+
const times = hourTimesFromPlan(ir, plan.times, true, opts);
|
|
333
349
|
return lead + ", at " + times + trailingQualifier(ir, opts);
|
|
334
350
|
}
|
|
335
351
|
var stepOrdinals = {
|
|
@@ -356,7 +372,8 @@ function renderMinuteSpanAcrossHourStep(ir, plan, opts) {
|
|
|
356
372
|
"hour",
|
|
357
373
|
opts
|
|
358
374
|
) : minuteRangeLead(ir.pattern.minute, opts);
|
|
359
|
-
|
|
375
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
376
|
+
return lead + ", " + (cadence ?? stepHours(segment, opts)) + trailingQualifier(ir, opts);
|
|
360
377
|
}
|
|
361
378
|
function minuteRangeLead(minuteField, opts) {
|
|
362
379
|
const bounds = minuteField.split("-");
|
|
@@ -393,6 +410,10 @@ function rangeMinuteLead(ir, opts) {
|
|
|
393
410
|
);
|
|
394
411
|
}
|
|
395
412
|
function renderHourStep(ir, plan, opts) {
|
|
413
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
414
|
+
if (cadence !== null) {
|
|
415
|
+
return cadence + trailingQualifier(ir, opts);
|
|
416
|
+
}
|
|
396
417
|
return stepHours(ir.analyses.segments.hour[0], opts) + trailingQualifier(ir, opts);
|
|
397
418
|
}
|
|
398
419
|
function boundedWindow(plan) {
|
|
@@ -403,7 +424,8 @@ function hourWindow(window, opts) {
|
|
|
403
424
|
}
|
|
404
425
|
function renderClockTimes(ir, plan, opts) {
|
|
405
426
|
if (ir.shapes.minute === "single") {
|
|
406
|
-
const
|
|
427
|
+
const minute = +ir.pattern.minute;
|
|
428
|
+
const cadence = hourCadence(ir, minute, opts) ?? hourRangeCadence(ir, minute, opts);
|
|
407
429
|
if (cadence !== null) {
|
|
408
430
|
return cadence;
|
|
409
431
|
}
|
|
@@ -421,9 +443,9 @@ function renderClockTimes(ir, plan, opts) {
|
|
|
421
443
|
}
|
|
422
444
|
function renderCompactClockTimes(ir, plan, opts) {
|
|
423
445
|
if (plan.fold) {
|
|
424
|
-
const
|
|
425
|
-
if (
|
|
426
|
-
return
|
|
446
|
+
const cadence2 = hourCadence(ir, +plan.minute, opts) ?? hourRangeCadence(ir, +plan.minute, opts);
|
|
447
|
+
if (cadence2 !== null) {
|
|
448
|
+
return cadence2;
|
|
427
449
|
}
|
|
428
450
|
const hasRange = ir.analyses.segments.hour.some(function range(segment) {
|
|
429
451
|
return segment.kind === "range";
|
|
@@ -434,16 +456,18 @@ function renderCompactClockTimes(ir, plan, opts) {
|
|
|
434
456
|
const fold = { minute: plan.minute, second: ir.analyses.clockSecond };
|
|
435
457
|
return interpretDayQualifier(ir, opts) + "at " + hourSegmentTimes(ir, fold, true, opts);
|
|
436
458
|
}
|
|
437
|
-
const
|
|
459
|
+
const minuteLead = (
|
|
438
460
|
// The non-fold branch is a minute list, which has segments. An
|
|
439
461
|
// offset/uneven step enumerated to that list reads as a stride.
|
|
440
|
-
|
|
462
|
+
strideFromSegments(ir.analyses.segments.minute, "minute", "hour", opts) ?? listPastThe(
|
|
441
463
|
segmentWords(ir.analyses.segments.minute, opts),
|
|
442
464
|
"minute",
|
|
443
465
|
"hour",
|
|
444
466
|
opts
|
|
445
|
-
)
|
|
467
|
+
)
|
|
446
468
|
);
|
|
469
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
470
|
+
const phrase = cadence ? minuteLead + ", " + cadence + trailingQualifier(ir, opts) : minuteLead + ", at " + hourSegmentTimes(ir, { minute: 0, second: null }, true, opts) + trailingQualifier(ir, opts);
|
|
447
471
|
return ir.analyses.clockSecond ? secondsLeadClause(ir, opts) + ", " + phrase : phrase;
|
|
448
472
|
}
|
|
449
473
|
function foldedHourWindows(ir, plan, opts) {
|
|
@@ -561,16 +585,46 @@ function hourStrideCadence(stride, opts) {
|
|
|
561
585
|
}
|
|
562
586
|
return cadence + " from " + getTime({ hour: start, minute: 0 }, opts) + through(opts) + getTime({ hour: last, minute: 0 }, opts);
|
|
563
587
|
}
|
|
588
|
+
function offsetCleanStride(stride) {
|
|
589
|
+
return stride.start < stride.interval && 24 % stride.interval === 0;
|
|
590
|
+
}
|
|
591
|
+
function unevenHourCadence(ir, opts) {
|
|
592
|
+
const stride = hourStride(ir);
|
|
593
|
+
if (!stride || offsetCleanStride(stride)) {
|
|
594
|
+
return null;
|
|
595
|
+
}
|
|
596
|
+
return hourStrideCadence(stride, opts);
|
|
597
|
+
}
|
|
598
|
+
function hourListStride(values) {
|
|
599
|
+
if (values.length < 2) {
|
|
600
|
+
return null;
|
|
601
|
+
}
|
|
602
|
+
const interval = values[1] - values[0];
|
|
603
|
+
if (interval < 2) {
|
|
604
|
+
return null;
|
|
605
|
+
}
|
|
606
|
+
for (let i = 2; i < values.length; i += 1) {
|
|
607
|
+
if (values[i] - values[i - 1] !== interval) {
|
|
608
|
+
return null;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
if (values[0] !== 0 && values.length < 5) {
|
|
612
|
+
return null;
|
|
613
|
+
}
|
|
614
|
+
return { interval, last: values[values.length - 1], start: values[0] };
|
|
615
|
+
}
|
|
564
616
|
function hourStride(ir) {
|
|
565
617
|
const segments = ir.analyses.segments.hour;
|
|
566
618
|
if (segments.length === 1 && segments[0].kind === "step") {
|
|
567
619
|
const segment = segments[0];
|
|
620
|
+
if (segment.fires.length < 2) {
|
|
621
|
+
return null;
|
|
622
|
+
}
|
|
568
623
|
const start = segment.startToken === "*" ? 0 : +segment.startToken.split("-")[0];
|
|
569
624
|
return { interval: segment.interval, last: segment.fires[segment.fires.length - 1], start };
|
|
570
625
|
}
|
|
571
626
|
const values = singleValues(segments);
|
|
572
|
-
|
|
573
|
-
return step || null;
|
|
627
|
+
return values && hourListStride(values);
|
|
574
628
|
}
|
|
575
629
|
function subMinuteSecond(ir) {
|
|
576
630
|
return ir.pattern.second === "*" || ir.shapes.second === "step";
|
|
@@ -594,13 +648,16 @@ function hourCadence(ir, minute, opts) {
|
|
|
594
648
|
return null;
|
|
595
649
|
}
|
|
596
650
|
const fires = (stride.last - stride.start) / stride.interval + 1;
|
|
597
|
-
if (ir.pattern.second === "0" && fires <= maxClockTimes) {
|
|
651
|
+
if (ir.pattern.second === "0" && fires <= maxClockTimes && offsetCleanStride(stride)) {
|
|
598
652
|
return null;
|
|
599
653
|
}
|
|
600
654
|
const confinement = minute === 0 && subMinuteSecond(ir) && cleanStrideSegment(ir);
|
|
601
655
|
if (confinement) {
|
|
602
656
|
return secondsClause(ir, "minute", opts) + " for one minute " + everyNthHour(confinement, opts) + trailingQualifier(ir, opts);
|
|
603
657
|
}
|
|
658
|
+
if (minute === 0 && ir.pattern.second === "0") {
|
|
659
|
+
return hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
|
|
660
|
+
}
|
|
604
661
|
return hourCadenceLead(ir, minute, opts) + ", " + hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
|
|
605
662
|
}
|
|
606
663
|
function cleanStrideSegment(ir) {
|
|
@@ -611,6 +668,46 @@ function cleanStrideSegment(ir) {
|
|
|
611
668
|
}
|
|
612
669
|
return segment;
|
|
613
670
|
}
|
|
671
|
+
function hasHourWindow(ir) {
|
|
672
|
+
return ir.analyses.segments.hour.some(function range(segment) {
|
|
673
|
+
return segment.kind === "range";
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
function hourRangeWindowTail(ir, opts) {
|
|
677
|
+
const windows = [];
|
|
678
|
+
const singles = [];
|
|
679
|
+
ir.analyses.segments.hour.forEach(function classify(segment) {
|
|
680
|
+
if (segment.kind === "range") {
|
|
681
|
+
windows.push("from " + getTime(
|
|
682
|
+
{ hour: +segment.bounds[0], minute: 0 },
|
|
683
|
+
opts
|
|
684
|
+
) + through(opts) + getTime({ hour: +segment.bounds[1], minute: 0 }, opts));
|
|
685
|
+
} else if (segment.kind === "step") {
|
|
686
|
+
singles.push(...segment.fires);
|
|
687
|
+
} else {
|
|
688
|
+
singles.push(+segment.value);
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
let phrase = "every hour " + joinList(windows, opts);
|
|
692
|
+
if (singles.length) {
|
|
693
|
+
phrase += " and at " + joinList(singles.map(function time(hour) {
|
|
694
|
+
return getTime({ hour, minute: 0 }, opts);
|
|
695
|
+
}), opts);
|
|
696
|
+
}
|
|
697
|
+
return phrase;
|
|
698
|
+
}
|
|
699
|
+
function hourRangeCadence(ir, minute, opts) {
|
|
700
|
+
if (minute !== 0 || !hasHourWindow(ir)) {
|
|
701
|
+
return null;
|
|
702
|
+
}
|
|
703
|
+
if (ir.pattern.second === "0") {
|
|
704
|
+
return null;
|
|
705
|
+
}
|
|
706
|
+
if (subMinuteSecond(ir)) {
|
|
707
|
+
return secondsClause(ir, "minute", opts) + " for one minute during the " + hourSegmentTimes(ir, { minute: 0, second: null }, false, opts) + " hours" + trailingQualifier(ir, opts);
|
|
708
|
+
}
|
|
709
|
+
return hourCadenceLead(ir, minute, opts) + ", " + hourRangeWindowTail(ir, opts) + trailingQualifier(ir, opts);
|
|
710
|
+
}
|
|
614
711
|
function seriesNumber(values, opts) {
|
|
615
712
|
const anyBig = values.some(function big(v) {
|
|
616
713
|
return +v > 10;
|