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/fi.js CHANGED
@@ -263,7 +263,11 @@ function composeSecondsOverMinuteStep(ir, freq, opts) {
263
263
  }
264
264
  function composeHourCadence(ir, plan, opts) {
265
265
  const clockRest = plan.rest.kind === "clockTimes" || plan.rest.kind === "compactClockTimes";
266
- return clockRest && ir.shapes.minute === "single" ? hourCadence(ir, +ir.pattern.minute, opts) : null;
266
+ if (!clockRest || ir.shapes.minute !== "single") {
267
+ return null;
268
+ }
269
+ const minute = +ir.pattern.minute;
270
+ return hourCadence(ir, minute, opts) ?? hourRangeCadence(ir, minute, opts);
267
271
  }
268
272
  function renderComposeSeconds(ir, plan, opts) {
269
273
  const cadence = composeHourCadence(ir, plan, opts);
@@ -279,7 +283,9 @@ function renderComposeSeconds(ir, plan, opts) {
279
283
  if (isEveryOtherMinuteSeconds(ir, plan)) {
280
284
  return secondsLeadClause(ir, opts) + " joka toisena minuuttina";
281
285
  }
282
- return secondsLeadClause(ir, opts) + ", " + render(ir, plan.rest, opts);
286
+ const restOwnsLead = plan.rest.kind === "compactClockTimes" && ir.analyses.clockSecond;
287
+ const lead = restOwnsLead ? "" : secondsLeadClause(ir, opts) + ", ";
288
+ return lead + render(ir, plan.rest, opts);
283
289
  }
284
290
  function isEveryOtherMinuteSeconds(ir, plan) {
285
291
  if (plan.rest.kind !== "minuteFrequency" || ir.pattern.second !== "*" || ir.shapes.hour !== "wildcard") {
@@ -398,6 +404,10 @@ function hourSegmentTimesWithSeka(ir, minute, second, opts) {
398
404
  function renderMinuteFrequency(ir, plan, opts) {
399
405
  const seg = stepSegment(ir.analyses.segments.minute);
400
406
  if (plan.hours.kind === "during") {
407
+ const cadence = unevenHourCadence(ir, opts);
408
+ if (cadence !== null) {
409
+ return stepCycle60(seg, units.minute, opts) + ", " + cadence + trailingQualifier(ir, opts);
410
+ }
401
411
  if (minuteStepIsAnchored(seg)) {
402
412
  const bareHours = kloFromTimes(ir, plan.hours.times, opts);
403
413
  return hoursFirstMinutes(bareHours, ir, opts) + trailingQualifier(ir, opts);
@@ -423,8 +433,12 @@ function renderMinuteSpanInHour(ir, plan, opts) {
423
433
  ) + trailingQualifier(ir, opts);
424
434
  }
425
435
  function renderMinutesAcrossHours(ir, plan, opts) {
436
+ const cadence = unevenHourCadence(ir, opts);
426
437
  if (plan.form === "wildcard") {
427
- return "joka minuutti " + hourWindowsFromTimes(ir, plan.times, opts) + trailingQualifier(ir, opts);
438
+ return cadence ? "joka minuutti, " + cadence + trailingQualifier(ir, opts) : "joka minuutti " + hourWindowsFromTimes(ir, plan.times, opts) + trailingQualifier(ir, opts);
439
+ }
440
+ if (cadence !== null) {
441
+ return bareMinutes(ir, opts) + ", " + cadence + trailingQualifier(ir, opts);
428
442
  }
429
443
  if (hoursAreRangeIsolated(ir.analyses.segments.hour)) {
430
444
  return bareMinutes(ir, opts) + " " + hourSegmentTimesWithSeka(ir, 0, null, opts) + trailingQualifier(ir, opts);
@@ -434,12 +448,12 @@ function renderMinutesAcrossHours(ir, plan, opts) {
434
448
  }
435
449
  function renderMinuteSpanAcrossHourStep(ir, plan, opts) {
436
450
  const segment = stepSegment(ir.analyses.segments.hour);
451
+ const cadence = unevenHourCadence(ir, opts);
437
452
  if (plan.form === "wildcard") {
438
453
  return "joka minuutti " + everyNthHour(segment, opts) + trailingQualifier(ir, opts);
439
454
  }
440
- if (segment.startToken.indexOf("-") !== -1) {
441
- const hoursStr = kloList(segment.fires, opts);
442
- return hoursFirstMinutes(hoursStr, ir, opts) + trailingQualifier(ir, opts);
455
+ if (cadence !== null) {
456
+ return bareMinutes(ir, opts) + ", " + cadence + trailingQualifier(ir, opts);
443
457
  }
444
458
  return bareMinutes(ir, opts) + hourStepTail(segment, opts) + trailingQualifier(ir, opts);
445
459
  }
@@ -514,6 +528,10 @@ function renderHourRange(ir, plan, opts) {
514
528
  return hoursFirstMinutes(window, ir, opts) + trailingQualifier(ir, opts);
515
529
  }
516
530
  function renderHourStep(ir, plan, opts) {
531
+ const cadence = unevenHourCadence(ir, opts);
532
+ if (cadence !== null) {
533
+ return cadence + trailingQualifier(ir, opts);
534
+ }
517
535
  return stepHours(stepSegment(ir.analyses.segments.hour), opts) + trailingQualifier(ir, opts);
518
536
  }
519
537
  function boundedWindow(plan) {
@@ -528,7 +546,8 @@ function hourWindow(window, opts) {
528
546
  }
529
547
  function renderClockTimes(ir, plan, opts) {
530
548
  if (ir.shapes.minute === "single") {
531
- const cadence = hourCadence(ir, +ir.pattern.minute, opts);
549
+ const minute = +ir.pattern.minute;
550
+ const cadence = hourCadence(ir, minute, opts) ?? hourRangeCadence(ir, minute, opts);
532
551
  if (cadence !== null) {
533
552
  return cadence;
534
553
  }
@@ -544,9 +563,9 @@ function renderClockTimes(ir, plan, opts) {
544
563
  }
545
564
  function renderCompactClockTimes(ir, plan, opts) {
546
565
  if (plan.fold) {
547
- const cadence = hourCadence(ir, plan.minute, opts);
548
- if (cadence !== null) {
549
- return cadence;
566
+ const cadence2 = hourCadence(ir, plan.minute, opts) ?? hourRangeCadence(ir, plan.minute, opts);
567
+ if (cadence2 !== null) {
568
+ return cadence2;
550
569
  }
551
570
  }
552
571
  const hourSegs = ir.analyses.segments.hour;
@@ -565,8 +584,12 @@ function renderCompactClockTimes(ir, plan, opts) {
565
584
  if (plan.fold) {
566
585
  return leadingQualifier(ir, opts) + hourSegmentTimes(ir, plan.minute, ir.analyses.clockSecond, opts);
567
586
  }
568
- const hoursStr = hourSegmentTimes(ir, 0, null, opts);
569
- const phrase = hoursFirstMinutes(hoursStr, ir, opts) + trailingQualifier(ir, opts);
587
+ const cadence = unevenHourCadence(ir, opts);
588
+ const phrase = cadence ? bareMinutes(ir, opts) + ", " + cadence + trailingQualifier(ir, opts) : (
589
+ // A minute list over purely enumerated hours (step fires, all singles) —
590
+ // hours-first, drop "joka tunti".
591
+ hoursFirstMinutes(hourSegmentTimes(ir, 0, null, opts), ir, opts) + trailingQualifier(ir, opts)
592
+ );
570
593
  return ir.analyses.clockSecond ? secondsLeadClause(ir, opts) + ", " + phrase : phrase;
571
594
  }
572
595
  var renderers = {
@@ -659,6 +682,27 @@ function hourStrideCadence(stride, opts) {
659
682
  }
660
683
  return cadence + " " + kloRange({ hour: start, minute: 0 }, { hour: last, minute: 0 }, opts);
661
684
  }
685
+ function hourListStride(values) {
686
+ if (values.length < 2) {
687
+ return null;
688
+ }
689
+ const interval = values[1] - values[0];
690
+ if (interval < 2) {
691
+ return null;
692
+ }
693
+ for (let i = 2; i < values.length; i += 1) {
694
+ if (values[i] - values[i - 1] !== interval) {
695
+ return null;
696
+ }
697
+ }
698
+ if (values[0] !== 0 && values.length < 5) {
699
+ return null;
700
+ }
701
+ return { interval, last: values[values.length - 1], start: values[0] };
702
+ }
703
+ function offsetCleanStride(stride) {
704
+ return stride.start < stride.interval && 24 % stride.interval === 0;
705
+ }
662
706
  function hourStride(ir) {
663
707
  const segments = ir.analyses.segments.hour;
664
708
  if (!segments) {
@@ -666,12 +710,21 @@ function hourStride(ir) {
666
710
  }
667
711
  if (segments.length === 1 && segments[0].kind === "step") {
668
712
  const segment = segments[0];
713
+ if (segment.fires.length < 2) {
714
+ return null;
715
+ }
669
716
  const start = segment.startToken === "*" ? 0 : +segment.startToken.split("-")[0];
670
717
  return { interval: segment.interval, last: segment.fires[segment.fires.length - 1], start };
671
718
  }
672
719
  const values = singleValues(segments);
673
- const step = values && arithmeticStep(values);
674
- return step || null;
720
+ return values && hourListStride(values);
721
+ }
722
+ function unevenHourCadence(ir, opts) {
723
+ const stride = hourStride(ir);
724
+ if (!stride || offsetCleanStride(stride)) {
725
+ return null;
726
+ }
727
+ return hourStrideCadence(stride, opts);
675
728
  }
676
729
  function subMinuteSecond(ir) {
677
730
  return ir.pattern.second === "*" || ir.shapes.second === "step";
@@ -695,7 +748,7 @@ function hourCadence(ir, minute, opts) {
695
748
  return null;
696
749
  }
697
750
  const fires = (stride.last - stride.start) / stride.interval + 1;
698
- if (ir.pattern.second === "0" && fires <= maxClockTimes) {
751
+ if (ir.pattern.second === "0" && fires <= maxClockTimes && offsetCleanStride(stride)) {
699
752
  return null;
700
753
  }
701
754
  const segment = ir.analyses.segments.hour[0];
@@ -703,6 +756,9 @@ function hourCadence(ir, minute, opts) {
703
756
  if (confined) {
704
757
  return secondsLeadClause(ir, opts) + " minuutin ajan " + everyNthHour(segment, opts) + trailingQualifier(ir, opts);
705
758
  }
759
+ if (minute === 0 && ir.pattern.second === "0") {
760
+ return hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
761
+ }
706
762
  return hourCadenceLead(ir, minute, opts) + ", " + hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
707
763
  }
708
764
  function cleanHourStride(segment) {
@@ -712,6 +768,23 @@ function cleanHourStride(segment) {
712
768
  const start = segment.startToken === "*" ? 0 : +segment.startToken;
713
769
  return 24 % segment.interval === 0 && start < segment.interval;
714
770
  }
771
+ function hasHourWindow(ir) {
772
+ const segments = ir.analyses.segments.hour;
773
+ return !!segments && segments.some(function range(segment) {
774
+ return segment.kind === "range";
775
+ });
776
+ }
777
+ function hourRangeWindowTail(ir, opts) {
778
+ return ir.analyses.segments.hour.length === 1 ? hourSegmentTimes(ir, 0, null, opts) : hourSegmentTimesWithSeka(ir, 0, null, opts);
779
+ }
780
+ function hourRangeCadence(ir, minute, opts) {
781
+ if (minute !== 0 || !hasHourWindow(ir) || ir.pattern.second === "0") {
782
+ return null;
783
+ }
784
+ const tail = hourRangeWindowTail(ir, opts);
785
+ const joiner = subMinuteSecond(ir) ? " " : ", ";
786
+ return hourCadenceLead(ir, minute, opts) + joiner + tail + trailingQualifier(ir, opts);
787
+ }
715
788
  function kloList(hours, opts) {
716
789
  if (hours.length === 1) {
717
790
  return timeWord(hours[0], 0, null, opts);
@@ -728,12 +801,16 @@ function kloFromTimes(ir, times, opts) {
728
801
  }
729
802
  function hourWindowsFromTimes(ir, times, opts) {
730
803
  if (times.kind === "fires") {
731
- return "klo " + joinList(times.fires.map(function window(hour) {
732
- return hourWindowDigits(hour, opts);
733
- }));
804
+ return kloList(times.fires, opts);
805
+ }
806
+ const segments = ir.analyses.segments.hour;
807
+ if (!segments.some(function ranged(segment) {
808
+ return segment.kind === "range";
809
+ })) {
810
+ return kloList(hourSegmentFires(segments), opts);
734
811
  }
735
812
  const pieces = [];
736
- ir.analyses.segments.hour.forEach(function window(segment) {
813
+ segments.forEach(function window(segment) {
737
814
  if (segment.kind === "range") {
738
815
  pieces.push(rangeDigits(
739
816
  { hour: +segment.bounds[0], minute: 0 },
@@ -750,6 +827,17 @@ function hourWindowsFromTimes(ir, times, opts) {
750
827
  });
751
828
  return "klo " + joinList(pieces);
752
829
  }
830
+ function hourSegmentFires(segments) {
831
+ const hours = [];
832
+ segments.forEach(function each(segment) {
833
+ if (segment.kind === "step") {
834
+ hours.push(...segment.fires);
835
+ } else if (segment.kind === "single") {
836
+ hours.push(+segment.value);
837
+ }
838
+ });
839
+ return hours;
840
+ }
753
841
  function hourWindowDigits(hour, opts) {
754
842
  return rangeDigits({ hour, minute: 0 }, { hour, minute: 59 }, opts);
755
843
  }
package/dist/lang/zh.cjs CHANGED
@@ -249,8 +249,18 @@ function minuteHourClause(ir) {
249
249
  function renderMinutePast(ir) {
250
250
  return minuteHourClause(ir);
251
251
  }
252
+ function hourSegmentWords(segment) {
253
+ if (segment.kind === "range") {
254
+ return [hourWord(+segment.bounds[0]) + "\u81F3" + hourWord(+segment.bounds[1])];
255
+ }
256
+ if (segment.kind === "step") {
257
+ return segment.fires.map(hourWord);
258
+ }
259
+ return [hourWord(+segment.value)];
260
+ }
252
261
  function hourList(ir) {
253
- return joinAnd(hourFires(ir).map(hourWord));
262
+ const words = fieldSegments(ir, "hour").flatMap(hourSegmentWords);
263
+ return joinAnd(words);
254
264
  }
255
265
  function hourFrame(ir) {
256
266
  if (ir.shapes.hour === "range") {
@@ -263,9 +273,11 @@ function renderMinuteFrequency(ir, plan) {
263
273
  const minuteStep = stepSegment(ir, "minute");
264
274
  const base = stepClause(minuteStep, UNITS.minute, "\u5206", "\u6BCF\u5C0F\u65F6");
265
275
  const { hours } = plan;
266
- if (hours.kind === "step") {
267
- const hourStep = stepSegment(ir, "hour");
268
- return hourStep.startToken === "*" ? cadence(hourStep.interval, UNITS.hour) + base : "\u5728" + hourList(ir) + "\uFF0C" + base;
276
+ if (hours.kind === "step" || hours.kind === "during") {
277
+ const hourCad = hourCadencePhrase(ir);
278
+ if (hourCad !== null) {
279
+ return hourCad + (hourCad.indexOf("\u81F3") === -1 ? "" : "\uFF0C") + base;
280
+ }
269
281
  }
270
282
  if (hours.kind === "single" || hours.kind === "window" && hours.from === hours.to) {
271
283
  return "\u5728" + hourWord(hours.from) + "\u81F3" + hours.from + "\u70B9" + hours.last + "\u5206\u4E4B\u95F4\uFF0C" + base;
@@ -287,20 +299,21 @@ function renderMinuteSpanInHour(ir, plan) {
287
299
  }
288
300
  function renderMinutesAcrossHours(ir, plan) {
289
301
  const { form } = plan;
302
+ const hourCad = hourCadencePhrase(ir);
290
303
  if (form === "wildcard") {
291
- return "\u5728" + hourList(ir) + "\uFF0C\u6BCF\u5206\u949F";
304
+ return hourCad === null ? "\u5728" + hourList(ir) + "\uFF0C\u6BCF\u5206\u949F" : hourCad + "\uFF0C\u6BCF\u5206\u949F";
292
305
  }
293
- return hourList(ir) + "\uFF0C" + minuteHourClause(ir) + "\uFF0C\u6BCF\u5206\u949F";
306
+ return (hourCad ?? hourList(ir)) + "\uFF0C" + minuteHourClause(ir) + "\uFF0C\u6BCF\u5206\u949F";
294
307
  }
295
308
  function renderMinuteSpanAcrossHourStep(ir, plan) {
296
309
  const hourStep = stepSegment(ir, "hour");
297
310
  const { form } = plan;
298
311
  if (form === "list") {
299
- return renderMinutePast(ir) + "\uFF0C\u5728" + hourList(ir);
312
+ return hourCadencePhrase(ir) + "\uFF0C" + renderMinutePast(ir);
300
313
  }
301
314
  const minuteTail = form === "wildcard" ? "\u6BCF\u5206\u949F" : minuteHourClause(ir) + "\uFF0C\u6BCF\u5206\u949F";
302
315
  if (hourStep.startToken !== "*") {
303
- return form === "wildcard" ? "\u5728" + hourList(ir) + "\uFF0C" + minuteTail : hourList(ir) + "\uFF0C" + minuteTail;
316
+ return hourCadencePhrase(ir) + "\uFF0C" + minuteTail;
304
317
  }
305
318
  if (hourStep.interval === 2 && form === "wildcard") {
306
319
  return "\u5728\u5076\u6570\u5C0F\u65F6\uFF0C" + minuteTail;
@@ -309,26 +322,26 @@ function renderMinuteSpanAcrossHourStep(ir, plan) {
309
322
  return form === "wildcard" ? cad + "\u5185\uFF0C" + minuteTail : cad + "\uFF0C" + minuteTail;
310
323
  }
311
324
  function renderClockTimes(ir, plan, opts) {
312
- if (ir.shapes.minute === "single") {
313
- const cad = hourCadence(ir);
314
- if (cad !== null) {
315
- return cad;
316
- }
325
+ const cad = hourCadenceText(ir);
326
+ if (cad !== null) {
327
+ return cad;
317
328
  }
318
329
  const { times } = plan;
319
330
  return joinAnd(times.map((t) => clockTime(t.hour, t.minute, t.second, opts)));
320
331
  }
321
332
  function renderCompactClockTimes(ir, plan) {
322
- if (ir.shapes.minute === "single") {
323
- const cad = hourCadence(ir);
324
- if (cad !== null) {
325
- return cad;
326
- }
333
+ const cad = hourCadenceText(ir);
334
+ if (cad !== null) {
335
+ return cad;
327
336
  }
328
- const { minute } = plan;
337
+ const compact = plan;
329
338
  const secs = fieldSegments(ir, "second");
330
339
  const tail = secs.length && ir.pattern.second !== "0" ? "\uFF0C\u7B2C" + valueText(secs) + "\u79D2" : "";
331
- if (minute > 0) {
340
+ if (!compact.fold) {
341
+ const hourCad = hourCadencePhrase(ir);
342
+ return hourCad === null ? minuteHourClause(ir) + "\uFF0C\u5728" + hourList(ir) + tail : hourCad + "\uFF0C" + minuteHourClause(ir) + tail;
343
+ }
344
+ if (compact.minute > 0) {
332
345
  return minuteHourClause(ir) + "\uFF0C\u5728" + hourList(ir) + tail;
333
346
  }
334
347
  return hourList(ir) + tail;
@@ -347,54 +360,62 @@ function renderHourRange(ir, plan) {
347
360
  }
348
361
  function renderHourStep(ir) {
349
362
  const segment = stepSegment(ir, "hour");
350
- if (segment.startToken !== "*") {
351
- return hourList(ir);
352
- }
353
363
  if (segment.fires.length <= 2) {
354
364
  return joinAnd(segment.fires.map(hourWord));
355
365
  }
356
- return cadence(segment.interval, UNITS.hour);
366
+ return hourCadencePhrase(ir);
357
367
  }
358
368
  function hourStride(ir) {
359
369
  const segments = fieldSegments(ir, "hour");
360
370
  if (segments.length === 1 && segments[0].kind === "step") {
361
- const segment = segments[0];
362
- const start = segment.startToken === "*" ? 0 : +segment.startToken;
363
- if (start !== 0 || 24 % segment.interval !== 0) {
364
- return null;
365
- }
366
- return {
367
- interval: segment.interval,
368
- last: segment.fires[segment.fires.length - 1]
369
- };
371
+ const { fires, interval } = segments[0];
372
+ return { interval, start: fires[0], last: fires[fires.length - 1] };
370
373
  }
371
374
  const values = singleValues(segments);
372
- const step = values && arithmeticStep(values);
373
- if (!step || step.start !== 0 || 24 % step.interval !== 0) {
374
- return null;
375
- }
376
- return { interval: step.interval, last: step.last };
375
+ return values && arithmeticStep(values);
376
+ }
377
+ function hourCadencePhrase(ir) {
378
+ const stride = hourStride(ir);
379
+ return stride && renderStride({
380
+ ...stride,
381
+ cycle: 24,
382
+ unit: UNITS.hour,
383
+ mark: "\u70B9",
384
+ anchor: ""
385
+ });
377
386
  }
378
387
  function hourCadence(ir) {
379
388
  const stride = hourStride(ir);
380
389
  if (!stride) {
381
390
  return null;
382
391
  }
383
- const fires = stride.last / stride.interval + 1;
392
+ const fires = (stride.last - stride.start) / stride.interval + 1;
384
393
  if (ir.pattern.second === "0" && fires <= maxClockTimes) {
385
394
  return null;
386
395
  }
387
- const prefix = cadence(stride.interval, UNITS.hour);
396
+ const prefix = hourCadencePhrase(ir);
397
+ if (prefix.indexOf("\u81F3") !== -1) {
398
+ return null;
399
+ }
388
400
  const minute = +ir.pattern.minute;
389
401
  const subMinute = ir.pattern.second === "*" || ir.shapes.second === "step";
390
402
  if (minute === 0 && subMinute) {
391
- return stride.interval === 2 ? "\u5728\u5076\u6570\u5C0F\u65F60\u5206" + secondTail(ir) : null;
403
+ return stride.interval === 2 && stride.start === 0 ? "\u5728\u5076\u6570\u5C0F\u65F60\u5206" + secondTail(ir) : null;
392
404
  }
393
405
  if (minute === 0) {
394
406
  return prefix + "0\u5206" + secondTail(ir);
395
407
  }
396
408
  return ir.pattern.second === "0" ? prefix + minute + "\u5206" : prefix + minute + "\u5206" + secondTail(ir);
397
409
  }
410
+ function hourCadenceText(ir) {
411
+ if (ir.shapes.minute !== "single") {
412
+ return null;
413
+ }
414
+ if (+ir.pattern.minute === 0 && ir.pattern.second === "0") {
415
+ return hourCadencePhrase(ir);
416
+ }
417
+ return hourCadence(ir);
418
+ }
398
419
  function secondTail(ir) {
399
420
  const sec = secondClause(ir);
400
421
  return sec === "\u6BCF\u79D2" ? "\u7684\u6BCF\u4E00\u79D2" : "\u7684" + sec;
@@ -442,8 +463,8 @@ function minuteClause(ir) {
442
463
  }
443
464
  return valueList(fieldSegments(ir, "minute"), "\u5206");
444
465
  }
445
- function isHourCadence(ir) {
446
- return ir.shapes.hour === "step" && stepSegment(ir, "hour").startToken === "*";
466
+ function clockRestCarriesSecond(rest) {
467
+ return rest.kind === "clockTimes" && rest.times.some((time) => Boolean(time.second));
447
468
  }
448
469
  function composeSecondsOnHour(ir, plan, opts) {
449
470
  const sec = secondClause(ir);
@@ -459,17 +480,19 @@ function composeSecondsOnHour(ir, plan, opts) {
459
480
  return composeMinuteZeroClocks(ir, sec);
460
481
  }
461
482
  const restText = render(ir, rest, opts);
462
- if (rest.kind === "clockTimes" || rest.kind === "compactClockTimes") {
463
- if (isDaily(ir)) {
464
- return "\u6BCF\u5929" + restText + sec;
465
- }
483
+ const secTail = clockRestCarriesSecond(rest) ? "" : sec;
484
+ if (composedClock && isDaily(ir)) {
485
+ return "\u6BCF\u5929" + restText + secTail;
466
486
  }
467
487
  if (rest.kind === "singleMinute") {
468
488
  return restText + "\uFF0C" + sec;
469
489
  }
470
- return restText + sec;
490
+ return restText + secTail;
471
491
  }
472
492
  function composeMinuteZeroClocks(ir, sec) {
493
+ if (hasHourWindow(ir)) {
494
+ return isDaily(ir) ? "\u6BCF\u5929" + hourRangeWindow(ir, sec) : hourRangeWindow(ir, sec);
495
+ }
473
496
  const clocks = hourFires(ir).map(function clock(hour) {
474
497
  return hour === 12 ? "\u6B63\u5348" : hourWord(hour) + "0\u5206";
475
498
  });
@@ -478,11 +501,24 @@ function composeMinuteZeroClocks(ir, sec) {
478
501
  const core = joinAnd(clocks) + tail;
479
502
  return isDaily(ir) ? "\u6BCF\u5929" + core : core;
480
503
  }
504
+ function hasHourWindow(ir) {
505
+ return fieldSegments(ir, "hour").some(function range(segment) {
506
+ return segment.kind === "range";
507
+ });
508
+ }
509
+ function hourRangeWindow(ir, sec) {
510
+ const span = hourList(ir);
511
+ if (ir.pattern.second === "*" || ir.shapes.second === "step") {
512
+ return span + "0\u5206" + (sec === "\u6BCF\u79D2" ? "\u7684\u6BCF\u4E00\u79D2" : "\u7684" + sec);
513
+ }
514
+ return span + "\uFF0C" + sec;
515
+ }
481
516
  function composeSecondsCadence(ir) {
482
517
  const sec = secondClause(ir);
483
518
  const tail = minuteClause(ir) + sec;
484
- if (isHourCadence(ir)) {
485
- return cadence(stepSegment(ir, "hour").interval, UNITS.hour) + "\u7684" + tail;
519
+ const hourCad = hourCadencePhrase(ir);
520
+ if (hourCad !== null) {
521
+ return hourCad + (hourCad.indexOf("\u81F3") === -1 ? "\u7684" : "\uFF0C") + tail;
486
522
  }
487
523
  if (ir.shapes.hour === "single") {
488
524
  return hourWord(hourFires(ir)[0]) + "\u7684" + tail;
@@ -509,8 +545,9 @@ function composeSecondsListed(ir) {
509
545
  if (ir.shapes.hour === "wildcard") {
510
546
  return minutes + "\uFF0C" + sec;
511
547
  }
512
- if (isHourCadence(ir)) {
513
- return cadence(stepSegment(ir, "hour").interval, UNITS.hour) + "\uFF0C" + minutes + "\uFF0C" + sec;
548
+ const hourCad = hourCadencePhrase(ir);
549
+ if (hourCad !== null) {
550
+ return hourCad + "\uFF0C" + minutes + "\uFF0C" + sec;
514
551
  }
515
552
  return hourFrame(ir) + minutes + "\uFF0C" + sec;
516
553
  }
@@ -722,7 +759,7 @@ function composeWindow(ir, core) {
722
759
  return qualifier(ir) + core;
723
760
  }
724
761
  function hourCadenceApplies(ir) {
725
- return ir.shapes.minute === "single" && hourCadence(ir) !== null;
762
+ return hourCadenceText(ir) !== null;
726
763
  }
727
764
  function describe(ir, opts) {
728
765
  const { kind } = ir.plan;