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/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 cadence = hourCadence(ir, +ir.pattern.minute);
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 (plan.rest.kind === "minuteFrequency" && ir.shapes.second === "wildcard" && ir.shapes.hour === "wildcard") {
446
- const minuteStep = stepSegment(ir.analyses.segments.minute);
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
- return secondsLead(ir) + ", " + render(ir, plan.rest, opts);
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 (strideFromSegments(fieldSegments(ir, "minute"), UNITS.minute, "") ?? countedPhrase(ir, "minute", "Minute", "Minuten")) + ", " + hours;
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
- return base + " " + duringHours(ir, plan.hours.times, sep);
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
- const step = values && arithmeticStep(values);
542
- return step || null;
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
- return ir.shapes.minute === "single" && hourCadence(ir, +ir.pattern.minute) !== null;
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 countedPhrase(ir, "minute", "Minute", "Minuten") + " jeder Stunde, " + window;
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 cadence = hourCadence(ir, +ir.pattern.minute);
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
- return clockRest && ir.shapes.minute === "single" ? hourCadence(ir, +ir.pattern.minute, opts) : null;
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
- const minute = plan.rest.times[0].minute;
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
- return secondsLeadClause(ir, opts) + ", " + render(ir, plan.rest, opts);
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
- phrase += " during the " + hourTimesFromPlan(ir, plan.hours.times, false, opts) + " hours";
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
- return lead + ", " + stepHours(segment, opts) + trailingQualifier(ir, opts);
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 cadence = hourCadence(ir, +ir.pattern.minute, opts);
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 cadence = hourCadence(ir, +plan.minute, opts);
425
- if (cadence !== null) {
426
- return cadence;
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 phrase = (
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
- (strideFromSegments(ir.analyses.segments.minute, "minute", "hour", opts) ?? listPastThe(
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
- )) + ", at " + hourSegmentTimes(ir, { minute: 0, second: null }, true, opts) + trailingQualifier(ir, opts)
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
- const step = values && arithmeticStep(values);
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;