make[1]: Entering directory `/home/bill/dev/later'
Line | Hits | Source |
---|---|---|
1 | 1 | later.array = {}; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Next | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Returns the next valid value in a range of values, wrapping as needed. Assumes | |
6 | * the array has already been sorted. | |
7 | * | |
8 | * Later is freely distributable under the MIT license. | |
9 | * For all details and documentation: | |
10 | * http://github.com/bunkat/later | |
11 | */ | |
12 | ||
13 | 1 | later.array.next = function (val, values, extent) { |
14 | ||
15 | 9815 | var cur, |
16 | zeroIsLargest = extent[0] !== 0, | |
17 | nextIdx = 0; | |
18 | ||
19 | 9815 | for(var i = values.length-1; i > -1; --i) { |
20 | 29761 | cur = values[i]; |
21 | ||
22 | 29761 | if(cur === val) { |
23 | 6579 | return cur; |
24 | } | |
25 | ||
26 | 23182 | if(cur > val || (cur === 0 && zeroIsLargest && extent[1] > val)) { |
27 | 21233 | nextIdx = i; |
28 | 21233 | continue; |
29 | } | |
30 | ||
31 | 1949 | break; |
32 | } | |
33 | ||
34 | 3236 | return values[nextIdx]; |
35 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Next Invalid | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Returns the next invalid value in a range of values, wrapping as needed. Assumes | |
6 | * the array has already been sorted. | |
7 | * | |
8 | * Later is freely distributable under the MIT license. | |
9 | * For all details and documentation: | |
10 | * http://github.com/bunkat/later | |
11 | */ | |
12 | ||
13 | 1 | later.array.nextInvalid = function (val, values, extent) { |
14 | ||
15 | 1255 | var min = extent[0], max = extent[1], len = values.length, |
16 | zeroVal = values[len-1] === 0 && min !== 0 ? max : 0, | |
17 | next = val, | |
18 | i = values.indexOf(val), | |
19 | start = next; | |
20 | ||
21 | 1255 | while(next === (values[i] || zeroVal)) { |
22 | ||
23 | 1448 | next++; |
24 | 1448 | if(next > max) { |
25 | 17 | next = min; |
26 | } | |
27 | ||
28 | 1448 | i++; |
29 | 1448 | if(i === len) { |
30 | 66 | i = 0; |
31 | } | |
32 | ||
33 | 1448 | if(next === start) { |
34 | 3 | return undefined; |
35 | } | |
36 | } | |
37 | ||
38 | 1252 | return next; |
39 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Previous | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Returns the previous valid value in a range of values, wrapping as needed. Assumes | |
6 | * the array has already been sorted. | |
7 | * | |
8 | * Later is freely distributable under the MIT license. | |
9 | * For all details and documentation: | |
10 | * http://github.com/bunkat/later | |
11 | */ | |
12 | ||
13 | 1 | later.array.prev = function (val, values, extent) { |
14 | ||
15 | 3574 | var cur, len = values.length, |
16 | zeroIsLargest = extent[0] !== 0, | |
17 | prevIdx = len-1; | |
18 | ||
19 | 3574 | for(var i = 0; i < len; i++) { |
20 | 5660 | cur = values[i]; |
21 | ||
22 | 5660 | if(cur === val) { |
23 | 1983 | return cur; |
24 | } | |
25 | ||
26 | 3677 | if(cur < val || (cur === 0 && zeroIsLargest && extent[1] < val)) { |
27 | 2897 | prevIdx = i; |
28 | 2897 | continue; |
29 | } | |
30 | ||
31 | 780 | break; |
32 | } | |
33 | ||
34 | 1591 | return values[prevIdx]; |
35 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Previous Invalid | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Returns the previous invalid value in a range of values, wrapping as needed. Assumes | |
6 | * the array has already been sorted. | |
7 | * | |
8 | * Later is freely distributable under the MIT license. | |
9 | * For all details and documentation: | |
10 | * http://github.com/bunkat/later | |
11 | */ | |
12 | ||
13 | 1 | later.array.prevInvalid = function (val, values, extent) { |
14 | ||
15 | 187 | var min = extent[0], max = extent[1], len = values.length, |
16 | zeroVal = values[len-1] === 0 && min !== 0 ? max : 0, | |
17 | next = val, | |
18 | i = values.indexOf(val), | |
19 | start = next; | |
20 | ||
21 | 187 | while(next === (values[i] || zeroVal)) { |
22 | 366 | next--; |
23 | ||
24 | 366 | if(next < min) { |
25 | 22 | next = max; |
26 | } | |
27 | ||
28 | 366 | i--; |
29 | 366 | if(i === -1) { |
30 | 46 | i = len-1; |
31 | } | |
32 | ||
33 | 366 | if(next === start) { |
34 | 4 | return undefined; |
35 | } | |
36 | } | |
37 | ||
38 | 183 | return next; |
39 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Sort | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Sorts an array in natural ascending order, placing zero at the end | |
6 | * if zeroIsLast is true. | |
7 | * | |
8 | * Later is freely distributable under the MIT license. | |
9 | * For all details and documentation: | |
10 | * http://github.com/bunkat/later | |
11 | */ | |
12 | ||
13 | 1 | later.array.sort = function (arr, zeroIsLast) { |
14 | 4 | arr.sort(function(a,b) { |
15 | 40 | return +a - +b; |
16 | }); | |
17 | ||
18 | 4 | if(zeroIsLast && arr[0] === 0) { |
19 | 1 | arr.push(arr.shift()); |
20 | } | |
21 | }; |
Line | Hits | Source |
---|---|---|
1 | // indexOf compares searchElement to elements of the Array using strict | |
2 | // equality (the same method used by the ===, or triple-equals, operator). | |
3 | // | |
4 | // https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf | |
5 | // | |
6 | 1 | if (!Array.prototype.indexOf) { |
7 | 0 | Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) { |
8 | 0 | "use strict"; |
9 | 0 | if (this == null) { |
10 | 0 | throw new TypeError(); |
11 | } | |
12 | 0 | var t = Object(this); |
13 | 0 | var len = t.length >>> 0; |
14 | 0 | if (len === 0) { |
15 | 0 | return -1; |
16 | } | |
17 | 0 | var n = 0; |
18 | 0 | if (arguments.length > 1) { |
19 | 0 | n = Number(arguments[1]); |
20 | 0 | if (n != n) { // shortcut for verifying if it's NaN |
21 | 0 | n = 0; |
22 | 0 | } else if (n != 0 && n != Infinity && n != -Infinity) { |
23 | 0 | n = (n > 0 || -1) * Math.floor(Math.abs(n)); |
24 | } | |
25 | } | |
26 | 0 | if (n >= len) { |
27 | 0 | return -1; |
28 | } | |
29 | 0 | var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); |
30 | 0 | for (; k < len; k++) { |
31 | 0 | if (k in t && t[k] === searchElement) { |
32 | 0 | return k; |
33 | } | |
34 | } | |
35 | 0 | return -1; |
36 | } | |
37 | } |
Line | Hits | Source |
---|---|---|
1 | // The trim method returns the string stripped of whitespace from both ends. | |
2 | // trim does not affect the value of the string itself. | |
3 | // | |
4 | // https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/Trim | |
5 | // | |
6 | 1 | if(!String.prototype.trim) { |
7 | 0 | String.prototype.trim = function () { |
8 | 0 | return this.replace(/^\s+|\s+$/g,''); |
9 | }; | |
10 | } |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Day Constraint (D) | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Definition for a day of month (date) constraint type. | |
6 | * | |
7 | * Later is freely distributable under the MIT license. | |
8 | * For all details and documentation: | |
9 | * http://github.com/bunkat/later | |
10 | */ | |
11 | 1 | later.day = later.D = { |
12 | ||
13 | /** | |
14 | * The name of this constraint. | |
15 | */ | |
16 | name: 'day', | |
17 | ||
18 | /** | |
19 | * The rough amount of seconds between start and end for this constraint. | |
20 | * (doesn't need to be exact) | |
21 | */ | |
22 | range: 86400, | |
23 | ||
24 | /** | |
25 | * The day value of the specified date. | |
26 | * | |
27 | * @param {Date} d: The date to calculate the value of | |
28 | */ | |
29 | val: function(d) { | |
30 | 104249 | return d.D || (d.D = later.date.getDate.call(d)); |
31 | }, | |
32 | ||
33 | /** | |
34 | * Returns true if the val is valid for the date specified. | |
35 | * | |
36 | * @param {Date} d: The date to check the value on | |
37 | * @param {Integer} val: The value to validate | |
38 | */ | |
39 | isValid: function(d, val) { | |
40 | 3600 | return later.D.val(d) === (val || later.D.extent(d)[1]); |
41 | }, | |
42 | ||
43 | /** | |
44 | * The minimum and maximum valid day values of the month specified. | |
45 | * Zero to specify the last day of the month. | |
46 | * | |
47 | * @param {Date} d: The date indicating the month to find the extent of | |
48 | */ | |
49 | extent: function(d) { | |
50 | 45462 | if(d.DExtent) return d.DExtent; |
51 | ||
52 | 35934 | var month = later.M.val(d), |
53 | max = later.DAYS_IN_MONTH[month-1]; | |
54 | ||
55 | 35934 | if(month === 2 && later.dy.extent(d)[1] === 366) { |
56 | 607 | max = max+1; |
57 | } | |
58 | ||
59 | 35934 | return (d.DExtent = [1, max]); |
60 | }, | |
61 | ||
62 | /** | |
63 | * The start of the day of the specified date. | |
64 | * | |
65 | * @param {Date} d: The specified date | |
66 | */ | |
67 | start: function(d) { | |
68 | 20568 | return d.DStart || (d.DStart = later.date.next( |
69 | later.Y.val(d), later.M.val(d), later.D.val(d))); | |
70 | }, | |
71 | ||
72 | /** | |
73 | * The end of the day of the specified date. | |
74 | * | |
75 | * @param {Date} d: The specified date | |
76 | */ | |
77 | end: function(d) { | |
78 | 6079 | return d.DEnd || (d.DEnd = later.date.prev( |
79 | later.Y.val(d), later.M.val(d), later.D.val(d))); | |
80 | }, | |
81 | ||
82 | /** | |
83 | * Returns the start of the next instance of the day value indicated. Returns | |
84 | * the first day of the next month if val is greater than the number of | |
85 | * days in the following month. | |
86 | * | |
87 | * @param {Date} d: The starting date | |
88 | * @param {int} val: The desired value, must be within extent | |
89 | */ | |
90 | next: function(d, val) { | |
91 | 1245 | val = val > later.D.extent(d)[1] ? 1 : val; |
92 | 1245 | var month = later.date.nextRollover(d, val, later.D, later.M), |
93 | DMax = later.D.extent(month)[1]; | |
94 | ||
95 | 1245 | val = val > DMax ? 1 : val || DMax; |
96 | ||
97 | 1245 | return later.date.next( |
98 | later.Y.val(month), | |
99 | later.M.val(month), | |
100 | val | |
101 | ); | |
102 | }, | |
103 | ||
104 | /** | |
105 | * Returns the end of the previous instance of the day value indicated. Returns | |
106 | * the last day in the previous month if val is greater than the number of days | |
107 | * in the previous month. | |
108 | * | |
109 | * @param {Date} d: The starting date | |
110 | * @param {int} val: The desired value, must be within extent | |
111 | */ | |
112 | prev: function(d, val) { | |
113 | 1029 | var month = later.date.prevRollover(d, val, later.D, later.M), |
114 | DMax = later.D.extent(month)[1]; | |
115 | ||
116 | 1029 | return later.date.prev( |
117 | later.Y.val(month), | |
118 | later.M.val(month), | |
119 | val > DMax ? DMax : val || DMax | |
120 | ); | |
121 | } | |
122 | ||
123 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Day of Week Constraint (dw) | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Definition for a day of week constraint type. | |
6 | * | |
7 | * Later is freely distributable under the MIT license. | |
8 | * For all details and documentation: | |
9 | * http://github.com/bunkat/later | |
10 | */ | |
11 | 1 | later.dayOfWeek = later.dw = later.d = { |
12 | ||
13 | /** | |
14 | * The name of this constraint. | |
15 | */ | |
16 | name: 'day of week', | |
17 | ||
18 | /** | |
19 | * The rough amount of seconds between start and end for this constraint. | |
20 | * (doesn't need to be exact) | |
21 | */ | |
22 | range: 86400, | |
23 | ||
24 | /** | |
25 | * The day of week value of the specified date. | |
26 | * | |
27 | * @param {Date} d: The date to calculate the value of | |
28 | */ | |
29 | val: function(d) { | |
30 | 111085 | return d.dw || (d.dw = later.date.getDay.call(d)+1); |
31 | }, | |
32 | ||
33 | /** | |
34 | * Returns true if the val is valid for the date specified. | |
35 | * | |
36 | * @param {Date} d: The date to check the value on | |
37 | * @param {Integer} val: The value to validate | |
38 | */ | |
39 | isValid: function(d, val) { | |
40 | 1974 | return later.dw.val(d) === (val || 7); |
41 | }, | |
42 | ||
43 | /** | |
44 | * The minimum and maximum valid day of week values. Unlike the standard | |
45 | * Date object, Later day of week goes from 1 to 7. | |
46 | */ | |
47 | extent: function() { | |
48 | 2300 | return [1, 7]; |
49 | }, | |
50 | ||
51 | /** | |
52 | * The start of the day of the specified date. | |
53 | * | |
54 | * @param {Date} d: The specified date | |
55 | */ | |
56 | start: function(d) { | |
57 | 417 | return later.D.start(d); |
58 | }, | |
59 | ||
60 | /** | |
61 | * The end of the day of the specified date. | |
62 | * | |
63 | * @param {Date} d: The specified date | |
64 | */ | |
65 | end: function(d) { | |
66 | 346 | return later.D.end(d); |
67 | }, | |
68 | ||
69 | /** | |
70 | * Returns the start of the next instance of the day of week value indicated. | |
71 | * | |
72 | * @param {Date} d: The starting date | |
73 | * @param {int} val: The desired value, must be within extent | |
74 | */ | |
75 | next: function(d, val) { | |
76 | 30253 | val = val > 7 ? 1 : val || 7; |
77 | ||
78 | 30253 | return later.date.next( |
79 | later.Y.val(d), | |
80 | later.M.val(d), | |
81 | later.D.val(d) + (val - later.dw.val(d)) + (val <= later.dw.val(d) ? 7 : 0)); | |
82 | }, | |
83 | ||
84 | /** | |
85 | * Returns the end of the previous instance of the day of week value indicated. | |
86 | * | |
87 | * @param {Date} d: The starting date | |
88 | * @param {int} val: The desired value, must be within extent | |
89 | */ | |
90 | prev: function(d, val) { | |
91 | 414 | val = val > 7 ? 7 : val || 7; |
92 | ||
93 | 414 | return later.date.prev( |
94 | later.Y.val(d), | |
95 | later.M.val(d), | |
96 | later.D.val(d) + (val - later.dw.val(d)) + (val >= later.dw.val(d) ? -7 : 0)); | |
97 | } | |
98 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Day of Week Count Constraint (dc) | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Definition for a day of week count constraint type. This constraint is used | |
6 | * to specify schedules like '2nd Tuesday of every month'. | |
7 | * | |
8 | * Later is freely distributable under the MIT license. | |
9 | * For all details and documentation: | |
10 | * http://github.com/bunkat/later | |
11 | */ | |
12 | 1 | later.dayOfWeekCount = later.dc = { |
13 | ||
14 | /** | |
15 | * The name of this constraint. | |
16 | */ | |
17 | name: 'day of week count', | |
18 | ||
19 | /** | |
20 | * The rough amount of seconds between start and end for this constraint. | |
21 | * (doesn't need to be exact) | |
22 | */ | |
23 | range: 604800, | |
24 | ||
25 | /** | |
26 | * The day of week count value of the specified date. | |
27 | * | |
28 | * @param {Date} d: The date to calculate the value of | |
29 | */ | |
30 | val: function(d) { | |
31 | 2966 | return d.dc || (d.dc = Math.floor((later.D.val(d)-1)/7)+1); |
32 | }, | |
33 | ||
34 | /** | |
35 | * Returns true if the val is valid for the date specified. | |
36 | * | |
37 | * @param {Date} d: The date to check the value on | |
38 | * @param {Integer} val: The value to validate | |
39 | */ | |
40 | isValid: function(d, val) { | |
41 | 1095 | return (later.dc.val(d) === val) || |
42 | (val === 0 && later.D.val(d) > later.D.extent(d)[1] - 7); | |
43 | }, | |
44 | ||
45 | /** | |
46 | * The minimum and maximum valid day values of the month specified. | |
47 | * Zero to specify the last day of week count of the month. | |
48 | * | |
49 | * @param {Date} d: The date indicating the month to find the extent of | |
50 | */ | |
51 | extent: function(d) { | |
52 | 2316 | return d.dcExtent || (d.dcExtent = [1, Math.ceil(later.D.extent(d)[1] /7)]); |
53 | }, | |
54 | ||
55 | /** | |
56 | * The first day of the month with the same day of week count as the date | |
57 | * specified. | |
58 | * | |
59 | * @param {Date} d: The specified date | |
60 | */ | |
61 | start: function(d) { | |
62 | 180 | return d.dcStart || (d.dcStart = |
63 | later.date.next( | |
64 | later.Y.val(d), | |
65 | later.M.val(d), | |
66 | Math.max(1, ((later.dc.val(d) - 1) * 7) + 1 || 1))); | |
67 | }, | |
68 | ||
69 | /** | |
70 | * The last day of the month with the same day of week count as the date | |
71 | * specified. | |
72 | * | |
73 | * @param {Date} d: The specified date | |
74 | */ | |
75 | end: function(d) { | |
76 | 427 | return d.dcEnd || (d.dcEnd = |
77 | later.date.prev( | |
78 | later.Y.val(d), | |
79 | later.M.val(d), | |
80 | Math.min(later.dc.val(d) * 7, later.D.extent(d)[1]))); | |
81 | }, | |
82 | ||
83 | /** | |
84 | * Returns the next earliest date with the day of week count specified. | |
85 | * | |
86 | * @param {Date} d: The starting date | |
87 | * @param {int} val: The desired value, must be within extent | |
88 | */ | |
89 | next: function(d, val) { | |
90 | 256 | val = val > later.dc.extent(d)[1] ? 1 : val; |
91 | 256 | var month = later.date.nextRollover(d, val, later.dc, later.M), |
92 | dcMax = later.dc.extent(month)[1]; | |
93 | ||
94 | 256 | val = val > dcMax ? 1 : val; |
95 | ||
96 | 256 | var next = later.date.next( |
97 | later.Y.val(month), | |
98 | later.M.val(month), | |
99 | val === 0 ? later.D.extent(month)[1] - 6 : 1 + (7 * (val - 1)) | |
100 | ); | |
101 | ||
102 | 256 | if(next.getTime() <= d.getTime()) { |
103 | 2 | month = later.M.next(d, later.M.val(d)+1); |
104 | ||
105 | 2 | return later.date.next( |
106 | later.Y.val(month), | |
107 | later.M.val(month), | |
108 | val === 0 ? later.D.extent(month)[1] - 6 : 1 + (7 * (val - 1)) | |
109 | ); | |
110 | } | |
111 | ||
112 | 254 | return next; |
113 | }, | |
114 | ||
115 | /** | |
116 | * Returns the closest previous date with the day of week count specified. | |
117 | * | |
118 | * @param {Date} d: The starting date | |
119 | * @param {int} val: The desired value, must be within extent | |
120 | */ | |
121 | prev: function(d, val) { | |
122 | 221 | var month = later.date.prevRollover(d, val, later.dc, later.M), |
123 | dcMax = later.dc.extent(month)[1]; | |
124 | ||
125 | 221 | val = val > dcMax ? dcMax : val || dcMax; |
126 | ||
127 | 221 | return later.dc.end(later.date.prev( |
128 | later.Y.val(month), | |
129 | later.M.val(month), | |
130 | 1 + (7 * (val - 1)) | |
131 | )); | |
132 | } | |
133 | ||
134 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Day of Year Constraint (dy) | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Definition for a day of year constraint type. | |
6 | * | |
7 | * Later is freely distributable under the MIT license. | |
8 | * For all details and documentation: | |
9 | * http://github.com/bunkat/later | |
10 | */ | |
11 | 1 | later.dayOfYear = later.dy = { |
12 | ||
13 | /** | |
14 | * The name of this constraint. | |
15 | */ | |
16 | name: 'day of year', | |
17 | ||
18 | /** | |
19 | * The rough amount of seconds between start and end for this constraint. | |
20 | * (doesn't need to be exact) | |
21 | */ | |
22 | range: 86400, | |
23 | ||
24 | /** | |
25 | * The day of year value of the specified date. | |
26 | * | |
27 | * @param {Date} d: The date to calculate the value of | |
28 | */ | |
29 | val: function(d) { | |
30 | 19188 | return d.dy || (d.dy = |
31 | Math.ceil(1 + (later.D.start(d).getTime() - later.Y.start(d).getTime()) / later.DAY)); | |
32 | }, | |
33 | ||
34 | /** | |
35 | * Returns true if the val is valid for the date specified. | |
36 | * | |
37 | * @param {Date} d: The date to check the value on | |
38 | * @param {Integer} val: The value to validate | |
39 | */ | |
40 | isValid: function(d, val) { | |
41 | 9568 | return later.dy.val(d) === (val || later.dy.extent(d)[1]); |
42 | }, | |
43 | ||
44 | /** | |
45 | * The minimum and maximum valid day of year values of the month specified. | |
46 | * Zero indicates the last day of the year. | |
47 | * | |
48 | * @param {Date} d: The date indicating the month to find the extent of | |
49 | */ | |
50 | extent: function(d) { | |
51 | 34831 | var year = later.Y.val(d); |
52 | ||
53 | // shortcut on finding leap years since this function gets called a lot | |
54 | // works between 1901 and 2099 | |
55 | 34831 | return d.dyExtent || (d.dyExtent = [1, year % 4 ? 365 : 366]); |
56 | }, | |
57 | ||
58 | /** | |
59 | * The start of the day of year of the specified date. | |
60 | * | |
61 | * @param {Date} d: The specified date | |
62 | */ | |
63 | start: function(d) { | |
64 | 4810 | return later.D.start(d); |
65 | }, | |
66 | ||
67 | /** | |
68 | * The end of the day of year of the specified date. | |
69 | * | |
70 | * @param {Date} d: The specified date | |
71 | */ | |
72 | end: function(d) { | |
73 | 4810 | return later.D.end(d); |
74 | }, | |
75 | ||
76 | /** | |
77 | * Returns the start of the next instance of the day of year value indicated. | |
78 | * | |
79 | * @param {Date} d: The starting date | |
80 | * @param {int} val: The desired value, must be within extent | |
81 | */ | |
82 | next: function(d, val) { | |
83 | 4784 | val = val > later.dy.extent(d)[1] ? 1 : val; |
84 | 4784 | var year = later.date.nextRollover(d, val, later.dy, later.Y), |
85 | dyMax = later.dy.extent(year)[1]; | |
86 | ||
87 | 4784 | val = val > dyMax ? 1 : val || dyMax; |
88 | ||
89 | 4784 | return later.date.next( |
90 | later.Y.val(year), | |
91 | later.M.val(year), | |
92 | val | |
93 | ); | |
94 | ||
95 | }, | |
96 | ||
97 | /** | |
98 | * Returns the end of the previous instance of the day of year value indicated. | |
99 | * | |
100 | * @param {Date} d: The starting date | |
101 | * @param {int} val: The desired value, must be within extent | |
102 | */ | |
103 | prev: function(d, val) { | |
104 | 4784 | var year = later.date.prevRollover(d, val, later.dy, later.Y), |
105 | dyMax = later.dy.extent(year)[1]; | |
106 | ||
107 | 4784 | val = val > dyMax ? dyMax : val || dyMax; |
108 | ||
109 | 4784 | return later.date.prev( |
110 | later.Y.val(year), | |
111 | later.M.val(year), | |
112 | val | |
113 | ); | |
114 | } | |
115 | ||
116 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Full date (fd) | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Definition for specifying a full date and time. | |
6 | * | |
7 | * Later is freely distributable under the MIT license. | |
8 | * For all details and documentation: | |
9 | * http://github.com/bunkat/later | |
10 | */ | |
11 | 1 | later.fullDate = later.fd = { |
12 | ||
13 | /** | |
14 | * The name of this constraint. | |
15 | */ | |
16 | name: 'full date', | |
17 | ||
18 | /** | |
19 | * The rough amount of seconds between start and end for this constraint. | |
20 | * (doesn't need to be exact) | |
21 | */ | |
22 | range: 1, | |
23 | ||
24 | /** | |
25 | * The time value of the specified date. | |
26 | * | |
27 | * @param {Date} d: The date to calculate the value of | |
28 | */ | |
29 | val: function(d) { | |
30 | 62 | return d.fd || (d.fd = d.getTime()); |
31 | }, | |
32 | ||
33 | /** | |
34 | * Returns true if the val is valid for the date specified. | |
35 | * | |
36 | * @param {Date} d: The date to check the value on | |
37 | * @param {Integer} val: The value to validate | |
38 | */ | |
39 | isValid: function(d, val) { | |
40 | 8 | return later.fd.val(d) === val; |
41 | }, | |
42 | ||
43 | /** | |
44 | * The minimum and maximum valid time values. | |
45 | */ | |
46 | extent: function() { | |
47 | 34 | return [0, 32503680000000]; |
48 | }, | |
49 | ||
50 | /** | |
51 | * Returns the specified date. | |
52 | * | |
53 | * @param {Date} d: The specified date | |
54 | */ | |
55 | start: function(d) { | |
56 | 6 | return d; |
57 | }, | |
58 | ||
59 | /** | |
60 | * Returns the specified date. | |
61 | * | |
62 | * @param {Date} d: The specified date | |
63 | */ | |
64 | end: function(d) { | |
65 | 2 | return d; |
66 | }, | |
67 | ||
68 | /** | |
69 | * Returns the start of the next instance of the time value indicated. | |
70 | * | |
71 | * @param {Date} d: The starting date | |
72 | * @param {int} val: The desired value, must be within extent | |
73 | */ | |
74 | next: function(d, val) { | |
75 | 13 | return later.fd.val(d) < val ? new Date(val) : later.NEVER; |
76 | }, | |
77 | ||
78 | /** | |
79 | * Returns the end of the previous instance of the time value indicated. | |
80 | * | |
81 | * @param {Date} d: The starting date | |
82 | * @param {int} val: The desired value, must be within extent | |
83 | */ | |
84 | prev: function(d, val) { | |
85 | 3 | return later.fd.val(d) > val ? new Date(val) : later.NEVER; |
86 | } | |
87 | ||
88 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Hour Constraint (H) | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Definition for a hour constraint type. | |
6 | * | |
7 | * Later is freely distributable under the MIT license. | |
8 | * For all details and documentation: | |
9 | * http://github.com/bunkat/later | |
10 | */ | |
11 | 1 | later.hour = later.h = { |
12 | ||
13 | /** | |
14 | * The name of this constraint. | |
15 | */ | |
16 | name: 'hour', | |
17 | ||
18 | /** | |
19 | * The rough amount of seconds between start and end for this constraint. | |
20 | * (doesn't need to be exact) | |
21 | */ | |
22 | range: 3600, | |
23 | ||
24 | /** | |
25 | * The hour value of the specified date. | |
26 | * | |
27 | * @param {Date} d: The date to calculate the value of | |
28 | */ | |
29 | val: function(d) { | |
30 | 33989 | return d.h || (d.h = later.date.getHour.call(d)); |
31 | }, | |
32 | ||
33 | /** | |
34 | * Returns true if the val is valid for the date specified. | |
35 | * | |
36 | * @param {Date} d: The date to check the value on | |
37 | * @param {Integer} val: The value to validate | |
38 | */ | |
39 | isValid: function(d, val) { | |
40 | 3023 | return later.h.val(d) === val; |
41 | }, | |
42 | ||
43 | /** | |
44 | * The minimum and maximum valid hour values. | |
45 | */ | |
46 | extent: function() { | |
47 | 3962 | return [0, 23]; |
48 | }, | |
49 | ||
50 | /** | |
51 | * The start of the hour of the specified date. | |
52 | * | |
53 | * @param {Date} d: The specified date | |
54 | */ | |
55 | start: function(d) { | |
56 | 734 | return d.hStart || (d.hStart = later.date.next( |
57 | later.Y.val(d), later.M.val(d), later.D.val(d), later.h.val(d))); | |
58 | }, | |
59 | ||
60 | /** | |
61 | * The end of the hour of the specified date. | |
62 | * | |
63 | * @param {Date} d: The specified date | |
64 | */ | |
65 | end: function(d) { | |
66 | 707 | return d.hEnd || (d.hEnd = later.date.prev( |
67 | later.Y.val(d), later.M.val(d), later.D.val(d), later.h.val(d))); | |
68 | }, | |
69 | ||
70 | /** | |
71 | * Returns the start of the next instance of the hour value indicated. | |
72 | * | |
73 | * @param {Date} d: The starting date | |
74 | * @param {int} val: The desired value, must be within extent | |
75 | */ | |
76 | next: function(d, val) { | |
77 | 955 | val = val > 23 ? 0 : val; |
78 | ||
79 | 955 | var next = later.date.next( |
80 | later.Y.val(d), | |
81 | later.M.val(d), | |
82 | later.D.val(d) + (val <= later.h.val(d) ? 1 : 0), | |
83 | val); | |
84 | ||
85 | // correct for passing over a daylight savings boundry | |
86 | 955 | if(!later.date.isUTC && next.getTime() <= d.getTime()) { |
87 | 1 | next = later.date.next( |
88 | later.Y.val(next), | |
89 | later.M.val(next), | |
90 | later.D.val(next), | |
91 | val + 1); | |
92 | } | |
93 | ||
94 | 955 | return next; |
95 | }, | |
96 | ||
97 | /** | |
98 | * Returns the end of the previous instance of the hour value indicated. | |
99 | * | |
100 | * @param {Date} d: The starting date | |
101 | * @param {int} val: The desired value, must be within extent | |
102 | */ | |
103 | prev: function(d, val) { | |
104 | 816 | val = val > 23 ? 23 : val; |
105 | ||
106 | 816 | return later.date.prev( |
107 | later.Y.val(d), | |
108 | later.M.val(d), | |
109 | later.D.val(d) + (val >= later.h.val(d) ? -1 : 0), | |
110 | val); | |
111 | } | |
112 | ||
113 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Minute Constraint (m) | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Definition for a minute constraint type. | |
6 | * | |
7 | * Later is freely distributable under the MIT license. | |
8 | * For all details and documentation: | |
9 | * http://github.com/bunkat/later | |
10 | */ | |
11 | 1 | later.minute = later.m = { |
12 | ||
13 | /** | |
14 | * The name of this constraint. | |
15 | */ | |
16 | name: 'minute', | |
17 | ||
18 | /** | |
19 | * The rough amount of seconds between start and end for this constraint. | |
20 | * (doesn't need to be exact) | |
21 | */ | |
22 | range: 60, | |
23 | ||
24 | /** | |
25 | * The minute value of the specified date. | |
26 | * | |
27 | * @param {Date} d: The date to calculate the value of | |
28 | */ | |
29 | val: function(d) { | |
30 | 38147 | return d.m || (d.m = later.date.getMin.call(d)); |
31 | }, | |
32 | ||
33 | /** | |
34 | * Returns true if the val is valid for the date specified. | |
35 | * | |
36 | * @param {Date} d: The date to check the value on | |
37 | * @param {Integer} val: The value to validate | |
38 | */ | |
39 | isValid: function(d, val) { | |
40 | 5226 | return later.m.val(d) === val; |
41 | }, | |
42 | ||
43 | /** | |
44 | * The minimum and maximum valid minute values. | |
45 | */ | |
46 | extent: function(d) { | |
47 | 8538 | return [0, 59]; |
48 | }, | |
49 | ||
50 | /** | |
51 | * The start of the minute of the specified date. | |
52 | * | |
53 | * @param {Date} d: The specified date | |
54 | */ | |
55 | start: function(d) { | |
56 | 3110 | return d.mStart || (d.mStart = later.date.next( |
57 | later.Y.val(d), later.M.val(d), later.D.val(d), later.h.val(d), later.m.val(d))); | |
58 | }, | |
59 | ||
60 | /** | |
61 | * The end of the minute of the specified date. | |
62 | * | |
63 | * @param {Date} d: The specified date | |
64 | */ | |
65 | end: function(d) { | |
66 | 1895 | return d.mEnd || (d.mEnd = later.date.prev( |
67 | later.Y.val(d), later.M.val(d), later.D.val(d), later.h.val(d), later.m.val(d))); | |
68 | }, | |
69 | ||
70 | /** | |
71 | * Returns the start of the next instance of the minute value indicated. | |
72 | * | |
73 | * @param {Date} d: The starting date | |
74 | * @param {int} val: The desired value, must be within extent | |
75 | */ | |
76 | next: function(d, val) { | |
77 | 2303 | var m = later.m.val(d), |
78 | s = later.s.val(d), | |
79 | inc = val > 59 ? 60-m : (val <= m ? (60-m) + val : val-m), | |
80 | next = new Date(d.getTime() + (inc * later.MIN) - (s * later.SEC)); | |
81 | ||
82 | // correct for passing over a daylight savings boundry | |
83 | 2303 | if(!later.date.isUTC && next.getTime() <= d.getTime()) { |
84 | 0 | next = new Date(d.getTime() + ((inc + 120) * later.MIN) - (s * later.SEC)); |
85 | } | |
86 | ||
87 | 2303 | return next; |
88 | }, | |
89 | ||
90 | /** | |
91 | * Returns the end of the previous instance of the minute value indicated. | |
92 | * | |
93 | * @param {Date} d: The starting date | |
94 | * @param {int} val: The desired value, must be within extent | |
95 | */ | |
96 | prev: function(d, val) { | |
97 | 1971 | val = val > 59 ? 59 : val; |
98 | ||
99 | 1971 | return later.date.prev( |
100 | later.Y.val(d), | |
101 | later.M.val(d), | |
102 | later.D.val(d), | |
103 | later.h.val(d) + (val >= later.m.val(d) ? -1 : 0), | |
104 | val); | |
105 | } | |
106 | ||
107 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Month Constraint (M) | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Definition for a month constraint type. | |
6 | * | |
7 | * Later is freely distributable under the MIT license. | |
8 | * For all details and documentation: | |
9 | * http://github.com/bunkat/later | |
10 | */ | |
11 | 1 | later.month = later.M = { |
12 | ||
13 | /** | |
14 | * The name of this constraint. | |
15 | */ | |
16 | name: 'month', | |
17 | ||
18 | /** | |
19 | * The rough amount of seconds between start and end for this constraint. | |
20 | * (doesn't need to be exact) | |
21 | */ | |
22 | range: 2629740, | |
23 | ||
24 | /** | |
25 | * The month value of the specified date. | |
26 | * | |
27 | * @param {Date} d: The date to calculate the value of | |
28 | */ | |
29 | val: function(d) { | |
30 | 151949 | return d.M || (d.M = later.date.getMonth.call(d)+1); |
31 | }, | |
32 | ||
33 | /** | |
34 | * Returns true if the val is valid for the date specified. | |
35 | * | |
36 | * @param {Date} d: The date to check the value on | |
37 | * @param {Integer} val: The value to validate | |
38 | */ | |
39 | isValid: function(d, val) { | |
40 | 1175 | return later.M.val(d) === (val || 12); |
41 | }, | |
42 | ||
43 | /** | |
44 | * The minimum and maximum valid month values. Unlike the native date object, | |
45 | * month values in later are 1 based. | |
46 | */ | |
47 | extent: function() { | |
48 | 1591 | return [1, 12]; |
49 | }, | |
50 | ||
51 | /** | |
52 | * The start of the month of the specified date. | |
53 | * | |
54 | * @param {Date} d: The specified date | |
55 | */ | |
56 | start: function(d) { | |
57 | 3898 | return d.MStart || (d.MStart = later.date.next(later.Y.val(d), later.M.val(d))); |
58 | }, | |
59 | ||
60 | /** | |
61 | * The end of the month of the specified date. | |
62 | * | |
63 | * @param {Date} d: The specified date | |
64 | */ | |
65 | end: function(d) { | |
66 | 2196 | return d.MEnd || (d.MEnd = later.date.prev(later.Y.val(d), later.M.val(d))); |
67 | }, | |
68 | ||
69 | /** | |
70 | * Returns the start of the next instance of the month value indicated. | |
71 | * | |
72 | * @param {Date} d: The starting date | |
73 | * @param {int} val: The desired value, must be within extent | |
74 | */ | |
75 | next: function(d, val) { | |
76 | 399 | val = val > 12 ? 1 : val || 12; |
77 | ||
78 | 399 | return later.date.next( |
79 | later.Y.val(d) + (val > later.M.val(d) ? 0 : 1), | |
80 | val); | |
81 | }, | |
82 | ||
83 | /** | |
84 | * Returns the end of the previous instance of the month value indicated. | |
85 | * | |
86 | * @param {Date} d: The starting date | |
87 | * @param {int} val: The desired value, must be within extent | |
88 | */ | |
89 | prev: function(d, val) { | |
90 | 1262 | val = val > 12 ? 12 : val || 12; |
91 | ||
92 | 1262 | return later.date.prev( |
93 | later.Y.val(d) - (val >= later.M.val(d) ? 1 : 0), | |
94 | val); | |
95 | } | |
96 | ||
97 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Second Constraint (s) | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Definition for a second constraint type. | |
6 | * | |
7 | * Later is freely distributable under the MIT license. | |
8 | * For all details and documentation: | |
9 | * http://github.com/bunkat/later | |
10 | */ | |
11 | 1 | later.second = later.s = { |
12 | ||
13 | /** | |
14 | * The name of this constraint. | |
15 | */ | |
16 | name: 'second', | |
17 | ||
18 | /** | |
19 | * The rough amount of seconds between start and end for this constraint. | |
20 | * (doesn't need to be exact) | |
21 | */ | |
22 | range: 1, | |
23 | ||
24 | /** | |
25 | * The second value of the specified date. | |
26 | * | |
27 | * @param {Date} d: The date to calculate the value of | |
28 | */ | |
29 | val: function(d) { | |
30 | 31987 | return d.s || (d.s = later.date.getSec.call(d)); |
31 | }, | |
32 | ||
33 | /** | |
34 | * Returns true if the val is valid for the date specified. | |
35 | * | |
36 | * @param {Date} d: The date to check the value on | |
37 | * @param {Integer} val: The value to validate | |
38 | */ | |
39 | isValid: function(d, val) { | |
40 | 5100 | return later.s.val(d) === val; |
41 | }, | |
42 | ||
43 | /** | |
44 | * The minimum and maximum valid second values. | |
45 | */ | |
46 | extent: function() { | |
47 | 7768 | return [0, 59]; |
48 | }, | |
49 | ||
50 | /** | |
51 | * The start of the second of the specified date. | |
52 | * | |
53 | * @param {Date} d: The specified date | |
54 | */ | |
55 | start: function(d) { | |
56 | 3249 | return d; |
57 | }, | |
58 | ||
59 | /** | |
60 | * The end of the second of the specified date. | |
61 | * | |
62 | * @param {Date} d: The specified date | |
63 | */ | |
64 | end: function(d) { | |
65 | 1997 | return d; |
66 | }, | |
67 | ||
68 | /** | |
69 | * Returns the start of the next instance of the second value indicated. | |
70 | * | |
71 | * @param {Date} d: The starting date | |
72 | * @param {int} val: The desired value, must be within extent | |
73 | */ | |
74 | next: function(d, val) { | |
75 | 2842 | var s = later.s.val(d), |
76 | inc = val > 59 ? 60-s : (val <= s ? (60-s) + val : val-s), | |
77 | next = new Date(d.getTime() + (inc * later.SEC)); | |
78 | ||
79 | // correct for passing over a daylight savings boundry | |
80 | 2842 | if(!later.date.isUTC && next.getTime() <= d.getTime()) { |
81 | 0 | next = new Date(d.getTime() + ((inc + 7200) * later.SEC)); |
82 | } | |
83 | ||
84 | 2842 | return next; |
85 | }, | |
86 | ||
87 | /** | |
88 | * Returns the end of the previous instance of the second value indicated. | |
89 | * | |
90 | * @param {Date} d: The starting date | |
91 | * @param {int} val: The desired value, must be within extent | |
92 | */ | |
93 | prev: function(d, val, cache) { | |
94 | 1723 | val = val > 59 ? 59 : val; |
95 | ||
96 | 1723 | return later.date.prev( |
97 | later.Y.val(d), | |
98 | later.M.val(d), | |
99 | later.D.val(d), | |
100 | later.h.val(d), | |
101 | later.m.val(d) + (val >= later.s.val(d) ? -1 : 0), | |
102 | val); | |
103 | } | |
104 | ||
105 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Time Constraint (dy) | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Definition for a time of day constraint type. Stored as number of seconds | |
6 | * since midnight to simplify calculations. | |
7 | * | |
8 | * Later is freely distributable under the MIT license. | |
9 | * For all details and documentation: | |
10 | * http://github.com/bunkat/later | |
11 | */ | |
12 | 1 | later.time = later.t = { |
13 | ||
14 | /** | |
15 | * The name of this constraint. | |
16 | */ | |
17 | name: 'time', | |
18 | ||
19 | /** | |
20 | * The rough amount of seconds between start and end for this constraint. | |
21 | * (doesn't need to be exact) | |
22 | */ | |
23 | range: 1, | |
24 | ||
25 | /** | |
26 | * The time value of the specified date. | |
27 | * | |
28 | * @param {Date} d: The date to calculate the value of | |
29 | */ | |
30 | val: function(d) { | |
31 | 22379 | return d.t || (d.t = |
32 | (later.h.val(d) * 3600) + (later.m.val(d) * 60) + (later.s.val(d))); | |
33 | }, | |
34 | ||
35 | /** | |
36 | * Returns true if the val is valid for the date specified. | |
37 | * | |
38 | * @param {Date} d: The date to check the value on | |
39 | * @param {Integer} val: The value to validate | |
40 | */ | |
41 | isValid: function(d, val) { | |
42 | 10378 | return later.t.val(d) === val; |
43 | }, | |
44 | ||
45 | /** | |
46 | * The minimum and maximum valid time values. | |
47 | */ | |
48 | extent: function() { | |
49 | 15940 | return [0, 86399]; |
50 | }, | |
51 | ||
52 | /** | |
53 | * Returns the specified date. | |
54 | * | |
55 | * @param {Date} d: The specified date | |
56 | */ | |
57 | start: function(d) { | |
58 | 5285 | return d; |
59 | }, | |
60 | ||
61 | /** | |
62 | * Returns the specified date. | |
63 | * | |
64 | * @param {Date} d: The specified date | |
65 | */ | |
66 | end: function(d) { | |
67 | 5116 | return d; |
68 | }, | |
69 | ||
70 | /** | |
71 | * Returns the start of the next instance of the time value indicated. | |
72 | * | |
73 | * @param {Date} d: The starting date | |
74 | * @param {int} val: The desired value, must be within extent | |
75 | */ | |
76 | next: function(d, val) { | |
77 | 5152 | val = val > 86399 ? 0 : val; |
78 | ||
79 | 5152 | var next = later.date.next( |
80 | later.Y.val(d), | |
81 | later.M.val(d), | |
82 | later.D.val(d) + (val <= later.t.val(d) ? 1 : 0), | |
83 | 0, | |
84 | 0, | |
85 | val); | |
86 | ||
87 | // correct for passing over a daylight savings boundry | |
88 | 5152 | if(!later.date.isUTC && next.getTime() < d.getTime()) { |
89 | 0 | next = later.date.next( |
90 | later.Y.val(next), | |
91 | later.M.val(next), | |
92 | later.D.val(next), | |
93 | later.h.val(next), | |
94 | later.m.val(next), | |
95 | val + 7200); | |
96 | } | |
97 | ||
98 | 5152 | return next; |
99 | }, | |
100 | ||
101 | /** | |
102 | * Returns the end of the previous instance of the time value indicated. | |
103 | * | |
104 | * @param {Date} d: The starting date | |
105 | * @param {int} val: The desired value, must be within extent | |
106 | */ | |
107 | prev: function(d, val) { | |
108 | 5004 | val = val > 86399 ? 86399 : val; |
109 | ||
110 | 5004 | return later.date.next( |
111 | later.Y.val(d), | |
112 | later.M.val(d), | |
113 | later.D.val(d) + (val >= later.t.val(d) ? -1 : 0), | |
114 | 0, | |
115 | 0, | |
116 | val); | |
117 | } | |
118 | ||
119 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Week of Month Constraint (wy) | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Definition for an week of month constraint type. Week of month treats the | |
6 | * first of the month as the start of week 1, with each following week starting | |
7 | * on Sunday. | |
8 | * | |
9 | * Later is freely distributable under the MIT license. | |
10 | * For all details and documentation: | |
11 | * http://github.com/bunkat/later | |
12 | */ | |
13 | 1 | later.weekOfMonth = later.wm = { |
14 | ||
15 | /** | |
16 | * The name of this constraint. | |
17 | */ | |
18 | name: 'week of month', | |
19 | ||
20 | /** | |
21 | * The rough amount of seconds between start and end for this constraint. | |
22 | * (doesn't need to be exact) | |
23 | */ | |
24 | range: 604800, | |
25 | ||
26 | /** | |
27 | * The week of month value of the specified date. | |
28 | * | |
29 | * @param {Date} d: The date to calculate the value of | |
30 | */ | |
31 | val: function(d) { | |
32 | 788 | return d.wm || (d.wm = |
33 | (later.D.val(d) + | |
34 | (later.dw.val(later.M.start(d)) - 1) + (7 - later.dw.val(d))) / 7); | |
35 | }, | |
36 | ||
37 | /** | |
38 | * Returns true if the val is valid for the date specified. | |
39 | * | |
40 | * @param {Date} d: The date to check the value on | |
41 | * @param {Integer} val: The value to validate | |
42 | */ | |
43 | isValid: function(d, val) { | |
44 | 368 | return later.wm.val(d) === (val || later.wm.extent(d)[1]); |
45 | }, | |
46 | ||
47 | /** | |
48 | * The minimum and maximum valid week of month values for the month indicated. | |
49 | * Zero indicates the last week in the month. | |
50 | * | |
51 | * @param {Date} d: The date indicating the month to find values for | |
52 | */ | |
53 | extent: function(d) { | |
54 | 1388 | return d.wmExtent || (d.wmExtent = [1, |
55 | (later.D.extent(d)[1] + (later.dw.val(later.M.start(d)) - 1) + | |
56 | (7 - later.dw.val(later.M.end(d)))) / 7]); | |
57 | }, | |
58 | ||
59 | /** | |
60 | * The start of the week of the specified date. | |
61 | * | |
62 | * @param {Date} d: The specified date | |
63 | */ | |
64 | start: function(d) { | |
65 | 210 | return d.wmStart || (d.wmStart = later.date.next( |
66 | later.Y.val(d), | |
67 | later.M.val(d), | |
68 | Math.max(later.D.val(d) - later.dw.val(d) + 1, 1))); | |
69 | }, | |
70 | ||
71 | /** | |
72 | * The end of the week of the specified date. | |
73 | * | |
74 | * @param {Date} d: The specified date | |
75 | */ | |
76 | end: function(d) { | |
77 | 394 | return d.wmEnd || (d.wmEnd = later.date.prev( |
78 | later.Y.val(d), | |
79 | later.M.val(d), | |
80 | Math.min(later.D.val(d) + (7 - later.dw.val(d)), later.D.extent(d)[1]))); | |
81 | }, | |
82 | ||
83 | /** | |
84 | * Returns the start of the next instance of the week value indicated. Returns | |
85 | * the first day of the next month if val is greater than the number of | |
86 | * days in the following month. | |
87 | * | |
88 | * @param {Date} d: The starting date | |
89 | * @param {int} val: The desired value, must be within extent | |
90 | */ | |
91 | next: function(d, val) { | |
92 | 184 | val = val > later.wm.extent(d)[1] ? 1 : val; |
93 | ||
94 | 184 | var month = later.date.nextRollover(d, val, later.wm, later.M), |
95 | wmMax = later.wm.extent(month)[1]; | |
96 | ||
97 | 184 | val = val > wmMax ? 1 : val || wmMax; |
98 | ||
99 | // jump to the Sunday of the desired week, set to 1st of month for week 1 | |
100 | 184 | return later.date.next( |
101 | later.Y.val(month), | |
102 | later.M.val(month), | |
103 | Math.max(1, (val-1) * 7 - (later.dw.val(month)-2))); | |
104 | }, | |
105 | ||
106 | /** | |
107 | * Returns the end of the previous instance of the week value indicated. Returns | |
108 | * the last day of the previous month if val is greater than the number of | |
109 | * days in the previous month. | |
110 | * | |
111 | * @param {Date} d: The starting date | |
112 | * @param {int} val: The desired value, must be within extent | |
113 | */ | |
114 | prev: function(d, val) { | |
115 | 184 | var month = later.date.prevRollover(d, val, later.wm, later.M), |
116 | wmMax = later.wm.extent(month)[1]; | |
117 | ||
118 | 184 | val = val > wmMax ? wmMax : val || wmMax; |
119 | ||
120 | // jump to the end of Saturday of the desired week | |
121 | 184 | return later.wm.end(later.date.next( |
122 | later.Y.val(month), | |
123 | later.M.val(month), | |
124 | Math.max(1, (val-1) * 7 - (later.dw.val(month)-2)))); | |
125 | } | |
126 | ||
127 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Week of Year Constraint (wy) | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Definition for an ISO 8601 week constraint type. For more information about | |
6 | * ISO 8601 see http://en.wikipedia.org/wiki/ISO_week_date. | |
7 | * | |
8 | * Later is freely distributable under the MIT license. | |
9 | * For all details and documentation: | |
10 | * http://github.com/bunkat/later | |
11 | */ | |
12 | 1 | later.weekOfYear = later.wy = { |
13 | ||
14 | /** | |
15 | * The name of this constraint. | |
16 | */ | |
17 | name: 'week of year (ISO)', | |
18 | ||
19 | /** | |
20 | * The rough amount of seconds between start and end for this constraint. | |
21 | * (doesn't need to be exact) | |
22 | */ | |
23 | range: 604800, | |
24 | ||
25 | /** | |
26 | * The ISO week year value of the specified date. | |
27 | * | |
28 | * @param {Date} d: The date to calculate the value of | |
29 | */ | |
30 | val: function(d) { | |
31 | 8999 | if (d.wy) return d.wy; |
32 | ||
33 | // move to the Thursday in the target week and find Thurs of target year | |
34 | 8669 | var wThur = later.dw.next(later.wy.start(d), 5), |
35 | YThur = later.dw.next(later.Y.prev(wThur, later.Y.val(wThur)-1), 5); | |
36 | ||
37 | // caculate the difference between the two dates in weeks | |
38 | 8669 | return (d.wy = 1 + Math.ceil((wThur.getTime() - YThur.getTime()) / later.WEEK)); |
39 | }, | |
40 | ||
41 | /** | |
42 | * Returns true if the val is valid for the date specified. | |
43 | * | |
44 | * @param {Date} d: The date to check the value on | |
45 | * @param {Integer} val: The value to validate | |
46 | */ | |
47 | isValid: function(d, val) { | |
48 | 2955 | return later.wy.val(d) === (val || later.wy.extent(d)[1]); |
49 | }, | |
50 | ||
51 | /** | |
52 | * The minimum and maximum valid ISO week values for the year indicated. | |
53 | * | |
54 | * @param {Date} d: The date indicating the year to find ISO values for | |
55 | */ | |
56 | extent: function(d) { | |
57 | 12401 | if (d.wyExtent) return d.wyExtent; |
58 | ||
59 | // go to start of ISO week to get to the right year | |
60 | 7953 | var year = later.dw.next(later.wy.start(d), 5), |
61 | dwFirst = later.dw.val(later.Y.start(year)), | |
62 | dwLast = later.dw.val(later.Y.end(year)); | |
63 | ||
64 | 7953 | return (d.wyExtent = [1, dwFirst === 5 || dwLast === 5 ? 53 : 52]); |
65 | }, | |
66 | ||
67 | /** | |
68 | * The start of the ISO week of the specified date. | |
69 | * | |
70 | * @param {Date} d: The specified date | |
71 | */ | |
72 | start: function(d) { | |
73 | 22324 | return d.wyStart || (d.wyStart = later.date.next( |
74 | later.Y.val(d), | |
75 | later.M.val(d), | |
76 | // jump to the Monday of the current week | |
77 | later.D.val(d) - (later.dw.val(d) > 1 ? later.dw.val(d) - 2 : 6) | |
78 | )); | |
79 | }, | |
80 | ||
81 | /** | |
82 | * The end of the ISO week of the specified date. | |
83 | * | |
84 | * @param {Date} d: The specified date | |
85 | */ | |
86 | end: function(d) { | |
87 | 4274 | return d.wyEnd || (d.wyEnd = later.date.prev( |
88 | later.Y.val(d), | |
89 | later.M.val(d), | |
90 | // jump to the Saturday of the current week | |
91 | later.D.val(d) + (later.dw.val(d) > 1 ? 8 - later.dw.val(d) : 0) | |
92 | )); | |
93 | }, | |
94 | ||
95 | /** | |
96 | * Returns the start of the next instance of the ISO week value indicated. | |
97 | * | |
98 | * @param {Date} d: The starting date | |
99 | * @param {int} val: The desired value, must be within extent | |
100 | */ | |
101 | next: function(d, val) { | |
102 | 1424 | val = val > later.wy.extent(d)[1] ? 1 : val; |
103 | ||
104 | 1424 | var wyThur = later.dw.next(later.wy.start(d), 5), |
105 | year = later.date.nextRollover(wyThur, val, later.wy, later.Y); | |
106 | ||
107 | // handle case where 1st of year is last week of previous month | |
108 | 1424 | if(later.wy.val(year) !== 1) { |
109 | 726 | year = later.dw.next(year, 2); |
110 | } | |
111 | ||
112 | 1424 | var wyMax = later.wy.extent(year)[1], |
113 | wyStart = later.wy.start(year); | |
114 | ||
115 | 1424 | val = val > wyMax ? 1 : val || wyMax; |
116 | ||
117 | 1424 | return later.date.next( |
118 | later.Y.val(wyStart), | |
119 | later.M.val(wyStart), | |
120 | later.D.val(wyStart) + 7 * (val-1) | |
121 | ); | |
122 | }, | |
123 | ||
124 | /** | |
125 | * Returns the end of the previous instance of the ISO week value indicated. | |
126 | * | |
127 | * @param {Date} d: The starting date | |
128 | * @param {int} val: The desired value, must be within extent | |
129 | */ | |
130 | prev: function(d, val) { | |
131 | 1420 | var wyThur = later.dw.next(later.wy.start(d), 5), |
132 | year = later.date.prevRollover(wyThur, val, later.wy, later.Y); | |
133 | ||
134 | // handle case where 1st of year is last week of previous month | |
135 | 1420 | if(later.wy.val(year) !== 1) { |
136 | 787 | year = later.dw.next(year, 2); |
137 | } | |
138 | ||
139 | 1420 | var wyMax = later.wy.extent(year)[1], |
140 | wyEnd = later.wy.end(year); | |
141 | ||
142 | 1420 | val = val > wyMax ? wyMax : val || wyMax; |
143 | ||
144 | 1420 | return later.wy.end(later.date.next( |
145 | later.Y.val(wyEnd), | |
146 | later.M.val(wyEnd), | |
147 | later.D.val(wyEnd) + 7 * (val-1) | |
148 | )); | |
149 | } | |
150 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Year Constraint (Y) | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Definition for a year constraint type. | |
6 | * | |
7 | * Later is freely distributable under the MIT license. | |
8 | * For all details and documentation: | |
9 | * http://github.com/bunkat/later | |
10 | */ | |
11 | 1 | later.year = later.Y = { |
12 | ||
13 | /** | |
14 | * The name of this constraint. | |
15 | */ | |
16 | name: 'year', | |
17 | ||
18 | /** | |
19 | * The rough amount of seconds between start and end for this constraint. | |
20 | * (doesn't need to be exact) | |
21 | */ | |
22 | range: 31556900, | |
23 | ||
24 | /** | |
25 | * The year value of the specified date. | |
26 | * | |
27 | * @param {Date} d: The date to calculate the value of | |
28 | */ | |
29 | val: function(d) { | |
30 | 230114 | return d.Y || (d.Y = later.date.getYear.call(d)); |
31 | }, | |
32 | ||
33 | /** | |
34 | * Returns true if the val is valid for the date specified. | |
35 | * | |
36 | * @param {Date} d: The date to check the value on | |
37 | * @param {Integer} val: The value to validate | |
38 | */ | |
39 | isValid: function(d, val) { | |
40 | 3551 | return later.Y.val(d) === val; |
41 | }, | |
42 | ||
43 | /** | |
44 | * The minimum and maximum valid values for the year constraint. | |
45 | * If max is past 2099, later.D.extent must be fixed to calculate leap years | |
46 | * correctly. | |
47 | */ | |
48 | extent: function() { | |
49 | 29309 | return [1970, 2099]; |
50 | }, | |
51 | ||
52 | /** | |
53 | * The start of the year of the specified date. | |
54 | * | |
55 | * @param {Date} d: The specified date | |
56 | */ | |
57 | start: function(d) { | |
58 | 34142 | return d.YStart || (d.YStart = later.date.next(later.Y.val(d))); |
59 | }, | |
60 | ||
61 | /** | |
62 | * The end of the year of the specified date. | |
63 | * | |
64 | * @param {Date} d: The specified date | |
65 | */ | |
66 | end: function(d) { | |
67 | 12002 | return d.YEnd || (d.YEnd = later.date.prev(later.Y.val(d))); |
68 | }, | |
69 | ||
70 | /** | |
71 | * Returns the start of the next instance of the year value indicated. | |
72 | * | |
73 | * @param {Date} d: The starting date | |
74 | * @param {int} val: The desired value, must be within extent | |
75 | */ | |
76 | next: function(d, val) { | |
77 | 3430 | return val > later.Y.val(d) && val <= later.Y.extent()[1] ? |
78 | later.date.next(val) : later.NEVER; | |
79 | }, | |
80 | ||
81 | /** | |
82 | * Returns the end of the previous instance of the year value indicated. | |
83 | * | |
84 | * @param {Date} d: The starting date | |
85 | * @param {int} val: The desired value, must be within extent | |
86 | */ | |
87 | prev: function(d, val) { | |
88 | 15471 | return val < later.Y.val(d) && val >= later.Y.extent()[0] ? |
89 | later.date.prev(val) : later.NEVER; | |
90 | } | |
91 | ||
92 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Compile | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Compiles a single schedule definition into a form from which instances can be | |
6 | * efficiently calculated from. | |
7 | * | |
8 | * Later is freely distributable under the MIT license. | |
9 | * For all details and documentation: | |
10 | * http://github.com/bunkat/later | |
11 | */ | |
12 | 1 | later.compile = function(schedDef) { |
13 | ||
14 | 696 | var constraints = [], |
15 | constraintsLen = 0, | |
16 | tickConstraint; | |
17 | ||
18 | 696 | for(var key in schedDef) { |
19 | 1498 | var nameParts = key.split('_'), |
20 | name = nameParts[0], | |
21 | mod = nameParts[1], | |
22 | vals = schedDef[key], | |
23 | constraint = mod ? later.modifier[mod](later[name], vals) : later[name]; | |
24 | ||
25 | 1498 | constraints.push({constraint: constraint, vals: vals}); |
26 | 1498 | constraintsLen++; |
27 | } | |
28 | ||
29 | // sort constraints based on their range for best performance (we want to | |
30 | // always skip the largest block of time possible to find the next valid | |
31 | // value) | |
32 | 696 | constraints.sort(function(a,b) { |
33 | 1232 | return a.constraint.range < b.constraint.range; |
34 | }); | |
35 | ||
36 | // this is the smallest constraint, we use this one to tick the schedule when | |
37 | // finding multiple instances | |
38 | 696 | tickConstraint = constraints[constraintsLen-1].constraint; |
39 | ||
40 | /** | |
41 | * Returns a function to use when comparing two dates. Encapsulates the | |
42 | * difference between searching for instances forward and backwards so that | |
43 | * the same code can be completely reused for both directions. | |
44 | * | |
45 | * @param {String} dir: The direction to use, either 'next' or 'prev' | |
46 | */ | |
47 | 696 | function compareFn(dir) { |
48 | 1338 | return dir === 'next' ? |
49 | 43 | function(a,b) { return a.getTime() > b.getTime(); } : |
50 | 41 | function(a,b) { return b.getTime() > a.getTime(); }; |
51 | } | |
52 | ||
53 | 696 | return { |
54 | ||
55 | /** | |
56 | * Calculates the start of the next valid occurrence of a particular schedule | |
57 | * that occurs on or after the specified start time. | |
58 | * | |
59 | * @param {String} dir: Direction to search in ('next' or 'prev') | |
60 | * @param {Date} startDate: The first possible valid occurrence | |
61 | */ | |
62 | start: function(dir, startDate) { | |
63 | 3887 | var next = startDate, |
64 | nextVal = later.array[dir], | |
65 | maxAttempts = 1000, | |
66 | done; | |
67 | ||
68 | 3887 | while(maxAttempts-- && !done && next) { |
69 | 7310 | done = true; |
70 | ||
71 | // verify all of the constraints in order since we want to make the | |
72 | // largest jumps possible to find the first valid value | |
73 | 7310 | for(var i = 0; i < constraintsLen; i++) { |
74 | ||
75 | 13372 | var constraint = constraints[i].constraint, |
76 | curVal = constraint.val(next), | |
77 | extent = constraint.extent(next), | |
78 | newVal = nextVal(curVal, constraints[i].vals, extent); | |
79 | ||
80 | 13372 | if(!constraint.isValid(next, newVal)) { |
81 | 3446 | next = constraint[dir](next, newVal); |
82 | 3446 | done = false; |
83 | 3446 | break; // need to retest all constraints with new date |
84 | } | |
85 | } | |
86 | } | |
87 | ||
88 | 3887 | if(next !== later.NEVER) { |
89 | 3864 | next = dir === 'next' ? tickConstraint.start(next) : |
90 | tickConstraint.end(next); | |
91 | } | |
92 | ||
93 | // if next, move to start of time period. needed when moving backwards | |
94 | 3887 | return next; |
95 | }, | |
96 | ||
97 | /** | |
98 | * Given a valid start time, finds the next schedule that is invalid. | |
99 | * Useful for finding the end of a valid time range. | |
100 | * | |
101 | * @param {Date} startDate: The first possible valid occurrence | |
102 | */ | |
103 | end: function(dir, startDate) { | |
104 | ||
105 | 1338 | var result, |
106 | nextVal = later.array[dir + 'Invalid'], | |
107 | compare = compareFn(dir); | |
108 | ||
109 | 1338 | for(var i = constraintsLen-1; i >= 0; i--) { |
110 | 1431 | var constraint = constraints[i].constraint, |
111 | curVal = constraint.val(startDate), | |
112 | extent = constraint.extent(startDate), | |
113 | newVal = nextVal(curVal, constraints[i].vals, extent), | |
114 | next; | |
115 | ||
116 | 1431 | if(newVal !== undefined) { // constraint has invalid value, use that |
117 | 1425 | next = constraint[dir](startDate, newVal); |
118 | 1425 | if(next && (!result || compare(result, next))) { |
119 | 1365 | result = next; |
120 | } | |
121 | } | |
122 | } | |
123 | ||
124 | 1338 | return result; |
125 | }, | |
126 | ||
127 | /** | |
128 | * Ticks the date by the minimum constraint in this schedule | |
129 | * | |
130 | * @param {String} dir: Direction to tick in ('next' or 'prev') | |
131 | * @param {Date} date: The start date to tick from | |
132 | */ | |
133 | tick: function(dir, date) { | |
134 | 900 | return new Date(dir === 'next' ? |
135 | tickConstraint.end(date).getTime() + later.SEC : | |
136 | tickConstraint.start(date).getTime() - later.SEC); | |
137 | }, | |
138 | ||
139 | /** | |
140 | * Ticks the date to the start of the minimum constraint | |
141 | * | |
142 | * @param {Date} date: The start date to tick from | |
143 | */ | |
144 | tickStart: function(date) { | |
145 | 281 | return tickConstraint.start(date); |
146 | } | |
147 | ||
148 | }; | |
149 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Schedule | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Returns an object to calculate future or previous occurrences of the | |
6 | * specified schedule. | |
7 | * | |
8 | * Later is freely distributable under the MIT license. | |
9 | * For all details and documentation: | |
10 | * http://github.com/bunkat/later | |
11 | */ | |
12 | 1 | later.schedule = function(sched) { |
13 | 490 | if(!sched) throw new Error('Missing schedule definition.'); |
14 | 490 | if(!sched.schedules) throw new Error('Definition must include at least one schedule.'); |
15 | ||
16 | // compile the schedule components | |
17 | 490 | var schedules = [], |
18 | schedulesLen = sched.schedules.length, | |
19 | exceptions = [], | |
20 | exceptionsLen = sched.exceptions ? sched.exceptions.length : 0; | |
21 | ||
22 | 490 | for(var i = 0; i < schedulesLen; i++) { |
23 | 581 | schedules.push(later.compile(sched.schedules[i])); |
24 | } | |
25 | ||
26 | 490 | for(var j = 0; j < exceptionsLen; j++) { |
27 | 101 | exceptions.push(later.compile(sched.exceptions[j])); |
28 | } | |
29 | ||
30 | /** | |
31 | * Calculates count number of instances or ranges for the current schedule, | |
32 | * optionally between the specified startDate and endDate. | |
33 | * | |
34 | * @param {String} dir: The direction to use, either 'next' or 'prev' | |
35 | * @param {Integer} count: The number of instances or ranges to return | |
36 | * @param {Date} startDate: The earliest date a valid instance can occur on | |
37 | * @param {Date} endDate: The latest date a valid instance can occur on | |
38 | * @param {Bool} isRange: True to return ranges, false to return instances | |
39 | */ | |
40 | 490 | function getInstances(dir, count, startDate, endDate, isRange) { |
41 | 490 | var compare = compareFn(dir), // encapsulates difference between directions |
42 | loopCount = count, | |
43 | maxAttempts = 1000, | |
44 | schedStarts = [], exceptStarts = [], | |
45 | next, end, results = []; | |
46 | ||
47 | 490 | startDate = startDate ? new Date(startDate) : new Date(); |
48 | 490 | if(!startDate || !startDate.getTime()) throw new Error('Invalid start date.'); |
49 | ||
50 | // Step 1: calculate the earliest start dates for each schedule and exception | |
51 | 490 | setNextStarts(dir, schedules, schedStarts, startDate); |
52 | 490 | setRangeStarts(dir, exceptions, exceptStarts, startDate); |
53 | ||
54 | // Step 2: select the earliest of the start dates calculated | |
55 | 490 | while(maxAttempts-- && loopCount && (next = findNext(schedStarts, compare))) { |
56 | ||
57 | // Step 3: make sure the start date we found is in range | |
58 | 2077 | if(endDate && compare(next, endDate)) { |
59 | 36 | break; |
60 | } | |
61 | ||
62 | // Step 4: make sure we aren't in the middle of an exception range | |
63 | 2041 | if(exceptionsLen) { |
64 | 1157 | updateRangeStarts(dir, exceptions, exceptStarts, next); |
65 | 1157 | if((end = calcRangeOverlap(dir, exceptStarts, next))) { |
66 | 1062 | updateNextStarts(dir, schedules, schedStarts, end); |
67 | 1062 | continue; |
68 | } | |
69 | } | |
70 | ||
71 | // Step 5: Date is good, if range, find the end of the range and update start dates | |
72 | 979 | if(isRange) { |
73 | 87 | var maxEndDate = calcMaxEndDate(exceptStarts, compare); |
74 | 87 | end = calcEnd(dir, schedules, schedStarts, next, maxEndDate); |
75 | 87 | results.push( dir === 'next' ? |
76 | [ | |
77 | new Date(Math.max(startDate, next)), | |
78 | new Date(endDate ? Math.min(end, endDate) : end) | |
79 | ] : | |
80 | [ | |
81 | new Date(endDate ? Math.max(endDate, end.getTime()+later.SEC) : end.getTime()+later.SEC), | |
82 | new Date(Math.min(startDate, next.getTime()+later.SEC)) | |
83 | ] | |
84 | ); | |
85 | ||
86 | 87 | updateNextStarts(dir, schedules, schedStarts, end); |
87 | } | |
88 | // otherwise store the start date and tick the start dates | |
89 | else { | |
90 | 892 | results.push( dir === 'next' ? |
91 | new Date(Math.max(startDate, next)) : | |
92 | getStart(schedules, schedStarts, next, endDate) | |
93 | ); | |
94 | ||
95 | 892 | tickStarts(dir, schedules, schedStarts, next); |
96 | } | |
97 | ||
98 | 979 | loopCount--; |
99 | } | |
100 | ||
101 | 490 | return results.length === 0 ? later.NEVER : count === 1 ? results[0] : results; |
102 | } | |
103 | ||
104 | /** | |
105 | * Initially sets the first valid next start times | |
106 | * | |
107 | * @param {String} dir: The direction to use, either 'next' or 'prev' | |
108 | * @param {Array} schedArr: The set of compiled schedules to use | |
109 | * @param {Array} startsArr: The set of cached start dates for the schedules | |
110 | * @param {Date} startDate: Starts earlier than this date will be calculated | |
111 | */ | |
112 | 490 | function setNextStarts(dir, schedArr, startsArr, startDate) { |
113 | 490 | for(var i = 0, len = schedArr.length; i < len; i++) { |
114 | 581 | startsArr[i] = schedArr[i].start(dir, startDate); |
115 | } | |
116 | } | |
117 | ||
118 | /** | |
119 | * Updates the set of cached start dates to the next valid start dates. Only | |
120 | * schedules where the current start date is less than or equal to the | |
121 | * specified startDate need to be updated. | |
122 | * | |
123 | * @param {String} dir: The direction to use, either 'next' or 'prev' | |
124 | * @param {Array} schedArr: The set of compiled schedules to use | |
125 | * @param {Array} startsArr: The set of cached start dates for the schedules | |
126 | * @param {Date} startDate: Starts earlier than this date will be calculated | |
127 | */ | |
128 | 490 | function updateNextStarts(dir, schedArr, startsArr, startDate) { |
129 | 1149 | var compare = compareFn(dir); |
130 | ||
131 | 1149 | for(var i = 0, len = schedArr.length; i < len; i++) { |
132 | 1293 | if(startsArr[i] && !compare(startsArr[i], startDate)) { |
133 | 1149 | startsArr[i] = schedArr[i].start(dir, startDate); |
134 | } | |
135 | } | |
136 | } | |
137 | ||
138 | /** | |
139 | * Updates the set of cached ranges to the next valid ranges. Only | |
140 | * schedules where the current start date is less than or equal to the | |
141 | * specified startDate need to be updated. | |
142 | * | |
143 | * @param {String} dir: The direction to use, either 'next' or 'prev' | |
144 | * @param {Array} schedArr: The set of compiled schedules to use | |
145 | * @param {Array} startsArr: The set of cached start dates for the schedules | |
146 | * @param {Date} startDate: Starts earlier than this date will be calculated | |
147 | */ | |
148 | 490 | function setRangeStarts(dir, schedArr, rangesArr, startDate) { |
149 | 490 | var compare = compareFn(dir); |
150 | ||
151 | 490 | for(var i = 0, len = schedArr.length; i < len; i++) { |
152 | 101 | var nextStart = schedArr[i].start(dir, startDate); |
153 | ||
154 | 101 | if(!nextStart) { |
155 | 1 | rangesArr[i] = later.NEVER; |
156 | } | |
157 | else { | |
158 | 100 | rangesArr[i] = [nextStart, schedArr[i].end(dir, nextStart)]; |
159 | } | |
160 | } | |
161 | } | |
162 | ||
163 | /** | |
164 | * Updates the set of cached ranges to the next valid ranges. Only | |
165 | * schedules where the current start date is less than or equal to the | |
166 | * specified startDate need to be updated. | |
167 | * | |
168 | * @param {String} dir: The direction to use, either 'next' or 'prev' | |
169 | * @param {Array} schedArr: The set of compiled schedules to use | |
170 | * @param {Array} startsArr: The set of cached start dates for the schedules | |
171 | * @param {Date} startDate: Starts earlier than this date will be calculated | |
172 | */ | |
173 | 490 | function updateRangeStarts(dir, schedArr, rangesArr, startDate) { |
174 | 1157 | var compare = compareFn(dir); |
175 | ||
176 | 1157 | for(var i = 0, len = schedArr.length; i < len; i++) { |
177 | 1277 | if(rangesArr[i] && !compare(rangesArr[i][0], startDate)) { |
178 | 1150 | var nextStart = schedArr[i].start(dir, startDate); |
179 | ||
180 | 1150 | if(!nextStart) { |
181 | 3 | rangesArr[i] = later.NEVER; |
182 | } | |
183 | else { | |
184 | 1147 | rangesArr[i] = [nextStart, schedArr[i].end(dir, nextStart)]; |
185 | } | |
186 | } | |
187 | } | |
188 | } | |
189 | ||
190 | /** | |
191 | * Increments all schedules with next start equal to startDate by one tick. | |
192 | * Tick size is determined by the smallest constraint within a schedule. | |
193 | * | |
194 | * @param {String} dir: The direction to use, either 'next' or 'prev' | |
195 | * @param {Array} schedArr: The set of compiled schedules to use | |
196 | * @param {Array} startsArr: The set of cached start dates for the schedules | |
197 | * @param {Date} startDate: The date that should cause a schedule to tick | |
198 | */ | |
199 | 490 | function tickStarts(dir, schedArr, startsArr, startDate) { |
200 | 892 | for(var i = 0, len = schedArr.length; i < len; i++) { |
201 | 989 | if(startsArr[i] && startsArr[i].getTime() === startDate.getTime()) { |
202 | 892 | startsArr[i] = schedArr[i].start(dir, schedArr[i].tick(dir, startDate)); |
203 | } | |
204 | } | |
205 | } | |
206 | ||
207 | /** | |
208 | * Determines the start date of the schedule that produced startDate | |
209 | * | |
210 | * @param {Array} schedArr: The set of compiled schedules to use | |
211 | * @param {Array} startsArr: The set of cached start dates for the schedules | |
212 | * @param {Date} startDate: The date that should cause a schedule to tick | |
213 | * @param {Date} minEndDate: The minimum end date to return | |
214 | */ | |
215 | 490 | function getStart(schedArr, startsArr, startDate, minEndDate) { |
216 | 281 | var result; |
217 | ||
218 | 281 | for(var i = 0, len = startsArr.length; i < len; i++) { |
219 | 300 | if(startsArr[i] && startsArr[i].getTime() === startDate.getTime()) { |
220 | 281 | var start = schedArr[i].tickStart(startDate); |
221 | ||
222 | 281 | if(minEndDate && (start < minEndDate)) { |
223 | 3 | return minEndDate; |
224 | } | |
225 | ||
226 | 278 | if(!result || (start > result)) { |
227 | 278 | result = start; |
228 | } | |
229 | } | |
230 | } | |
231 | ||
232 | 278 | return result; |
233 | } | |
234 | ||
235 | /** | |
236 | * Calculates the end of the overlap between any exception schedule and the | |
237 | * specified start date. Returns undefined if there is no overlap. | |
238 | * | |
239 | * @param {String} dir: The direction to use, either 'next' or 'prev' | |
240 | * @param {Array} schedArr: The set of compiled schedules to use | |
241 | * @param {Array} rangesArr: The set of cached start dates for the schedules | |
242 | * @param {Date} startDate: The valid date for which the overlap will be found | |
243 | */ | |
244 | 490 | function calcRangeOverlap(dir, rangesArr, startDate) { |
245 | 1157 | var compare = compareFn(dir), result; |
246 | ||
247 | 1157 | for(var i = 0, len = rangesArr.length; i < len; i++) { |
248 | 1277 | var range = rangesArr[i]; |
249 | ||
250 | 1277 | if(range && !compare(range[0], startDate) && |
251 | (!range[1] || compare(range[1], startDate))) { | |
252 | // startDate is in the middle of an exception range | |
253 | 1070 | if(!result || compare(range[1], result)) { |
254 | 1062 | result = range[1]; |
255 | } | |
256 | } | |
257 | } | |
258 | ||
259 | 1157 | return result; |
260 | } | |
261 | ||
262 | /** | |
263 | * Calculates the earliest start of an exception schedule, this is the maximum | |
264 | * end date of the schedule. | |
265 | * | |
266 | * @param {Array} exceptsArr: The set of cached exception ranges | |
267 | * @param {Array} compare: The compare function to use to determine earliest | |
268 | */ | |
269 | 490 | function calcMaxEndDate(exceptsArr, compare) { |
270 | 87 | var result; |
271 | ||
272 | 87 | for(var i = 0, len = exceptsArr.length; i < len; i++) { |
273 | 81 | if(exceptsArr[i] && (!result || compare(result, exceptsArr[i][0]))) { |
274 | 55 | result = exceptsArr[i][0]; |
275 | } | |
276 | } | |
277 | ||
278 | 87 | return result; |
279 | } | |
280 | ||
281 | ||
282 | /** | |
283 | * Calculates the next invalid date for a particular schedules starting from | |
284 | * the specified valid start date. | |
285 | * | |
286 | * @param {String} dir: The direction to use, either 'next' or 'prev' | |
287 | * @param {Array} schedArr: The set of compiled schedules to use | |
288 | * @param {Array} startsArr: The set of cached start dates for the schedules | |
289 | * @param {Date} startDate: The valid date for which the end date will be found | |
290 | * @param {Date} maxEndDate: The latested possible end date or null for none | |
291 | */ | |
292 | 490 | function calcEnd(dir, schedArr, startsArr, startDate, maxEndDate) { |
293 | 87 | var compare = compareFn(dir), result; |
294 | ||
295 | 87 | for(var i = 0, len = schedArr.length; i < len; i++) { |
296 | 111 | var start = startsArr[i]; |
297 | ||
298 | 111 | if(start && start.getTime() === startDate.getTime()) { |
299 | 87 | var end = schedArr[i].end(dir, start); |
300 | ||
301 | // if the end date is past the maxEndDate, just return the maxEndDate | |
302 | 87 | if(maxEndDate && compare(end, maxEndDate)) { |
303 | 30 | return maxEndDate; |
304 | } | |
305 | ||
306 | // otherwise, return the maximum end date that was calculated | |
307 | 57 | if(!result || compare(end, result)) { |
308 | 57 | result = end; |
309 | } | |
310 | } | |
311 | } | |
312 | ||
313 | 57 | return result; |
314 | } | |
315 | ||
316 | /** | |
317 | * Returns a function to use when comparing two dates. Encapsulates the | |
318 | * difference between searching for instances forward and backwards so that | |
319 | * the same code can be completely reused for both directions. | |
320 | * | |
321 | * @param {String} dir: The direction to use, either 'next' or 'prev' | |
322 | */ | |
323 | 490 | function compareFn(dir) { |
324 | 4530 | return dir === 'next' ? |
325 | 6409 | function(a,b) { return a.getTime() > b.getTime(); } : |
326 | 892 | function(a,b) { return b.getTime() > a.getTime(); }; |
327 | } | |
328 | ||
329 | /** | |
330 | * Returns the next value in an array using the function passed in as compare | |
331 | * to do the comparison. Skips over null or undefined values. | |
332 | * | |
333 | * @param {Array} arr: The array of values | |
334 | * @param {Function} compare: The comparison function to use | |
335 | */ | |
336 | 490 | function findNext(arr, compare) { |
337 | 2083 | var next = arr[0]; |
338 | ||
339 | 2083 | for(var i = 1, len = arr.length; i < len; i++) { |
340 | 261 | if(arr[i] && compare(next, arr[i])) { |
341 | 38 | next = arr[i]; |
342 | } | |
343 | } | |
344 | ||
345 | 2083 | return next; |
346 | } | |
347 | ||
348 | 490 | return { |
349 | ||
350 | /** | |
351 | * Returns true if d is a valid occurrence of the current schedule. | |
352 | * | |
353 | * @param {Date} d: The date to check | |
354 | */ | |
355 | isValid: function(d) { | |
356 | 356 | return getInstances('next', 1, d, d) !== later.NEVER; |
357 | }, | |
358 | ||
359 | /** | |
360 | * Finds the next valid instance or instances of the current schedule, | |
361 | * optionally between a specified start and end date. Start date is | |
362 | * Date.now() by default, end date is unspecified. Start date must be | |
363 | * smaller than end date. | |
364 | * | |
365 | * @param {Integer} count: The number of instances to return | |
366 | * @param {Date} startDate: The earliest a valid instance can occur | |
367 | * @param {Date} endDate: The latest a valid instance can occur | |
368 | */ | |
369 | next: function(count, startDate, endDate) { | |
370 | 63 | return getInstances('next', count || 1, startDate, endDate); |
371 | }, | |
372 | ||
373 | /** | |
374 | * Finds the previous valid instance or instances of the current schedule, | |
375 | * optionally between a specified start and end date. Start date is | |
376 | * Date.now() by default, end date is unspecified. Start date must be | |
377 | * greater than end date. | |
378 | * | |
379 | * @param {Integer} count: The number of instances to return | |
380 | * @param {Date} startDate: The earliest a valid instance can occur | |
381 | * @param {Date} endDate: The latest a valid instance can occur | |
382 | */ | |
383 | prev: function(count, startDate, endDate) { | |
384 | 55 | return getInstances('prev', count || 1, startDate, endDate); |
385 | }, | |
386 | ||
387 | /** | |
388 | * Finds the next valid range or ranges of the current schedule, | |
389 | * optionally between a specified start and end date. Start date is | |
390 | * Date.now() by default, end date is unspecified. Start date must be | |
391 | * greater than end date. | |
392 | * | |
393 | * @param {Integer} count: The number of ranges to return | |
394 | * @param {Date} startDate: The earliest a valid range can occur | |
395 | * @param {Date} endDate: The latest a valid range can occur | |
396 | */ | |
397 | nextRange: function(count, startDate, endDate) { | |
398 | 9 | return getInstances('next', count || 1, startDate, endDate, true); |
399 | }, | |
400 | ||
401 | /** | |
402 | * Finds the previous valid range or ranges of the current schedule, | |
403 | * optionally between a specified start and end date. Start date is | |
404 | * Date.now() by default, end date is unspecified. Start date must be | |
405 | * greater than end date. | |
406 | * | |
407 | * @param {Integer} count: The number of ranges to return | |
408 | * @param {Date} startDate: The earliest a valid range can occur | |
409 | * @param {Date} endDate: The latest a valid range can occur | |
410 | */ | |
411 | prevRange: function(count, startDate, endDate) { | |
412 | 7 | return getInstances('prev', count || 1, startDate, endDate, true); |
413 | } | |
414 | }; | |
415 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Set Interval | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Works similar to setInterval() but allows you to specify a Later schedule | |
6 | * instead of milliseconds. | |
7 | * | |
8 | * Later is freely distributable under the MIT license. | |
9 | * For all details and documentation: | |
10 | * http://github.com/bunkat/later | |
11 | */ | |
12 | ||
13 | 1 | later.setInterval = function(fn, sched) { |
14 | ||
15 | 2 | var t = later.setTimeout(scheduleTimeout, sched), |
16 | done = false; | |
17 | ||
18 | /** | |
19 | * Executes the specified function and then sets the timeout for the next | |
20 | * interval. | |
21 | */ | |
22 | 2 | function scheduleTimeout() { |
23 | 4 | if(!done) { |
24 | 3 | fn(); |
25 | 3 | t = later.setTimeout(scheduleTimeout, sched); |
26 | } | |
27 | } | |
28 | ||
29 | 2 | return { |
30 | ||
31 | /** | |
32 | * Clears the timeout. | |
33 | */ | |
34 | clear: function() { | |
35 | 2 | done = true; |
36 | 2 | t.clear(); |
37 | } | |
38 | ||
39 | }; | |
40 | ||
41 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Set Timeout | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Works similar to setTimeout() but allows you to specify a Later schedule | |
6 | * instead of milliseconds. | |
7 | * | |
8 | * Later is freely distributable under the MIT license. | |
9 | * For all details and documentation: | |
10 | * http://github.com/bunkat/later | |
11 | */ | |
12 | ||
13 | 1 | later.setTimeout = function(fn, sched) { |
14 | ||
15 | 8 | var s = later.schedule(sched), t; |
16 | 8 | scheduleTimeout(); |
17 | ||
18 | /** | |
19 | * Schedules the timeout to occur. If the next occurrence is greater than the | |
20 | * max supported delay (2147483647 ms) than we delay for that amount before | |
21 | * attempting to schedule the timeout again. | |
22 | */ | |
23 | 8 | function scheduleTimeout() { |
24 | 8 | var now = Date.now(), |
25 | next = s.next(2, now), | |
26 | diff = next[0].getTime() - now; | |
27 | ||
28 | // minimum time to fire is one second, use next occurrence instead | |
29 | 8 | if(diff < 1000) { |
30 | 6 | diff = next[1].getTime() - now; |
31 | } | |
32 | ||
33 | 8 | if(diff < 2147483647) { |
34 | 7 | t = setTimeout(fn, diff); |
35 | } | |
36 | else { | |
37 | 1 | t = setTimeout(scheduleTimeout, 2147483647); |
38 | } | |
39 | } | |
40 | ||
41 | 8 | return { |
42 | ||
43 | /** | |
44 | * Clears the timeout. | |
45 | */ | |
46 | clear: function() { | |
47 | 4 | clearTimeout(t); |
48 | } | |
49 | ||
50 | }; | |
51 | ||
52 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Date Constants | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Useful constants for dealing with time conversions. | |
6 | * | |
7 | * Later is freely distributable under the MIT license. | |
8 | * For all details and documentation: | |
9 | * http://github.com/bunkat/later | |
10 | */ | |
11 | ||
12 | // Time to milliseconds conversion | |
13 | 1 | later.SEC = 1000; |
14 | 1 | later.MIN = later.SEC * 60; |
15 | 1 | later.HOUR = later.MIN * 60; |
16 | 1 | later.DAY = later.HOUR * 24; |
17 | 1 | later.WEEK = later.DAY * 7; |
18 | ||
19 | // Array of days in each month, must be corrected for leap years | |
20 | 1 | later.DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; |
21 | ||
22 | // constant for specifying that a schedule can never occur | |
23 | 1 | later.NEVER = 0; |
Line | Hits | Source |
---|---|---|
1 | 1 | later.date = {}; |
2 | ||
3 | ||
4 | ||
5 | ||
6 | ||
7 | ||
8 |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Next | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Creates a new Date object defaulted to the first second after the specified | |
6 | * values. | |
7 | * | |
8 | * Later is freely distributable under the MIT license. | |
9 | * For all details and documentation: | |
10 | * http://github.com/bunkat/later | |
11 | */ | |
12 | ||
13 | /** | |
14 | * Builds and returns a new Date using the specified values. Date | |
15 | * returned is either using Local time or UTC based on isLocal. | |
16 | * | |
17 | * @param {Int} Y: Four digit year | |
18 | * @param {Int} M: Month between 1 and 12, defaults to 1 | |
19 | * @param {Int} D: Date between 1 and 31, defaults to 1 | |
20 | * @param {Int} h: Hour between 0 and 23, defaults to 0 | |
21 | * @param {Int} m: Minute between 0 and 59, defaults to 0 | |
22 | * @param {Int} s: Second between 0 and 59, defaults to 0 | |
23 | */ | |
24 | 1 | later.date.next = function(Y, M, D, h, m, s) { |
25 | ||
26 | 144440 | return later.date.build( |
27 | Y, | |
28 | M !== undefined ? M-1 : 0, | |
29 | D !== undefined ? D : 1, | |
30 | h || 0, | |
31 | m || 0, | |
32 | s || 0); | |
33 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Next Rollover | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Determines if a value will cause a particualr constraint to rollover to the | |
6 | * next largest time period. Used primarily when a constraint has a | |
7 | * variable extent. | |
8 | * | |
9 | * Later is freely distributable under the MIT license. | |
10 | * For all details and documentation: | |
11 | * http://github.com/bunkat/later | |
12 | */ | |
13 | ||
14 | 1 | later.date.nextRollover = function(d, val, constraint, period) { |
15 | 7893 | var cur = constraint.val(d), |
16 | max = constraint.extent(d)[1]; | |
17 | ||
18 | 7893 | return (((val || max) <= cur) || val > max) ? |
19 | new Date(period.end(d).getTime() + later.SEC) : | |
20 | period.start(d); | |
21 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Prev | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Creates a new Date object defaulted to the last second after the specified | |
6 | * values. | |
7 | * | |
8 | * Later is freely distributable under the MIT license. | |
9 | * For all details and documentation: | |
10 | * http://github.com/bunkat/later | |
11 | */ | |
12 | ||
13 | /** | |
14 | * Builds and returns a new Date using the specified values. Date | |
15 | * returned is either using Local time or UTC based on isLocal. | |
16 | * | |
17 | * @param {Int} Y: Four digit year | |
18 | * @param {Int} M: Month between 0 and 11, defaults to 11 | |
19 | * @param {Int} D: Date between 1 and 31, defaults to last day of month | |
20 | * @param {Int} h: Hour between 0 and 23, defaults to 23 | |
21 | * @param {Int} m: Minute between 0 and 59, defaults to 59 | |
22 | * @param {Int} s: Second between 0 and 59, defaults to 59 | |
23 | */ | |
24 | 1 | later.date.prev = function(Y, M, D, h, m, s) { |
25 | ||
26 | 51857 | var len = arguments.length; |
27 | 51857 | M = len < 2 ? 11 : M-1; |
28 | 51857 | D = len < 3 ? later.D.extent(later.date.next(Y, M+1))[1] : D; |
29 | 51857 | h = len < 4 ? 23 : h; |
30 | 51857 | m = len < 5 ? 59 : m; |
31 | 51857 | s = len < 6 ? 59 : s; |
32 | ||
33 | 51857 | return later.date.build(Y, M, D, h, m, s); |
34 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Prev Rollover | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Determines if a value will cause a particualr constraint to rollover to the | |
6 | * previous largest time period. Used primarily when a constraint has a | |
7 | * variable extent. | |
8 | * | |
9 | * Later is freely distributable under the MIT license. | |
10 | * For all details and documentation: | |
11 | * http://github.com/bunkat/later | |
12 | */ | |
13 | ||
14 | 1 | later.date.prevRollover = function(d, val, constraint, period) { |
15 | 7638 | var cur = constraint.val(d); |
16 | ||
17 | 7638 | return (val >= cur || !val) ? |
18 | period.start(period.prev(d, period.val(d)-1)) : | |
19 | period.start(d); | |
20 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Timezone | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Configures helper functions to switch between useing local time and UTC. Later | |
6 | * uses UTC time by default. | |
7 | * | |
8 | * Later is freely distributable under the MIT license. | |
9 | * For all details and documentation: | |
10 | * http://github.com/bunkat/later | |
11 | */ | |
12 | ||
13 | 1 | later.date.timezone = function(useLocalTime) { |
14 | ||
15 | // configure the date builder used to create new dates in the right timezone | |
16 | 41460 | later.date.build = useLocalTime ? |
17 | 85178 | function(Y, M, D, h, m, s) { return new Date(Y, M, D, h, m, s); } : |
18 | 111119 | function(Y, M, D, h, m, s) { return new Date(Date.UTC(Y, M, D, h, m, s)); }; |
19 | ||
20 | // configure the accessor methods | |
21 | 41460 | var get = useLocalTime ? 'get' : 'getUTC', |
22 | d = Date.prototype; | |
23 | ||
24 | 41460 | later.date.getYear = d[get + 'FullYear']; |
25 | 41460 | later.date.getMonth = d[get + 'Month']; |
26 | 41460 | later.date.getDate = d[get + 'Date']; |
27 | 41460 | later.date.getDay = d[get + 'Day']; |
28 | 41460 | later.date.getHour = d[get + 'Hours']; |
29 | 41460 | later.date.getMin = d[get + 'Minutes']; |
30 | 41460 | later.date.getSec = d[get + 'Seconds']; |
31 | ||
32 | // set the isUTC flag | |
33 | 41460 | later.date.isUTC = !useLocalTime; |
34 | }; | |
35 | ||
36 | // friendly names for available timezones | |
37 | 20801 | later.date.UTC = function() { later.date.timezone(false); }; |
38 | 20661 | later.date.localTime = function() { later.date.timezone(true); }; |
39 | ||
40 | // use UTC by default | |
41 | 1 | later.date.UTC(); |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * After Modifier | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Modifies a constraint such that all values that are greater than the | |
6 | * specified value are considered valid. | |
7 | * | |
8 | * Later is freely distributable under the MIT license. | |
9 | * For all details and documentation: | |
10 | * http://github.com/bunkat/later | |
11 | */ | |
12 | ||
13 | /** | |
14 | * Creates a new modified constraint. | |
15 | * | |
16 | * @param {Constraint} constraint: The constraint to be modified | |
17 | * @param {Integer} value: The starting value of the after constraint | |
18 | */ | |
19 | 1 | later.modifier.after = later.modifier.a = function(constraint, values) { |
20 | ||
21 | 153 | var value = values[0]; |
22 | ||
23 | 153 | return { |
24 | ||
25 | /** | |
26 | * Returns the name of the constraint with the 'after' modifier. | |
27 | */ | |
28 | name: 'after ' + constraint.name, | |
29 | ||
30 | /** | |
31 | * Pass through to the constraint. | |
32 | */ | |
33 | range: (constraint.extent(new Date())[1] - value) * constraint.range, | |
34 | ||
35 | /** | |
36 | * The value of the specified date. Returns value for any constraint val | |
37 | * that is greater than or equal to value. | |
38 | * | |
39 | * @param {Date} d: The date to calculate the value of | |
40 | */ | |
41 | val: constraint.val, | |
42 | ||
43 | /** | |
44 | * Returns true if the val is valid for the date specified. | |
45 | * | |
46 | * @param {Date} d: The date to check the value on | |
47 | * @param {Integer} val: The value to validate | |
48 | */ | |
49 | isValid: function(d, val) { | |
50 | 1494 | return this.val(d) >= value; |
51 | }, | |
52 | ||
53 | /** | |
54 | * Pass through to the constraint. | |
55 | */ | |
56 | extent: constraint.extent, | |
57 | ||
58 | /** | |
59 | * Pass through to the constraint. | |
60 | */ | |
61 | start: constraint.start, | |
62 | ||
63 | /** | |
64 | * Pass through to the constraint. | |
65 | */ | |
66 | end: constraint.end, | |
67 | ||
68 | /** | |
69 | * Pass through to the constraint. | |
70 | */ | |
71 | next: function(startDate, val) { | |
72 | 143 | if(val != value) val = constraint.extent(startDate)[0]; |
73 | 105 | return constraint.next(startDate, val); |
74 | }, | |
75 | ||
76 | /** | |
77 | * Pass through to the constraint. | |
78 | */ | |
79 | prev: function(startDate, val) { | |
80 | 59 | val = val === value ? constraint.extent(startDate)[1] : value - 1; |
81 | 59 | return constraint.prev(startDate, val); |
82 | } | |
83 | ||
84 | }; | |
85 | ||
86 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Before Modifier | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Modifies a constraint such that all values that are less than the | |
6 | * specified value are considered valid. | |
7 | * | |
8 | * Later is freely distributable under the MIT license. | |
9 | * For all details and documentation: | |
10 | * http://github.com/bunkat/later | |
11 | */ | |
12 | ||
13 | /** | |
14 | * Creates a new modified constraint. | |
15 | * | |
16 | * @param {Constraint} constraint: The constraint to be modified | |
17 | * @param {Integer} value: The starting value of the before constraint | |
18 | */ | |
19 | 1 | later.modifier.before = later.modifier.b = function(constraint, values) { |
20 | ||
21 | 141 | var value = values[values.length-1]; |
22 | ||
23 | 141 | return { |
24 | ||
25 | /** | |
26 | * Returns the name of the constraint with the 'before' modifier. | |
27 | */ | |
28 | name: 'before ' + constraint.name, | |
29 | ||
30 | /** | |
31 | * Pass through to the constraint. | |
32 | */ | |
33 | range: constraint.range * (value-1), | |
34 | ||
35 | /** | |
36 | * The value of the specified date. Returns value for any constraint val | |
37 | * that is less than or equal to value. | |
38 | * | |
39 | * @param {Date} d: The date to calculate the value of | |
40 | */ | |
41 | val: constraint.val, | |
42 | ||
43 | /** | |
44 | * Returns true if the val is valid for the date specified. | |
45 | * | |
46 | * @param {Date} d: The date to check the value on | |
47 | * @param {Integer} val: The value to validate | |
48 | */ | |
49 | isValid: function(d, val) { | |
50 | 491 | return this.val(d) < value; |
51 | }, | |
52 | ||
53 | /** | |
54 | * Pass through to the constraint. | |
55 | */ | |
56 | extent: constraint.extent, | |
57 | ||
58 | /** | |
59 | * Pass through to the constraint. | |
60 | */ | |
61 | start: constraint.start, | |
62 | ||
63 | /** | |
64 | * Jump to the end of the range. | |
65 | */ | |
66 | end: constraint.end, | |
67 | ||
68 | /** | |
69 | * Pass through to the constraint. | |
70 | */ | |
71 | next: function(startDate, val) { | |
72 | 81 | val = val === value ? constraint.extent(startDate)[0] : value; |
73 | 81 | return constraint.next(startDate, val); |
74 | }, | |
75 | ||
76 | /** | |
77 | * Pass through to the constraint. | |
78 | */ | |
79 | prev: function(startDate, val) { | |
80 | 55 | val = val === value ? value - 1 : constraint.extent(startDate)[1]; |
81 | 55 | return constraint.prev(startDate, val); |
82 | } | |
83 | ||
84 | }; | |
85 | ||
86 | }; |
Line | Hits | Source |
---|---|---|
1 | ||
2 | 1 | later.modifier = {}; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Cron | |
3 | * (c) 2013 Bill, BunKat LLC. | |
4 | * | |
5 | * Creates a valid Later schedule from a valid cron expression. | |
6 | * | |
7 | * Later is freely distributable under the MIT license. | |
8 | * For all details and documentation: | |
9 | * http://github.com/bunkat/later | |
10 | */ | |
11 | ||
12 | /** | |
13 | * Parses a valid cron expression and produces a valid schedule that | |
14 | * can then be used with Later. | |
15 | * | |
16 | * CronParser().parse('* 5 * * * * *', true); | |
17 | * | |
18 | * @param {String} expr: The cron expression to parse | |
19 | * @param {Bool} hasSeconds: True if the expression uses a seconds field | |
20 | * @api public | |
21 | */ | |
22 | 1 | later.parse.cron = function (expr, hasSeconds) { |
23 | ||
24 | // Constant array to convert valid names to values | |
25 | 87 | var NAMES = { |
26 | JAN: 1, FEB: 2, MAR: 3, APR: 4, MAY: 5, JUN: 6, JUL: 7, AUG: 8, | |
27 | SEP: 9, OCT: 10, NOV: 11, DEC: 12, | |
28 | SUN: 1, MON: 2, TUE: 3, WED: 4, THU: 5, FRI: 6, SAT: 7 | |
29 | }; | |
30 | ||
31 | // Contains the index, min, and max for each of the constraints | |
32 | 87 | var FIELDS = { |
33 | s: [0, 0, 59], // seconds | |
34 | m: [1, 0, 59], // minutes | |
35 | h: [2, 0, 23], // hours | |
36 | D: [3, 1, 31], // day of month | |
37 | M: [4, 1, 12], // month | |
38 | Y: [6, 1970, 2099], // year | |
39 | d: [5, 1, 7, 1] // day of week | |
40 | }; | |
41 | ||
42 | /** | |
43 | * Returns the value + offset if value is a number, otherwise it | |
44 | * attempts to look up the value in the NAMES table and returns | |
45 | * that result instead. | |
46 | * | |
47 | * @param {Int,String} value: The value that should be parsed | |
48 | * @param {Int} offset: Any offset that must be added to the value | |
49 | */ | |
50 | 87 | function getValue(value, offset) { |
51 | 321 | return isNaN(value) ? NAMES[value] || null : +value + (offset || 0); |
52 | } | |
53 | ||
54 | /** | |
55 | * Returns a deep clone of a schedule skipping any day of week | |
56 | * constraints. | |
57 | * | |
58 | * @param {Sched} sched: The schedule that will be cloned | |
59 | */ | |
60 | 87 | function cloneSchedule(sched) { |
61 | 6 | var clone = {}, field; |
62 | ||
63 | 6 | for(field in sched) { |
64 | 11 | if (field !== 'dc' && field !== 'd') { |
65 | 2 | clone[field] = sched[field].slice(0); |
66 | } | |
67 | } | |
68 | ||
69 | 6 | return clone; |
70 | } | |
71 | ||
72 | /** | |
73 | * Adds values to the specified constraint in the current schedule. | |
74 | * | |
75 | * @param {Sched} sched: The schedule to add the constraint to | |
76 | * @param {String} name: Name of constraint to add | |
77 | * @param {Int} min: Minimum value for this constraint | |
78 | * @param {Int} max: Maximum value for this constraint | |
79 | * @param {Int} inc: The increment to use between min and max | |
80 | */ | |
81 | 87 | function add(sched, name, min, max, inc) { |
82 | 187 | var i = min; |
83 | ||
84 | 187 | if (!sched[name]) { |
85 | 163 | sched[name] = []; |
86 | } | |
87 | ||
88 | 187 | while (i <= max) { |
89 | 359 | if (sched[name].indexOf(i) < 0) { |
90 | 353 | sched[name].push(i); |
91 | } | |
92 | 359 | i += inc || 1; |
93 | } | |
94 | } | |
95 | ||
96 | /** | |
97 | * Adds a hash item (of the form x#y or xL) to the schedule. | |
98 | * | |
99 | * @param {Schedule} schedules: The current schedule array to add to | |
100 | * @param {Schedule} curSched: The current schedule to add to | |
101 | * @param {Int} value: The value to add (x of x#y or xL) | |
102 | * @param {Int} hash: The hash value to add (y of x#y) | |
103 | */ | |
104 | 87 | function addHash(schedules, curSched, value, hash) { |
105 | // if there are any existing day of week constraints that | |
106 | // aren't equal to the one we're adding, create a new | |
107 | // composite schedule | |
108 | 14 | if ((curSched.d && !curSched.dc) || |
109 | (curSched.dc && curSched.dc.indexOf(hash) < 0)) { | |
110 | 6 | schedules.push(cloneSchedule(curSched)); |
111 | 6 | curSched = schedules[schedules.length-1]; |
112 | } | |
113 | ||
114 | 14 | add(curSched, 'd', value, value); |
115 | 14 | add(curSched, 'dc', hash, hash); |
116 | } | |
117 | ||
118 | 87 | function addWeekday(s, curSched, value) { |
119 | 4 | var except1 = {}, except2 = {}; |
120 | 4 | if (value=== 1) { |
121 | // cron doesn't pass month boundaries, so if 1st is a | |
122 | // weekend then we need to use 2nd or 3rd instead | |
123 | 1 | add(curSched, 'D', 1, 3); |
124 | 1 | add(curSched, 'd', NAMES.MON, NAMES.FRI); |
125 | 1 | add(except1, 'D', 2, 2); |
126 | 1 | add(except1, 'd', NAMES.TUE, NAMES.FRI); |
127 | 1 | add(except2, 'D', 3, 3); |
128 | 1 | add(except2, 'd', NAMES.TUE, NAMES.FRI); |
129 | } else { | |
130 | // normally you want the closest day, so if v is a | |
131 | // Saturday, use the previous Friday. If it's a | |
132 | // sunday, use the following Monday. | |
133 | 3 | add(curSched, 'D', value-1, value+1); |
134 | 3 | add(curSched, 'd', NAMES.MON, NAMES.FRI); |
135 | 3 | add(except1, 'D', value-1, value-1); |
136 | 3 | add(except1, 'd', NAMES.MON, NAMES.THU); |
137 | 3 | add(except2, 'D', value+1, value+1); |
138 | 3 | add(except2, 'd', NAMES.TUE, NAMES.FRI); |
139 | } | |
140 | 4 | s.exceptions.push(except1); |
141 | 4 | s.exceptions.push(except2); |
142 | } | |
143 | ||
144 | /** | |
145 | * Adds a range item (of the form x-y/z) to the schedule. | |
146 | * | |
147 | * @param {String} item: The cron expression item to add | |
148 | * @param {Schedule} curSched: The current schedule to add to | |
149 | * @param {String} name: The name to use for this constraint | |
150 | * @param {Int} min: The min value for the constraint | |
151 | * @param {Int} max: The max value for the constraint | |
152 | * @param {Int} offset: The offset to apply to the cron value | |
153 | */ | |
154 | 87 | function addRange(item, curSched, name, min, max, offset) { |
155 | // parse range/x | |
156 | 36 | var incSplit = item.split('/'), |
157 | inc = +incSplit[1], | |
158 | range = incSplit[0]; | |
159 | ||
160 | // parse x-y or * or 0 | |
161 | 36 | if (range !== '*' && range !== '0') { |
162 | 24 | var rangeSplit = range.split('-'); |
163 | 24 | min = getValue(rangeSplit[0], offset); |
164 | ||
165 | // fix for issue #13, range may be single digit | |
166 | 24 | max = getValue(rangeSplit[1], offset) || max; |
167 | } | |
168 | 36 | add(curSched, name, min, max, inc); |
169 | } | |
170 | ||
171 | /** | |
172 | * Parses a particular item within a cron expression. | |
173 | * | |
174 | * @param {String} item: The cron expression item to parse | |
175 | * @param {Schedule} s: The existing set of schedules | |
176 | * @param {String} name: The name to use for this constraint | |
177 | * @param {Int} min: The min value for the constraint | |
178 | * @param {Int} max: The max value for the constraint | |
179 | * @param {Int} offset: The offset to apply to the cron value | |
180 | */ | |
181 | 87 | function parse(item, s, name, min, max, offset) { |
182 | 153 | var value, |
183 | split, | |
184 | schedules = s.schedules, | |
185 | curSched = schedules[schedules.length-1]; | |
186 | ||
187 | // L just means min - 1 (this also makes it work for any field) | |
188 | 153 | if (item === 'L') { |
189 | 2 | item = min - 1; |
190 | } | |
191 | ||
192 | // parse x | |
193 | 153 | if ((value = getValue(item, offset)) !== null) { |
194 | 99 | add(curSched, name, value, value); |
195 | } | |
196 | // parse xW | |
197 | 54 | else if ((value = getValue(item.replace('W', ''), offset)) !== null) { |
198 | 4 | addWeekday(s, curSched, value); |
199 | } | |
200 | // parse xL | |
201 | 50 | else if ((value = getValue(item.replace('L', ''), offset)) !== null) { |
202 | 6 | addHash(schedules, curSched, value, min-1); |
203 | } | |
204 | // parse x#y | |
205 | 44 | else if ((split = item.split('#')).length === 2) { |
206 | 8 | value = getValue(split[0], offset); |
207 | 8 | addHash(schedules, curSched, value, getValue(split[1])); |
208 | } | |
209 | // parse x-y or x-y/z or */z or 0/z | |
210 | else { | |
211 | 36 | addRange(item, curSched, name, min, max, offset); |
212 | } | |
213 | } | |
214 | ||
215 | /** | |
216 | * Returns true if the item is either of the form x#y or xL. | |
217 | * | |
218 | * @param {String} item: The expression item to check | |
219 | */ | |
220 | 87 | function isHash(item) { |
221 | 33 | return item.indexOf('#') > -1 || item.indexOf('L') > 0; |
222 | } | |
223 | ||
224 | ||
225 | 87 | function itemSorter(a,b) { |
226 | 28 | return isHash(a) && !isHash(b) ? 1 : 0; |
227 | } | |
228 | ||
229 | /** | |
230 | * Parses each of the fields in a cron expression. The expression must | |
231 | * include the seconds field, the year field is optional. | |
232 | * | |
233 | * @param {String} expr: The cron expression to parse | |
234 | */ | |
235 | 87 | function parseExpr(expr) { |
236 | 87 | var schedule = {schedules: [{}], exceptions: []}, |
237 | components = expr.split(' '), | |
238 | field, f, component, items; | |
239 | ||
240 | 87 | for(field in FIELDS) { |
241 | 609 | f = FIELDS[field]; |
242 | 609 | component = components[f[0]]; |
243 | 609 | if (component && component !== '*' && component !== '?') { |
244 | // need to sort so that any #'s come last, otherwise | |
245 | // schedule clones to handle # won't contain all of the | |
246 | // other constraints | |
247 | 125 | items = component.split(',').sort(itemSorter); |
248 | 125 | var i, length = items.length; |
249 | 125 | for (i = 0; i < length; i++) { |
250 | 153 | parse(items[i], schedule, field, f[1], f[2], f[3]); |
251 | } | |
252 | } | |
253 | } | |
254 | ||
255 | 87 | return schedule; |
256 | } | |
257 | ||
258 | 87 | var e = expr.toUpperCase(); |
259 | 87 | return parseExpr(hasSeconds ? e : '0 ' + e); |
260 | }; |
Line | Hits | Source |
---|---|---|
1 | 1 | later.parse = {}; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Simple API for generating valid schedules for Later.js. All commands | |
3 | * are chainable. | |
4 | * | |
5 | * Example: | |
6 | * | |
7 | * Every 5 minutes between minutes 15 and 45 of each hour and also | |
8 | * at 9:00 am every day, except in the months of January and February | |
9 | * | |
10 | * recur().every(5).minute().between(15, 45).and().at('09:00:00') | |
11 | * .except().on(0, 1).month(); | |
12 | */ | |
13 | 1 | later.parse.recur = function () { |
14 | ||
15 | 154 | var schedules = [], |
16 | exceptions = [], | |
17 | cur, | |
18 | curArr = schedules, | |
19 | curName, | |
20 | values, every, modifier, applyMin, applyMax, i, last; | |
21 | ||
22 | /** | |
23 | * Adds values to the specified constraint in the current schedule. | |
24 | * | |
25 | * @param {String} name: Name of constraint to add | |
26 | * @param {Int} min: Minimum value for this constraint | |
27 | * @param {Int} max: Maximum value for this constraint | |
28 | */ | |
29 | 154 | function add(name, min, max) { |
30 | 240 | name = modifier ? name + '_' + modifier : name; |
31 | ||
32 | 240 | if (!cur) { |
33 | 162 | curArr.push({}); |
34 | 162 | cur = curArr[0]; |
35 | } | |
36 | ||
37 | 240 | if (!cur[name]) { |
38 | 229 | cur[name] = []; |
39 | } | |
40 | ||
41 | 240 | curName = cur[name]; |
42 | ||
43 | 240 | if (every) { |
44 | 50 | values = []; |
45 | 50 | for (i = min; i <= max; i += every) { |
46 | 782 | values.push(i); |
47 | } | |
48 | ||
49 | // save off values in case of startingOn or between | |
50 | 50 | last = {n: name, x: every, c: curName.length, m: max}; |
51 | } | |
52 | ||
53 | 240 | values = applyMin ? [min] : applyMax ? [max] : values; |
54 | 240 | var length = values.length; |
55 | 240 | for (i = 0; i < length; i += 1) { |
56 | 1024 | var val = values[i]; |
57 | 1024 | if (curName.indexOf(val) < 0) { |
58 | 1024 | curName.push(val); |
59 | } | |
60 | } | |
61 | ||
62 | // reset the built up state | |
63 | 240 | values = every = modifier = applyMin = applyMax = 0; |
64 | } | |
65 | ||
66 | 154 | return { |
67 | ||
68 | /** | |
69 | * Set of constraints that must be met for an occurrence to be valid. | |
70 | * | |
71 | * @api public | |
72 | */ | |
73 | schedules: schedules, | |
74 | ||
75 | /** | |
76 | * Set of exceptions that must not be met for an occurrence to be | |
77 | * valid. | |
78 | * | |
79 | * @api public | |
80 | */ | |
81 | exceptions: exceptions, | |
82 | ||
83 | /** | |
84 | * Specifies the specific instances of a time period that are valid. | |
85 | * Must be followed by the desired time period (minute(), hour(), | |
86 | * etc). For example, to specify a schedule for the 5th and 25th | |
87 | * minute of every hour: | |
88 | * | |
89 | * recur().on(5, 25).minute(); | |
90 | * | |
91 | * @param {Int} args: One or more valid instances | |
92 | * @api public | |
93 | */ | |
94 | on: function () { | |
95 | 108 | values = arguments[0] instanceof Array ? arguments[0] : arguments; |
96 | 108 | return this; |
97 | }, | |
98 | ||
99 | /** | |
100 | * Specifies the recurring interval of a time period that are valid. | |
101 | * Must be followed by the desired time period (minute(), hour(), | |
102 | * etc). For example, to specify a schedule for every 4 hours in the | |
103 | * day: | |
104 | * | |
105 | * recur().every(4).hour(); | |
106 | * | |
107 | * @param {Int} x: Recurring interval | |
108 | * @api public | |
109 | */ | |
110 | every: function (x) { | |
111 | 42 | every = x || 1; |
112 | 42 | return this; |
113 | }, | |
114 | ||
115 | /** | |
116 | * Specifies the minimum valid value. For example, to specify a schedule | |
117 | * that is valid for all hours after four: | |
118 | * | |
119 | * recur().after(4).hour(); | |
120 | * | |
121 | * @param {Int} x: Recurring interval | |
122 | * @api public | |
123 | */ | |
124 | after: function (x) { | |
125 | 31 | modifier = 'a'; |
126 | 31 | values = [x]; |
127 | 31 | return this; |
128 | }, | |
129 | ||
130 | /** | |
131 | * Specifies the maximum valid value. For example, to specify a schedule | |
132 | * that is valid for all hours before four: | |
133 | * | |
134 | * recur().before(4).hour(); | |
135 | * | |
136 | * @param {Int} x: Recurring interval | |
137 | * @api public | |
138 | */ | |
139 | before: function (x) { | |
140 | 29 | modifier = 'b'; |
141 | 29 | values = [x]; |
142 | 29 | return this; |
143 | }, | |
144 | ||
145 | /** | |
146 | * Specifies that the first instance of a time period is valid. Must | |
147 | * be followed by the desired time period (minute(), hour(), etc). | |
148 | * For example, to specify a schedule for the first day of every | |
149 | * month: | |
150 | * | |
151 | * recur().first().dayOfMonth(); | |
152 | * | |
153 | * @api public | |
154 | */ | |
155 | first: function () { | |
156 | 8 | applyMin = 1; |
157 | 8 | return this; |
158 | }, | |
159 | ||
160 | /** | |
161 | * Specifies that the last instance of a time period is valid. Must | |
162 | * be followed by the desired time period (minute(), hour(), etc). | |
163 | * For example, to specify a schedule for the last day of every year: | |
164 | * | |
165 | * recur().last().dayOfYear(); | |
166 | * | |
167 | * @api public | |
168 | */ | |
169 | last: function () { | |
170 | 11 | applyMax = 1; |
171 | 11 | return this; |
172 | }, | |
173 | ||
174 | /** | |
175 | * Specifies a specific time that is valid. Time must be specified in | |
176 | * hh:mm:ss format using 24 hour time. For example, to specify | |
177 | * a schedule for 8:30 pm every day: | |
178 | * | |
179 | * recur().time('20:30:00'); | |
180 | * | |
181 | * @param {String} time: Time in hh:mm:ss 24-hour format | |
182 | * @api public | |
183 | */ | |
184 | time: function () { | |
185 | //values = arguments; | |
186 | 47 | for (var i = 0, len = values.length; i < len; i++) { |
187 | 48 | var split = values[i].split(':'); |
188 | 92 | if(split.length < 3) split.push(0); |
189 | 48 | values[i] = (+split[0]) * 3600 + (+split[1]) * 60 + (+split[2]); |
190 | } | |
191 | ||
192 | 47 | add('t'); |
193 | 47 | return this; |
194 | }, | |
195 | ||
196 | /** | |
197 | * Seconds time period, denotes seconds within each minute. | |
198 | * Minimum value is 0, maximum value is 59. Specify 59 for last. | |
199 | * | |
200 | * recur().on(5, 15, 25).second(); | |
201 | * | |
202 | * @api public | |
203 | */ | |
204 | second: function () { | |
205 | 21 | add('s', 0, 59); |
206 | 21 | return this; |
207 | }, | |
208 | ||
209 | /** | |
210 | * Minutes time period, denotes minutes within each hour. | |
211 | * Minimum value is 0, maximum value is 59. Specify 59 for last. | |
212 | * | |
213 | * recur().on(5, 15, 25).minute(); | |
214 | * | |
215 | * @api public | |
216 | */ | |
217 | minute: function () { | |
218 | 48 | add('m', 0, 59); |
219 | 48 | return this; |
220 | }, | |
221 | ||
222 | /** | |
223 | * Hours time period, denotes hours within each day. | |
224 | * Minimum value is 0, maximum value is 23. Specify 23 for last. | |
225 | * | |
226 | * recur().on(5, 15, 25).hour(); | |
227 | * | |
228 | * @api public | |
229 | */ | |
230 | hour: function () { | |
231 | 12 | add('h', 0, 23); |
232 | 12 | return this; |
233 | }, | |
234 | ||
235 | /** | |
236 | * Days of month time period, denotes number of days within a month. | |
237 | * Minimum value is 1, maximum value is 31. Specify 0 for last. | |
238 | * | |
239 | * recur().every(2).dayOfMonth(); | |
240 | * | |
241 | * @api public | |
242 | */ | |
243 | dayOfMonth: function () { | |
244 | 20 | add('D', 1, applyMax ? 0 : 31); |
245 | 20 | return this; |
246 | }, | |
247 | ||
248 | /** | |
249 | * Days of week time period, denotes the days within a week. | |
250 | * Minimum value is 1, maximum value is 7. Specify 0 for last. | |
251 | * 1 - Sunday | |
252 | * 2 - Monday | |
253 | * 3 - Tuesday | |
254 | * 4 - Wednesday | |
255 | * 5 - Thursday | |
256 | * 6 - Friday | |
257 | * 7 - Saturday | |
258 | * | |
259 | * recur().on(1).dayOfWeek(); | |
260 | * | |
261 | * @api public | |
262 | */ | |
263 | dayOfWeek: function () { | |
264 | 27 | add('d', 1, 7); |
265 | 27 | return this; |
266 | }, | |
267 | ||
268 | /** | |
269 | * Short hand for on(1,7).dayOfWeek() | |
270 | * | |
271 | * @api public | |
272 | */ | |
273 | onWeekend: function() { | |
274 | 1 | values = [1,7]; |
275 | 1 | return this.dayOfWeek(); |
276 | }, | |
277 | ||
278 | /** | |
279 | * Short hand for on(2,3,4,5,6).dayOfWeek() | |
280 | * | |
281 | * @api public | |
282 | */ | |
283 | onWeekday: function() { | |
284 | 2 | values = [2,3,4,5,6]; |
285 | 2 | return this.dayOfWeek(); |
286 | }, | |
287 | ||
288 | /** | |
289 | * Days of week count time period, denotes the number of times a | |
290 | * particular day has occurred within a month. Used to specify | |
291 | * things like second Tuesday, or third Friday in a month. | |
292 | * Minimum value is 1, maximum value is 5. Specify 0 for last. | |
293 | * 1 - First occurrence | |
294 | * 2 - Second occurrence | |
295 | * 3 - Third occurrence | |
296 | * 4 - Fourth occurrence | |
297 | * 5 - Fifth occurrence | |
298 | * 0 - Last occurrence | |
299 | * | |
300 | * recur().on(1).dayOfWeek().on(1).dayOfWeekCount(); | |
301 | * | |
302 | * @api public | |
303 | */ | |
304 | dayOfWeekCount: function () { | |
305 | 6 | add('dc', 1, applyMax ? 0 : 5); |
306 | 6 | return this; |
307 | }, | |
308 | ||
309 | /** | |
310 | * Days of year time period, denotes number of days within a year. | |
311 | * Minimum value is 1, maximum value is 366. Specify 0 for last. | |
312 | * | |
313 | * recur().every(2).dayOfYear(); | |
314 | * | |
315 | * @api public | |
316 | */ | |
317 | dayOfYear: function () { | |
318 | 4 | add('dy', 1, applyMax ? 0 : 366); |
319 | 4 | return this; |
320 | }, | |
321 | ||
322 | /** | |
323 | * Weeks of month time period, denotes number of weeks within a | |
324 | * month. The first week is the week that includes the 1st of the | |
325 | * month. Subsequent weeks start on Sunday. | |
326 | * Minimum value is 1, maximum value is 5. Specify 0 for last. | |
327 | * February 2nd, 2012 - Week 1 | |
328 | * February 5th, 2012 - Week 2 | |
329 | * February 12th, 2012 - Week 3 | |
330 | * February 19th, 2012 - Week 4 | |
331 | * February 26th, 2012 - Week 5 (or 0) | |
332 | * | |
333 | * recur().on(2).weekOfMonth(); | |
334 | * | |
335 | * @api public | |
336 | */ | |
337 | weekOfMonth: function () { | |
338 | 5 | add('wm', 1, applyMax ? 0 : 5); |
339 | 5 | return this; |
340 | }, | |
341 | ||
342 | /** | |
343 | * Weeks of year time period, denotes the ISO 8601 week date. For | |
344 | * more information see: http://en.wikipedia.org/wiki/ISO_week_date. | |
345 | * Minimum value is 1, maximum value is 53. Specify 0 for last. | |
346 | * | |
347 | * recur().every(2).weekOfYear(); | |
348 | * | |
349 | * @api public | |
350 | */ | |
351 | weekOfYear: function () { | |
352 | 12 | add('wy', 1, applyMax ? 0 : 53); |
353 | 12 | return this; |
354 | }, | |
355 | ||
356 | /** | |
357 | * Month time period, denotes the months within a year. | |
358 | * Minimum value is 1, maximum value is 12. Specify 0 for last. | |
359 | * 1 - January | |
360 | * 2 - February | |
361 | * 3 - March | |
362 | * 4 - April | |
363 | * 5 - May | |
364 | * 6 - June | |
365 | * 7 - July | |
366 | * 8 - August | |
367 | * 9 - September | |
368 | * 10 - October | |
369 | * 11 - November | |
370 | * 12 - December | |
371 | * | |
372 | * recur().on(1).dayOfWeek(); | |
373 | * | |
374 | * @api public | |
375 | */ | |
376 | month: function () { | |
377 | 17 | add('M', 1, 12); |
378 | 17 | return this; |
379 | }, | |
380 | ||
381 | /** | |
382 | * Year time period, denotes the four digit year. | |
383 | * Minimum value is 1970, maximum value is Jan 1, 2100 (arbitrary) | |
384 | * | |
385 | * recur().on(2011, 2012, 2013).year(); | |
386 | * | |
387 | * @api public | |
388 | */ | |
389 | year: function () { | |
390 | 11 | add('Y', 1970, 2450); |
391 | 11 | return this; |
392 | }, | |
393 | ||
394 | /** | |
395 | * Full date period, denotes a full date and time. | |
396 | * Minimum value is Jan 1, 1970, maximum value is Jan 1, 2100 (arbitrary) | |
397 | * | |
398 | * recur().on(new Date(2013, 3, 2, 10, 30, 0)).fullDate(); | |
399 | * | |
400 | * @api public | |
401 | */ | |
402 | fullDate: function () { | |
403 | 2 | for (var i = 0, len = values.length; i < len; i++) { |
404 | 2 | values[i] = values[i].getTime(); |
405 | } | |
406 | ||
407 | 2 | add('fd'); |
408 | 2 | return this; |
409 | }, | |
410 | ||
411 | /** | |
412 | * Custom modifier. | |
413 | * | |
414 | * recur().on(2011, 2012, 2013).custom('partOfDay'); | |
415 | * | |
416 | * @api public | |
417 | */ | |
418 | customModifier: function (id, vals) { | |
419 | 0 | var custom = later.modifier[id]; |
420 | 0 | if(!custom) throw new Error('Custom modifier ' + id + ' not recognized!'); |
421 | ||
422 | 0 | modifier = id; |
423 | 0 | values = arguments[1] instanceof Array ? arguments[1] : [arguments[1]]; |
424 | 0 | return this; |
425 | }, | |
426 | ||
427 | /** | |
428 | * Custom time period. | |
429 | * | |
430 | * recur().on(2011, 2012, 2013).customPeriod('partOfDay'); | |
431 | * | |
432 | * @api public | |
433 | */ | |
434 | customPeriod: function (id) { | |
435 | 0 | var custom = later[id]; |
436 | 0 | if(!custom) throw new Error('Custom time period ' + id + ' not recognized!'); |
437 | ||
438 | 0 | add(id, custom.extent(new Date())[0], custom.extent(new Date())[1]); |
439 | 0 | return this; |
440 | }, | |
441 | ||
442 | /** | |
443 | * Modifies a recurring interval (specified using every) to start | |
444 | * at a given offset. To create a schedule for every 5 minutes | |
445 | * starting on the 6th minute - making minutes 6, 11, 16, etc valid: | |
446 | * | |
447 | * recur().every(5).minute().startingOn(6); | |
448 | * | |
449 | * @param {Int} start: The desired starting offset | |
450 | * @api public | |
451 | */ | |
452 | startingOn: function (start) { | |
453 | 4 | return this.between(start, last.m); |
454 | }, | |
455 | ||
456 | /** | |
457 | * Modifies a recurring interval (specified using every) to start | |
458 | * and stop at specified times. To create a schedule for every | |
459 | * 5 minutes starting on the 6th minute and ending on the 11th | |
460 | * minute - making minutes 6 and 11 valid: | |
461 | * | |
462 | * recur().every(5).minute().between(6, 11); | |
463 | * | |
464 | * @param {Int} start: The desired starting offset | |
465 | * @param {Int} end: The last valid value | |
466 | * @api public | |
467 | */ | |
468 | between: function (start, end) { | |
469 | // remove the values added as part of specifying the last | |
470 | // time period and replace them with the new restricted values | |
471 | 8 | cur[last.n] = cur[last.n].splice(0, last.c); |
472 | 8 | every = last.x; |
473 | 8 | add(last.n, start, end); |
474 | 8 | return this; |
475 | }, | |
476 | ||
477 | /** | |
478 | * Creates a composite schedule. With a composite schedule, a valid | |
479 | * occurrence of any of the component schedules is considered a valid | |
480 | * value for the composite schedule (e.g. they are OR'ed together). | |
481 | * To create a schedule for every 5 minutes on Mondays and every 10 | |
482 | * minutes on Tuesdays: | |
483 | * | |
484 | * recur().every(5).minutes().on(1).dayOfWeek().and().every(10) | |
485 | * .minutes().on(2).dayOfWeek(); | |
486 | * | |
487 | * @api public | |
488 | */ | |
489 | and: function () { | |
490 | 15 | cur = curArr[curArr.push({}) - 1]; |
491 | 15 | return this; |
492 | }, | |
493 | ||
494 | /** | |
495 | * Creates exceptions to a schedule. Any valid occurrence of the | |
496 | * exception schedule (which may also be composite schedules) is | |
497 | * considered a invalid schedule occurrence. Everything that follows | |
498 | * except will be treated as an exception schedule. To create a | |
499 | * schedule for 8:00 am every Tuesday except for patch Tuesday | |
500 | * (second Tuesday each month): | |
501 | * | |
502 | * recur().at('08:00:00').on(2).dayOfWeek().except() | |
503 | * .dayOfWeekCount(1); | |
504 | * | |
505 | * @api public | |
506 | */ | |
507 | except: function () { | |
508 | 10 | curArr = exceptions; |
509 | 10 | cur = null; |
510 | 10 | return this; |
511 | } | |
512 | }; | |
513 | }; |
Line | Hits | Source |
---|---|---|
1 | /** | |
2 | * Parses an English string expression and produces a schedule that is | |
3 | * compatible with Later.js. | |
4 | * | |
5 | * Examples: | |
6 | * | |
7 | * every 5 minutes between the 1st and 30th minute | |
8 | * at 10:00 am on tues of may in 2012 | |
9 | * on the 15-20th day of march-dec | |
10 | * every 20 seconds every 5 minutes every 4 hours between the 10th and 20th hour | |
11 | */ | |
12 | 1 | later.parse.text = function(str) { |
13 | ||
14 | 95 | var recur = later.parse.recur, |
15 | pos = 0, | |
16 | input = '', | |
17 | error; | |
18 | ||
19 | // Regex expressions for all of the valid tokens | |
20 | 95 | var TOKENTYPES = { |
21 | eof: /^$/, | |
22 | rank: /^((\d\d\d\d)|([2-5]?1(st)?|[2-5]?2(nd)?|[2-5]?3(rd)?|(0|[1-5]?[4-9]|[1-5]0|1[1-3])(th)?))\b/, | |
23 | time: /^((([0]?[1-9]|1[0-2]):[0-5]\d(\s)?(am|pm))|(([0]?\d|1\d|2[0-3]):[0-5]\d))\b/, | |
24 | dayName: /^((sun|mon|tue(s)?|wed(nes)?|thu(r(s)?)?|fri|sat(ur)?)(day)?)\b/, | |
25 | monthName: /^(jan(uary)?|feb(ruary)?|ma((r(ch)?)?|y)|apr(il)?|ju(ly|ne)|aug(ust)?|oct(ober)?|(sept|nov|dec)(ember)?)\b/, | |
26 | yearIndex: /^(\d\d\d\d)\b/, | |
27 | every: /^every\b/, | |
28 | after: /^after\b/, | |
29 | before: /^before\b/, | |
30 | second: /^(s|sec(ond)?(s)?)\b/, | |
31 | minute: /^(m|min(ute)?(s)?)\b/, | |
32 | hour: /^(h|hour(s)?)\b/, | |
33 | day: /^(day(s)?( of the month)?)\b/, | |
34 | dayInstance: /^day instance\b/, | |
35 | dayOfWeek: /^day(s)? of the week\b/, | |
36 | dayOfYear: /^day(s)? of the year\b/, | |
37 | weekOfYear: /^week(s)?( of the year)?\b/, | |
38 | weekOfMonth: /^week(s)? of the month\b/, | |
39 | weekday: /^weekday\b/, | |
40 | weekend: /^weekend\b/, | |
41 | month: /^month(s)?\b/, | |
42 | year: /^year(s)?\b/, | |
43 | between: /^between (the)?\b/, | |
44 | start: /^(start(ing)? (at|on( the)?)?)\b/, | |
45 | at: /^(at|@)\b/, | |
46 | and: /^(,|and\b)/, | |
47 | except: /^(except\b)/, | |
48 | also: /(also)\b/, | |
49 | first: /^(first)\b/, | |
50 | last: /^last\b/, | |
51 | "in": /^in\b/, | |
52 | of: /^of\b/, | |
53 | onthe: /^on the\b/, | |
54 | on: /^on\b/, | |
55 | through: /(-|^(to|through)\b)/ | |
56 | }; | |
57 | ||
58 | // Array to convert string names to valid numerical values | |
59 | 95 | var NAMES = { jan: 1, feb: 2, mar: 3, apr: 4, may: 5, jun: 6, jul: 7, |
60 | aug: 8, sep: 9, oct: 10, nov: 11, dec: 12, sun: 1, mon: 2, tue: 3, | |
61 | wed: 4, thu: 5, fri: 6, sat: 7, '1st': 1, fir: 1, '2nd': 2, sec: 2, | |
62 | '3rd': 3, thi: 3, '4th': 4, 'for': 4 | |
63 | }; | |
64 | ||
65 | /** | |
66 | * Bundles up the results of the peek operation into a token. | |
67 | * | |
68 | * @param {Int} start: The start position of the token | |
69 | * @param {Int} end: The end position of the token | |
70 | * @param {String} text: The actual text that was parsed | |
71 | * @param {TokenType} type: The TokenType of the token | |
72 | */ | |
73 | 95 | function t(start, end, text, type) { |
74 | 1980 | return {startPos: start, endPos: end, text: text, type: type}; |
75 | } | |
76 | ||
77 | /** | |
78 | * Peeks forward to see if the next token is the expected token and | |
79 | * returns the token if found. Pos is not moved during a Peek operation. | |
80 | * | |
81 | * @param {TokenType} exepected: The types of token to scan for | |
82 | */ | |
83 | 95 | function peek(expected) { |
84 | 658 | var scanTokens = expected instanceof Array ? expected : [expected], |
85 | whiteSpace = /\s+/, | |
86 | token, curInput, m, scanToken, start, len; | |
87 | ||
88 | 658 | scanTokens.push(whiteSpace); |
89 | ||
90 | // loop past any skipped tokens and only look for expected tokens | |
91 | 658 | start = pos; |
92 | 658 | while (!token || token.type === whiteSpace) { |
93 | 1112 | len = -1; |
94 | 1112 | curInput = input.substring(start); |
95 | 1112 | token = t(start, start, input.split(whiteSpace)[0]); |
96 | ||
97 | 1112 | var i, length = scanTokens.length; |
98 | 1112 | for(i = 0; i < length; i++) { |
99 | 5424 | scanToken = scanTokens[i]; |
100 | 5424 | m = scanToken.exec(curInput); |
101 | 5424 | if (m && m.index === 0 && m[0].length > len) { |
102 | 868 | len = m[0].length; |
103 | 868 | token = t(start, start + len, curInput.substring(0, len), scanToken); |
104 | } | |
105 | } | |
106 | ||
107 | // update the start position if this token should be skipped | |
108 | 1112 | if (token.type === whiteSpace) { |
109 | 454 | start = token.endPos; |
110 | } | |
111 | } | |
112 | ||
113 | 658 | return token; |
114 | } | |
115 | ||
116 | /** | |
117 | * Moves pos to the end of the expectedToken if it is found. | |
118 | * | |
119 | * @param {TokenType} exepectedToken: The types of token to scan for | |
120 | */ | |
121 | 95 | function scan(expectedToken) { |
122 | 376 | var token = peek(expectedToken); |
123 | 376 | pos = token.endPos; |
124 | 376 | return token; |
125 | } | |
126 | ||
127 | /** | |
128 | * Parses the next 'y-z' expression and returns the resulting valid | |
129 | * value array. | |
130 | * | |
131 | * @param {TokenType} tokenType: The type of range values allowed | |
132 | */ | |
133 | 95 | function parseThroughExpr(tokenType) { |
134 | 44 | var start = +parseTokenValue(tokenType), |
135 | end = checkAndParse(TOKENTYPES.through) ? +parseTokenValue(tokenType) : start, | |
136 | nums = []; | |
137 | ||
138 | 44 | for (var i = start; i <= end; i++) { |
139 | 62 | nums.push(i); |
140 | } | |
141 | ||
142 | 44 | return nums; |
143 | } | |
144 | ||
145 | /** | |
146 | * Parses the next 'x,y-z' expression and returns the resulting valid | |
147 | * value array. | |
148 | * | |
149 | * @param {TokenType} tokenType: The type of range values allowed | |
150 | */ | |
151 | 95 | function parseRanges(tokenType) { |
152 | 35 | var nums = parseThroughExpr(tokenType); |
153 | 35 | while (checkAndParse(TOKENTYPES.and)) { |
154 | 9 | nums = nums.concat(parseThroughExpr(tokenType)); |
155 | } | |
156 | 35 | return nums; |
157 | } | |
158 | ||
159 | /** | |
160 | * Parses the next 'every (weekend|weekday|x) (starting on|between)' expression. | |
161 | * | |
162 | * @param {Recur} r: The recurrence to add the expression to | |
163 | */ | |
164 | 95 | function parseEvery(r) { |
165 | 22 | var num, period, start, end; |
166 | ||
167 | 22 | if (checkAndParse(TOKENTYPES.weekend)) { |
168 | 1 | r.on(NAMES.sun,NAMES.sat).dayOfWeek(); |
169 | } | |
170 | 21 | else if (checkAndParse(TOKENTYPES.weekday)) { |
171 | 2 | r.on(NAMES.mon,NAMES.tue,NAMES.wed,NAMES.thu,NAMES.fri).dayOfWeek(); |
172 | } | |
173 | else { | |
174 | 19 | num = parseTokenValue(TOKENTYPES.rank); |
175 | 19 | r.every(num); |
176 | 19 | period = parseTimePeriod(r); |
177 | ||
178 | 19 | if (checkAndParse(TOKENTYPES.start)) { |
179 | 1 | num = parseTokenValue(TOKENTYPES.rank); |
180 | 1 | r.startingOn(num); |
181 | 1 | parseToken(period.type); |
182 | } | |
183 | 18 | else if (checkAndParse(TOKENTYPES.between)) { |
184 | 1 | start = parseTokenValue(TOKENTYPES.rank); |
185 | 1 | if (checkAndParse(TOKENTYPES.and)) { |
186 | 1 | end = parseTokenValue(TOKENTYPES.rank); |
187 | 1 | r.between(start,end); |
188 | } | |
189 | } | |
190 | } | |
191 | } | |
192 | ||
193 | /** | |
194 | * Parses the next 'on the (first|last|x,y-z)' expression. | |
195 | * | |
196 | * @param {Recur} r: The recurrence to add the expression to | |
197 | */ | |
198 | 95 | function parseOnThe(r) { |
199 | 23 | if (checkAndParse(TOKENTYPES.first)) { |
200 | 1 | r.first(); |
201 | } | |
202 | 22 | else if (checkAndParse(TOKENTYPES.last)) { |
203 | 4 | r.last(); |
204 | } | |
205 | else { | |
206 | 18 | r.on(parseRanges(TOKENTYPES.rank)); |
207 | } | |
208 | ||
209 | 23 | parseTimePeriod(r); |
210 | } | |
211 | ||
212 | /** | |
213 | * Parses the schedule expression and returns the resulting schedules, | |
214 | * and exceptions. Error will return the position in the string where | |
215 | * an error occurred, will be null if no errors were found in the | |
216 | * expression. | |
217 | * | |
218 | * @param {String} str: The schedule expression to parse | |
219 | */ | |
220 | 95 | function parseScheduleExpr(str) { |
221 | 95 | pos = 0; |
222 | 95 | input = str; |
223 | 95 | error = -1; |
224 | ||
225 | 95 | var r = recur(); |
226 | 95 | while (pos < input.length && error < 0) { |
227 | ||
228 | 138 | var token = parseToken([TOKENTYPES.every, TOKENTYPES.after, TOKENTYPES.before, |
229 | TOKENTYPES.onthe, TOKENTYPES.on, TOKENTYPES.of, TOKENTYPES["in"], | |
230 | TOKENTYPES.at, TOKENTYPES.and, TOKENTYPES.except, | |
231 | TOKENTYPES.also]); | |
232 | ||
233 | 138 | switch (token.type) { |
234 | case TOKENTYPES.every: | |
235 | 22 | parseEvery(r); |
236 | 22 | break; |
237 | case TOKENTYPES.after: | |
238 | 21 | if(peek(TOKENTYPES.time).type !== undefined) { |
239 | 7 | r.after(parseTokenValue(TOKENTYPES.time)); |
240 | 7 | r.time(); |
241 | } | |
242 | else { | |
243 | 14 | r.after(parseTokenValue(TOKENTYPES.rank)); |
244 | 14 | parseTimePeriod(r); |
245 | } | |
246 | 21 | break; |
247 | case TOKENTYPES.before: | |
248 | 21 | if(peek(TOKENTYPES.time).type !== undefined) { |
249 | 7 | r.before(parseTokenValue(TOKENTYPES.time)); |
250 | 7 | r.time(); |
251 | } | |
252 | else { | |
253 | 14 | r.before(parseTokenValue(TOKENTYPES.rank)); |
254 | 14 | parseTimePeriod(r); |
255 | } | |
256 | 21 | break; |
257 | case TOKENTYPES.onthe: | |
258 | 23 | parseOnThe(r); |
259 | 23 | break; |
260 | case TOKENTYPES.on: | |
261 | 8 | r.on(parseRanges(TOKENTYPES.dayName)).dayOfWeek(); |
262 | 8 | break; |
263 | case TOKENTYPES.of: | |
264 | 5 | r.on(parseRanges(TOKENTYPES.monthName)).month(); |
265 | 5 | break; |
266 | case TOKENTYPES["in"]: | |
267 | 4 | r.on(parseRanges(TOKENTYPES.yearIndex)).year(); |
268 | 4 | break; |
269 | case TOKENTYPES.at: | |
270 | 23 | r.on(parseTokenValue(TOKENTYPES.time)).time(); |
271 | 23 | while (checkAndParse(TOKENTYPES.and)) { |
272 | 3 | r.on(parseTokenValue(TOKENTYPES.time)).time(); |
273 | } | |
274 | 23 | break; |
275 | case TOKENTYPES.and: | |
276 | 4 | break; |
277 | case TOKENTYPES.also: | |
278 | 2 | r.and(); |
279 | 2 | break; |
280 | case TOKENTYPES.except: | |
281 | 2 | r.except(); |
282 | 2 | break; |
283 | default: | |
284 | 3 | error = pos; |
285 | } | |
286 | } | |
287 | ||
288 | 95 | return {schedules: r.schedules, exceptions: r.exceptions, error: error}; |
289 | } | |
290 | ||
291 | /** | |
292 | * Parses the next token representing a time period and adds it to | |
293 | * the provided recur object. | |
294 | * | |
295 | * @param {Recur} r: The recurrence to add the time period to | |
296 | */ | |
297 | 95 | function parseTimePeriod(r) { |
298 | 70 | var timePeriod = parseToken([TOKENTYPES.second, TOKENTYPES.minute, |
299 | TOKENTYPES.hour, TOKENTYPES.dayOfYear, TOKENTYPES.dayOfWeek, | |
300 | TOKENTYPES.dayInstance, TOKENTYPES.day, TOKENTYPES.month, | |
301 | TOKENTYPES.year, TOKENTYPES.weekOfMonth, TOKENTYPES.weekOfYear]); | |
302 | ||
303 | 70 | switch (timePeriod.type) { |
304 | case TOKENTYPES.second: | |
305 | 6 | r.second(); |
306 | 6 | break; |
307 | case TOKENTYPES.minute: | |
308 | 15 | r.minute(); |
309 | 15 | break; |
310 | case TOKENTYPES.hour: | |
311 | 7 | r.hour(); |
312 | 7 | break; |
313 | case TOKENTYPES.dayOfYear: | |
314 | 3 | r.dayOfYear(); |
315 | 3 | break; |
316 | case TOKENTYPES.dayOfWeek: | |
317 | 5 | r.dayOfWeek(); |
318 | 5 | break; |
319 | case TOKENTYPES.dayInstance: | |
320 | 3 | r.dayOfWeekCount(); |
321 | 3 | break; |
322 | case TOKENTYPES.day: | |
323 | 10 | r.dayOfMonth(); |
324 | 10 | break; |
325 | case TOKENTYPES.weekOfMonth: | |
326 | 4 | r.weekOfMonth(); |
327 | 4 | break; |
328 | case TOKENTYPES.weekOfYear: | |
329 | 6 | r.weekOfYear(); |
330 | 6 | break; |
331 | case TOKENTYPES.month: | |
332 | 8 | r.month(); |
333 | 8 | break; |
334 | case TOKENTYPES.year: | |
335 | 3 | r.year(); |
336 | 3 | break; |
337 | default: | |
338 | 0 | error = pos; |
339 | } | |
340 | ||
341 | 70 | return timePeriod; |
342 | } | |
343 | ||
344 | /** | |
345 | * Checks the next token to see if it is of tokenType. Returns true if | |
346 | * it is and discards the token. Returns false otherwise. | |
347 | * | |
348 | * @param {TokenType} tokenType: The type or types of token to parse | |
349 | */ | |
350 | 95 | function checkAndParse(tokenType) { |
351 | 240 | var found = (peek(tokenType)).type === tokenType; |
352 | 240 | if (found) { |
353 | 28 | scan(tokenType); |
354 | } | |
355 | 240 | return found; |
356 | } | |
357 | ||
358 | /** | |
359 | * Parses and returns the next token. | |
360 | * | |
361 | * @param {TokenType} tokenType: The type or types of token to parse | |
362 | */ | |
363 | 95 | function parseToken(tokenType) { |
364 | 348 | var t = scan(tokenType); |
365 | 348 | if (t.type) { |
366 | 344 | t.text = convertString(t.text, tokenType); |
367 | } | |
368 | else { | |
369 | 4 | error = pos; |
370 | } | |
371 | 348 | return t; |
372 | } | |
373 | ||
374 | /** | |
375 | * Returns the text value of the token that was parsed. | |
376 | * | |
377 | * @param {TokenType} tokenType: The type of token to parse | |
378 | */ | |
379 | 95 | function parseTokenValue(tokenType) { |
380 | 139 | return (parseToken(tokenType)).text; |
381 | } | |
382 | ||
383 | /** | |
384 | * Converts a string value to a numerical value based on the type of | |
385 | * token that was parsed. | |
386 | * | |
387 | * @param {String} str: The schedule string to parse | |
388 | * @param {TokenType} tokenType: The type of token to convert | |
389 | */ | |
390 | 95 | function convertString(str, tokenType) { |
391 | 344 | var output = str; |
392 | ||
393 | 344 | switch (tokenType) { |
394 | case TOKENTYPES.time: | |
395 | 40 | var parts = str.split(/(:|am|pm)/), |
396 | hour = parts[3] === 'pm' && parts[0] < 12 ? parseInt(parts[0],10) + 12 : parts[0], | |
397 | min = parts[2].trim(); | |
398 | ||
399 | 40 | output = (hour.length === 1 ? '0' : '') + hour + ":" + min; |
400 | 40 | break; |
401 | ||
402 | case TOKENTYPES.rank: | |
403 | 74 | output = parseInt((/^\d+/.exec(str))[0],10); |
404 | 74 | break; |
405 | ||
406 | case TOKENTYPES.monthName: | |
407 | case TOKENTYPES.dayName: | |
408 | 17 | output = NAMES[str.substring(0,3)]; |
409 | 17 | break; |
410 | } | |
411 | ||
412 | 344 | return output; |
413 | } | |
414 | ||
415 | 95 | return parseScheduleExpr(str.toLowerCase()); |
416 | }; |