cronli5 0.1.4 → 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 +53 -0
- package/cronli5.min.js +2 -2
- package/dist/cronli5.cjs +286 -45
- package/dist/cronli5.js +286 -45
- package/dist/lang/de.cjs +252 -13
- package/dist/lang/de.js +252 -13
- package/dist/lang/en.cjs +281 -38
- package/dist/lang/en.js +281 -38
- package/dist/lang/es.cjs +259 -29
- package/dist/lang/es.js +259 -29
- package/dist/lang/fi.cjs +285 -49
- package/dist/lang/fi.js +285 -49
- package/dist/lang/zh.cjs +225 -42
- package/dist/lang/zh.js +225 -42
- package/package.json +3 -2
- package/src/core/analyze.ts +7 -0
- package/src/core/ir.ts +1 -1
- package/src/core/util.ts +31 -1
- package/src/lang/de/index.ts +561 -30
- package/src/lang/en/index.ts +593 -59
- package/src/lang/es/index.ts +576 -52
- package/src/lang/fi/index.ts +633 -95
- package/src/lang/zh/index.ts +484 -77
- package/types/core/ir.d.ts +1 -1
- package/types/core/util.d.ts +6 -1
package/dist/lang/en.js
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
// src/core/util.ts
|
|
2
|
+
function arithmeticStep(values) {
|
|
3
|
+
if (values.length < 5) {
|
|
4
|
+
return null;
|
|
5
|
+
}
|
|
6
|
+
const interval = values[1] - values[0];
|
|
7
|
+
if (interval < 2) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
for (let i = 2; i < values.length; i += 1) {
|
|
11
|
+
if (values[i] - values[i - 1] !== interval) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return { start: values[0], interval, last: values[values.length - 1] };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// src/core/specs.ts
|
|
19
|
+
var maxClockTimes = 6;
|
|
20
|
+
|
|
1
21
|
// src/core/format.ts
|
|
2
22
|
function pad(n) {
|
|
3
23
|
n = "" + n;
|
|
@@ -153,18 +173,34 @@ function renderSecondsWithinMinute(ir, plan, opts) {
|
|
|
153
173
|
}
|
|
154
174
|
return secondsLeadClause(ir, opts) + ", " + minuteWord + " " + minuteUnit + " past the hour, every hour" + trailingQualifier(ir, opts);
|
|
155
175
|
}
|
|
176
|
+
function composeHourCadence(ir, plan, opts) {
|
|
177
|
+
const clockRest = plan.rest.kind === "clockTimes" || plan.rest.kind === "compactClockTimes";
|
|
178
|
+
if (!clockRest || ir.shapes.minute !== "single") {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
const minute = +ir.pattern.minute;
|
|
182
|
+
return hourCadence(ir, minute, opts) ?? hourRangeCadence(ir, minute, opts);
|
|
183
|
+
}
|
|
184
|
+
function clockTimesConfinement(ir, rest, opts) {
|
|
185
|
+
if (+rest.times[0].minute === 0 && ir.shapes.minute === "single") {
|
|
186
|
+
return secondsLeadClause(ir, opts) + " for one minute at " + durationHours(ir, rest, opts);
|
|
187
|
+
}
|
|
188
|
+
return secondsLeadClause(ir, opts) + " of " + clockTimesOf(ir, rest, opts);
|
|
189
|
+
}
|
|
156
190
|
function renderComposeSeconds(ir, plan, opts) {
|
|
191
|
+
const cadence = composeHourCadence(ir, plan, opts);
|
|
192
|
+
if (cadence !== null) {
|
|
193
|
+
return cadence;
|
|
194
|
+
}
|
|
157
195
|
if (plan.rest.kind === "clockTimes" && (ir.shapes.second === "wildcard" || ir.shapes.second === "step")) {
|
|
158
|
-
|
|
159
|
-
if (+minute === 0) {
|
|
160
|
-
return secondsLeadClause(ir, opts) + " for one minute at " + durationHours(ir, plan.rest, opts);
|
|
161
|
-
}
|
|
162
|
-
return secondsLeadClause(ir, opts) + " of " + clockTimesOf(ir, plan.rest, opts);
|
|
196
|
+
return clockTimesConfinement(ir, plan.rest, opts);
|
|
163
197
|
}
|
|
164
198
|
if (ir.shapes.second === "wildcard" && plan.rest.kind === "minuteFrequency" && plan.rest.hours.kind === "none" && ir.pattern.minute === "*/2") {
|
|
165
199
|
return "every second of every other minute" + trailingQualifier(ir, opts);
|
|
166
200
|
}
|
|
167
|
-
|
|
201
|
+
const restOwnsLead = plan.rest.kind === "compactClockTimes" && ir.analyses.clockSecond;
|
|
202
|
+
const lead = restOwnsLead ? "" : secondsLeadClause(ir, opts) + ", ";
|
|
203
|
+
return lead + render(ir, plan.rest, opts);
|
|
168
204
|
}
|
|
169
205
|
function durationHours(ir, plan, opts) {
|
|
170
206
|
const hours = plan.times.map(function clock(time) {
|
|
@@ -186,6 +222,9 @@ function clockTimesOf(ir, plan, opts) {
|
|
|
186
222
|
return joinList(times, opts) + (trail && ", " + trail);
|
|
187
223
|
}
|
|
188
224
|
function secondsLeadClause(ir, opts) {
|
|
225
|
+
return secondsClause(ir, "minute", opts);
|
|
226
|
+
}
|
|
227
|
+
function secondsClause(ir, anchor, opts) {
|
|
189
228
|
const secondField = ir.pattern.second;
|
|
190
229
|
const shape = ir.shapes.second;
|
|
191
230
|
if (secondField === "*") {
|
|
@@ -195,22 +234,27 @@ function secondsLeadClause(ir, opts) {
|
|
|
195
234
|
return stepCycle60(
|
|
196
235
|
ir.analyses.segments.second[0],
|
|
197
236
|
"second",
|
|
198
|
-
|
|
237
|
+
anchor,
|
|
199
238
|
opts
|
|
200
239
|
);
|
|
201
240
|
}
|
|
202
241
|
if (shape === "range") {
|
|
203
242
|
const bounds = secondField.split("-");
|
|
204
243
|
const num = seriesNumber(bounds, opts);
|
|
205
|
-
return "every second from " + num(bounds[0]) + through(opts) + num(bounds[1]) + " past the
|
|
244
|
+
return "every second from " + num(bounds[0]) + through(opts) + num(bounds[1]) + " past the " + anchor;
|
|
206
245
|
}
|
|
207
246
|
if (shape === "single") {
|
|
208
|
-
return "at " + getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the
|
|
247
|
+
return "at " + getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the " + anchor;
|
|
209
248
|
}
|
|
210
|
-
return
|
|
249
|
+
return strideFromSegments(
|
|
250
|
+
ir.analyses.segments.second,
|
|
251
|
+
"second",
|
|
252
|
+
anchor,
|
|
253
|
+
opts
|
|
254
|
+
) ?? listPastThe(
|
|
211
255
|
segmentWords(ir.analyses.segments.second, opts),
|
|
212
256
|
"second",
|
|
213
|
-
|
|
257
|
+
anchor,
|
|
214
258
|
opts
|
|
215
259
|
);
|
|
216
260
|
}
|
|
@@ -225,12 +269,11 @@ function renderRangeOfMinutes(ir, plan, opts) {
|
|
|
225
269
|
return minuteRangeLead(ir.pattern.minute, opts) + trailingQualifier(ir, opts);
|
|
226
270
|
}
|
|
227
271
|
function renderMultipleMinutes(ir, plan, opts) {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
"hour",
|
|
272
|
+
const stride = strideFromSegments(ir.analyses.segments.minute, "minute", "hour", opts);
|
|
273
|
+
return (stride ?? listPastThe(segmentWords(
|
|
274
|
+
ir.analyses.segments.minute,
|
|
232
275
|
opts
|
|
233
|
-
) + trailingQualifier(ir, opts);
|
|
276
|
+
), "minute", "hour", opts)) + trailingQualifier(ir, opts);
|
|
234
277
|
}
|
|
235
278
|
function renderMinuteFrequency(ir, plan, opts) {
|
|
236
279
|
let phrase = stepCycle60(
|
|
@@ -240,7 +283,8 @@ function renderMinuteFrequency(ir, plan, opts) {
|
|
|
240
283
|
opts
|
|
241
284
|
);
|
|
242
285
|
if (plan.hours.kind === "during") {
|
|
243
|
-
|
|
286
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
287
|
+
phrase += cadence ? ", " + cadence : " during the " + hourTimesFromPlan(ir, plan.hours.times, false, opts) + " hours";
|
|
244
288
|
} else if (plan.hours.kind === "window") {
|
|
245
289
|
phrase += " " + hourWindow(plan.hours, opts);
|
|
246
290
|
} else if (plan.hours.kind === "step") {
|
|
@@ -255,19 +299,27 @@ function renderMinuteSpanInHour(ir, plan, opts) {
|
|
|
255
299
|
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);
|
|
256
300
|
}
|
|
257
301
|
function renderMinutesAcrossHours(ir, plan, opts) {
|
|
302
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
258
303
|
if (plan.form === "wildcard") {
|
|
304
|
+
if (cadence !== null) {
|
|
305
|
+
return "every minute, " + cadence + trailingQualifier(ir, opts);
|
|
306
|
+
}
|
|
259
307
|
return "every minute during the " + hourTimesFromPlan(ir, plan.times, false, opts) + " hours" + trailingQualifier(ir, opts);
|
|
260
308
|
}
|
|
261
|
-
const times = hourTimesFromPlan(ir, plan.times, true, opts);
|
|
262
309
|
const lead = plan.form === "range" ? minuteRangeLead(ir.pattern.minute, opts) : (
|
|
263
|
-
// The 'list' form is a minute list, which has segments
|
|
264
|
-
|
|
310
|
+
// The 'list' form is a minute list, which has segments; an offset/uneven
|
|
311
|
+
// step enumerated to that list reads as a stride.
|
|
312
|
+
strideFromSegments(ir.analyses.segments.minute, "minute", "hour", opts) ?? listPastThe(
|
|
265
313
|
segmentWords(ir.analyses.segments.minute, opts),
|
|
266
314
|
"minute",
|
|
267
315
|
"hour",
|
|
268
316
|
opts
|
|
269
317
|
)
|
|
270
318
|
);
|
|
319
|
+
if (cadence !== null) {
|
|
320
|
+
return lead + ", " + cadence + trailingQualifier(ir, opts);
|
|
321
|
+
}
|
|
322
|
+
const times = hourTimesFromPlan(ir, plan.times, true, opts);
|
|
271
323
|
return lead + ", at " + times + trailingQualifier(ir, opts);
|
|
272
324
|
}
|
|
273
325
|
var stepOrdinals = {
|
|
@@ -288,7 +340,14 @@ function renderMinuteSpanAcrossHourStep(ir, plan, opts) {
|
|
|
288
340
|
if (plan.form === "wildcard") {
|
|
289
341
|
return "every minute " + everyNthHour(segment, opts) + trailingQualifier(ir, opts);
|
|
290
342
|
}
|
|
291
|
-
|
|
343
|
+
const lead = plan.form === "list" ? strideFromSegments(ir.analyses.segments.minute, "minute", "hour", opts) ?? listPastThe(
|
|
344
|
+
segmentWords(ir.analyses.segments.minute, opts),
|
|
345
|
+
"minute",
|
|
346
|
+
"hour",
|
|
347
|
+
opts
|
|
348
|
+
) : minuteRangeLead(ir.pattern.minute, opts);
|
|
349
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
350
|
+
return lead + ", " + (cadence ?? stepHours(segment, opts)) + trailingQualifier(ir, opts);
|
|
292
351
|
}
|
|
293
352
|
function minuteRangeLead(minuteField, opts) {
|
|
294
353
|
const bounds = minuteField.split("-");
|
|
@@ -312,7 +371,12 @@ function rangeMinuteLead(ir, opts) {
|
|
|
312
371
|
if (ir.pattern.minute === "0") {
|
|
313
372
|
return "every hour";
|
|
314
373
|
}
|
|
315
|
-
return
|
|
374
|
+
return strideFromSegments(
|
|
375
|
+
ir.analyses.segments.minute,
|
|
376
|
+
"minute",
|
|
377
|
+
"hour",
|
|
378
|
+
opts
|
|
379
|
+
) ?? listPastThe(
|
|
316
380
|
segmentWords(ir.analyses.segments.minute, opts),
|
|
317
381
|
"minute",
|
|
318
382
|
"hour",
|
|
@@ -320,6 +384,10 @@ function rangeMinuteLead(ir, opts) {
|
|
|
320
384
|
);
|
|
321
385
|
}
|
|
322
386
|
function renderHourStep(ir, plan, opts) {
|
|
387
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
388
|
+
if (cadence !== null) {
|
|
389
|
+
return cadence + trailingQualifier(ir, opts);
|
|
390
|
+
}
|
|
323
391
|
return stepHours(ir.analyses.segments.hour[0], opts) + trailingQualifier(ir, opts);
|
|
324
392
|
}
|
|
325
393
|
function boundedWindow(plan) {
|
|
@@ -329,6 +397,13 @@ function hourWindow(window, opts) {
|
|
|
329
397
|
return "from " + getTime({ hour: window.from, minute: 0 }, opts) + through(opts) + getTime({ hour: window.to, minute: window.last }, opts);
|
|
330
398
|
}
|
|
331
399
|
function renderClockTimes(ir, plan, opts) {
|
|
400
|
+
if (ir.shapes.minute === "single") {
|
|
401
|
+
const minute = +ir.pattern.minute;
|
|
402
|
+
const cadence = hourCadence(ir, minute, opts) ?? hourRangeCadence(ir, minute, opts);
|
|
403
|
+
if (cadence !== null) {
|
|
404
|
+
return cadence;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
332
407
|
const plain = mixedTwelve(plan.times);
|
|
333
408
|
const times = plan.times.map(function clock(time) {
|
|
334
409
|
return getTime({
|
|
@@ -342,6 +417,10 @@ function renderClockTimes(ir, plan, opts) {
|
|
|
342
417
|
}
|
|
343
418
|
function renderCompactClockTimes(ir, plan, opts) {
|
|
344
419
|
if (plan.fold) {
|
|
420
|
+
const cadence2 = hourCadence(ir, +plan.minute, opts) ?? hourRangeCadence(ir, +plan.minute, opts);
|
|
421
|
+
if (cadence2 !== null) {
|
|
422
|
+
return cadence2;
|
|
423
|
+
}
|
|
345
424
|
const hasRange = ir.analyses.segments.hour.some(function range(segment) {
|
|
346
425
|
return segment.kind === "range";
|
|
347
426
|
});
|
|
@@ -351,15 +430,18 @@ function renderCompactClockTimes(ir, plan, opts) {
|
|
|
351
430
|
const fold = { minute: plan.minute, second: ir.analyses.clockSecond };
|
|
352
431
|
return interpretDayQualifier(ir, opts) + "at " + hourSegmentTimes(ir, fold, true, opts);
|
|
353
432
|
}
|
|
354
|
-
const
|
|
355
|
-
// The non-fold branch is a minute list, which has segments.
|
|
356
|
-
|
|
433
|
+
const minuteLead = (
|
|
434
|
+
// The non-fold branch is a minute list, which has segments. An
|
|
435
|
+
// offset/uneven step enumerated to that list reads as a stride.
|
|
436
|
+
strideFromSegments(ir.analyses.segments.minute, "minute", "hour", opts) ?? listPastThe(
|
|
357
437
|
segmentWords(ir.analyses.segments.minute, opts),
|
|
358
438
|
"minute",
|
|
359
439
|
"hour",
|
|
360
440
|
opts
|
|
361
|
-
)
|
|
441
|
+
)
|
|
362
442
|
);
|
|
443
|
+
const cadence = unevenHourCadence(ir, opts);
|
|
444
|
+
const phrase = cadence ? minuteLead + ", " + cadence + trailingQualifier(ir, opts) : minuteLead + ", at " + hourSegmentTimes(ir, { minute: 0, second: null }, true, opts) + trailingQualifier(ir, opts);
|
|
363
445
|
return ir.analyses.clockSecond ? secondsLeadClause(ir, opts) + ", " + phrase : phrase;
|
|
364
446
|
}
|
|
365
447
|
function foldedHourWindows(ir, plan, opts) {
|
|
@@ -406,24 +488,50 @@ var renderers = {
|
|
|
406
488
|
singleMinute: renderSingleMinute,
|
|
407
489
|
standaloneSeconds: renderStandaloneSeconds
|
|
408
490
|
};
|
|
491
|
+
function renderStride(stride, opts) {
|
|
492
|
+
const { interval, start, last, cycle, unit, anchor } = stride;
|
|
493
|
+
const cadence = "every " + getNumber(interval, opts) + " " + unit + "s";
|
|
494
|
+
const tiles = cycle % interval === 0;
|
|
495
|
+
if (start === 0 && tiles) {
|
|
496
|
+
return cadence;
|
|
497
|
+
}
|
|
498
|
+
if (start < interval && tiles) {
|
|
499
|
+
return cadence + " from " + getNumber(start, opts) + " " + pluralize(start, unit) + " past the " + anchor;
|
|
500
|
+
}
|
|
501
|
+
const num = seriesNumber([start, last], opts);
|
|
502
|
+
return cadence + " from " + num(start) + through(opts) + num(last) + " " + pluralize(last, unit) + " past the " + anchor;
|
|
503
|
+
}
|
|
504
|
+
function singleValues(segments) {
|
|
505
|
+
const values = [];
|
|
506
|
+
for (const segment of segments) {
|
|
507
|
+
if (segment.kind !== "single") {
|
|
508
|
+
return null;
|
|
509
|
+
}
|
|
510
|
+
values.push(+segment.value);
|
|
511
|
+
}
|
|
512
|
+
return values;
|
|
513
|
+
}
|
|
514
|
+
function strideFromSegments(segments, unit, anchor, opts) {
|
|
515
|
+
const values = singleValues(segments);
|
|
516
|
+
const step = values && arithmeticStep(values);
|
|
517
|
+
return step ? renderStride({ ...step, cycle: 60, unit, anchor }, opts) : null;
|
|
518
|
+
}
|
|
409
519
|
function stepCycle60(segment, unit, anchor, opts) {
|
|
410
520
|
if (segment.startToken.indexOf("-") !== -1) {
|
|
411
521
|
return listPastThe(numberWords(segment.fires, opts), unit, anchor, opts);
|
|
412
522
|
}
|
|
413
523
|
const start = segment.startToken === "*" ? 0 : +segment.startToken;
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
if (segment.fires.length <= 3) {
|
|
417
|
-
return listPastThe(
|
|
418
|
-
numberWords(segment.fires, opts),
|
|
419
|
-
unit,
|
|
420
|
-
anchor,
|
|
421
|
-
opts
|
|
422
|
-
);
|
|
423
|
-
}
|
|
424
|
-
return "every " + getNumber(interval, opts) + " " + unit + "s from " + getNumber(start, opts) + " " + pluralize(start, unit) + " past the " + anchor;
|
|
524
|
+
if (start !== 0 && segment.fires.length <= 3) {
|
|
525
|
+
return listPastThe(numberWords(segment.fires, opts), unit, anchor, opts);
|
|
425
526
|
}
|
|
426
|
-
return
|
|
527
|
+
return renderStride({
|
|
528
|
+
interval: segment.interval,
|
|
529
|
+
start,
|
|
530
|
+
last: segment.fires[segment.fires.length - 1],
|
|
531
|
+
cycle: 60,
|
|
532
|
+
unit,
|
|
533
|
+
anchor
|
|
534
|
+
}, opts);
|
|
427
535
|
}
|
|
428
536
|
function stepHours(segment, opts) {
|
|
429
537
|
if (segment.startToken.indexOf("-") !== -1) {
|
|
@@ -439,6 +547,141 @@ function stepHours(segment, opts) {
|
|
|
439
547
|
}
|
|
440
548
|
return "every " + getNumber(interval, opts) + " hours from " + getTime({ hour: start, minute: 0 }, opts);
|
|
441
549
|
}
|
|
550
|
+
function hourStrideCadence(stride, opts) {
|
|
551
|
+
const { start, interval, last } = stride;
|
|
552
|
+
const cadence = "every " + getNumber(interval, opts) + " hours";
|
|
553
|
+
const tiles = 24 % interval === 0;
|
|
554
|
+
if (start === 0 && tiles) {
|
|
555
|
+
return cadence;
|
|
556
|
+
}
|
|
557
|
+
if (start < interval && tiles) {
|
|
558
|
+
return cadence + " from " + getTime({ hour: start, minute: 0 }, opts);
|
|
559
|
+
}
|
|
560
|
+
return cadence + " from " + getTime({ hour: start, minute: 0 }, opts) + through(opts) + getTime({ hour: last, minute: 0 }, opts);
|
|
561
|
+
}
|
|
562
|
+
function offsetCleanStride(stride) {
|
|
563
|
+
return stride.start < stride.interval && 24 % stride.interval === 0;
|
|
564
|
+
}
|
|
565
|
+
function unevenHourCadence(ir, opts) {
|
|
566
|
+
const stride = hourStride(ir);
|
|
567
|
+
if (!stride || offsetCleanStride(stride)) {
|
|
568
|
+
return null;
|
|
569
|
+
}
|
|
570
|
+
return hourStrideCadence(stride, opts);
|
|
571
|
+
}
|
|
572
|
+
function hourListStride(values) {
|
|
573
|
+
if (values.length < 2) {
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
const interval = values[1] - values[0];
|
|
577
|
+
if (interval < 2) {
|
|
578
|
+
return null;
|
|
579
|
+
}
|
|
580
|
+
for (let i = 2; i < values.length; i += 1) {
|
|
581
|
+
if (values[i] - values[i - 1] !== interval) {
|
|
582
|
+
return null;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
if (values[0] !== 0 && values.length < 5) {
|
|
586
|
+
return null;
|
|
587
|
+
}
|
|
588
|
+
return { interval, last: values[values.length - 1], start: values[0] };
|
|
589
|
+
}
|
|
590
|
+
function hourStride(ir) {
|
|
591
|
+
const segments = ir.analyses.segments.hour;
|
|
592
|
+
if (segments.length === 1 && segments[0].kind === "step") {
|
|
593
|
+
const segment = segments[0];
|
|
594
|
+
if (segment.fires.length < 2) {
|
|
595
|
+
return null;
|
|
596
|
+
}
|
|
597
|
+
const start = segment.startToken === "*" ? 0 : +segment.startToken.split("-")[0];
|
|
598
|
+
return { interval: segment.interval, last: segment.fires[segment.fires.length - 1], start };
|
|
599
|
+
}
|
|
600
|
+
const values = singleValues(segments);
|
|
601
|
+
return values && hourListStride(values);
|
|
602
|
+
}
|
|
603
|
+
function subMinuteSecond(ir) {
|
|
604
|
+
return ir.pattern.second === "*" || ir.shapes.second === "step";
|
|
605
|
+
}
|
|
606
|
+
function hourCadenceLead(ir, minute, opts) {
|
|
607
|
+
if (minute === 0) {
|
|
608
|
+
if (subMinuteSecond(ir)) {
|
|
609
|
+
return secondsClause(ir, "minute", opts) + " for one minute";
|
|
610
|
+
}
|
|
611
|
+
return secondsClause(ir, "hour", opts);
|
|
612
|
+
}
|
|
613
|
+
const minutePhrase = getNumber(minute, opts) + " " + pluralize(minute, "minute") + " past the hour";
|
|
614
|
+
if (ir.pattern.second === "0") {
|
|
615
|
+
return minutePhrase;
|
|
616
|
+
}
|
|
617
|
+
return secondsClause(ir, "minute", opts) + ", " + minutePhrase;
|
|
618
|
+
}
|
|
619
|
+
function hourCadence(ir, minute, opts) {
|
|
620
|
+
const stride = hourStride(ir);
|
|
621
|
+
if (!stride) {
|
|
622
|
+
return null;
|
|
623
|
+
}
|
|
624
|
+
const fires = (stride.last - stride.start) / stride.interval + 1;
|
|
625
|
+
if (ir.pattern.second === "0" && fires <= maxClockTimes && offsetCleanStride(stride)) {
|
|
626
|
+
return null;
|
|
627
|
+
}
|
|
628
|
+
const confinement = minute === 0 && subMinuteSecond(ir) && cleanStrideSegment(ir);
|
|
629
|
+
if (confinement) {
|
|
630
|
+
return secondsClause(ir, "minute", opts) + " for one minute " + everyNthHour(confinement, opts) + trailingQualifier(ir, opts);
|
|
631
|
+
}
|
|
632
|
+
if (minute === 0 && ir.pattern.second === "0") {
|
|
633
|
+
return hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
|
|
634
|
+
}
|
|
635
|
+
return hourCadenceLead(ir, minute, opts) + ", " + hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
|
|
636
|
+
}
|
|
637
|
+
function cleanStrideSegment(ir) {
|
|
638
|
+
const segments = ir.analyses.segments.hour;
|
|
639
|
+
const segment = segments.length === 1 && segments[0];
|
|
640
|
+
if (!segment || segment.kind !== "step" || segment.startToken.indexOf("-") !== -1 || !(segment.interval in stepOrdinals)) {
|
|
641
|
+
return null;
|
|
642
|
+
}
|
|
643
|
+
return segment;
|
|
644
|
+
}
|
|
645
|
+
function hasHourWindow(ir) {
|
|
646
|
+
return ir.analyses.segments.hour.some(function range(segment) {
|
|
647
|
+
return segment.kind === "range";
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
function hourRangeWindowTail(ir, opts) {
|
|
651
|
+
const windows = [];
|
|
652
|
+
const singles = [];
|
|
653
|
+
ir.analyses.segments.hour.forEach(function classify(segment) {
|
|
654
|
+
if (segment.kind === "range") {
|
|
655
|
+
windows.push("from " + getTime(
|
|
656
|
+
{ hour: +segment.bounds[0], minute: 0 },
|
|
657
|
+
opts
|
|
658
|
+
) + through(opts) + getTime({ hour: +segment.bounds[1], minute: 0 }, opts));
|
|
659
|
+
} else if (segment.kind === "step") {
|
|
660
|
+
singles.push(...segment.fires);
|
|
661
|
+
} else {
|
|
662
|
+
singles.push(+segment.value);
|
|
663
|
+
}
|
|
664
|
+
});
|
|
665
|
+
let phrase = "every hour " + joinList(windows, opts);
|
|
666
|
+
if (singles.length) {
|
|
667
|
+
phrase += " and at " + joinList(singles.map(function time(hour) {
|
|
668
|
+
return getTime({ hour, minute: 0 }, opts);
|
|
669
|
+
}), opts);
|
|
670
|
+
}
|
|
671
|
+
return phrase;
|
|
672
|
+
}
|
|
673
|
+
function hourRangeCadence(ir, minute, opts) {
|
|
674
|
+
if (minute !== 0 || !hasHourWindow(ir)) {
|
|
675
|
+
return null;
|
|
676
|
+
}
|
|
677
|
+
if (ir.pattern.second === "0") {
|
|
678
|
+
return null;
|
|
679
|
+
}
|
|
680
|
+
if (subMinuteSecond(ir)) {
|
|
681
|
+
return secondsClause(ir, "minute", opts) + " for one minute during the " + hourSegmentTimes(ir, { minute: 0, second: null }, false, opts) + " hours" + trailingQualifier(ir, opts);
|
|
682
|
+
}
|
|
683
|
+
return hourCadenceLead(ir, minute, opts) + ", " + hourRangeWindowTail(ir, opts) + trailingQualifier(ir, opts);
|
|
684
|
+
}
|
|
442
685
|
function seriesNumber(values, opts) {
|
|
443
686
|
const anyBig = values.some(function big(v) {
|
|
444
687
|
return +v > 10;
|