sugar-rails 1.2.5.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +110 -28
- data/lib/generators/sugar/build/build_generator.rb +107 -0
- data/lib/generators/sugar/install/install_generator.rb +2 -2
- data/lib/sugar/rails/version.rb +2 -2
- data/sugar-rails.gemspec +1 -1
- data/vendor/assets/javascripts/precompiled/development/array.js +1212 -0
- data/vendor/assets/javascripts/precompiled/development/core.js +329 -0
- data/vendor/assets/javascripts/precompiled/development/date.js +2179 -0
- data/vendor/assets/javascripts/precompiled/development/date_locales.js +952 -0
- data/vendor/assets/javascripts/precompiled/development/date_ranges.js +183 -0
- data/vendor/assets/javascripts/precompiled/development/es5.js +443 -0
- data/vendor/assets/javascripts/precompiled/development/function.js +222 -0
- data/vendor/assets/javascripts/{sugar-inflections.js → precompiled/development/inflections.js} +51 -162
- data/vendor/assets/javascripts/precompiled/development/language.js +383 -0
- data/vendor/assets/javascripts/precompiled/development/number.js +422 -0
- data/vendor/assets/javascripts/precompiled/development/object.js +348 -0
- data/vendor/assets/javascripts/precompiled/development/regexp.js +92 -0
- data/vendor/assets/javascripts/precompiled/development/string.js +871 -0
- data/vendor/assets/javascripts/precompiled/minified/array.js +16 -0
- data/vendor/assets/javascripts/precompiled/minified/core.js +8 -0
- data/vendor/assets/javascripts/precompiled/minified/date.js +40 -0
- data/vendor/assets/javascripts/precompiled/minified/date_locales.js +38 -0
- data/vendor/assets/javascripts/precompiled/minified/date_ranges.js +3 -0
- data/vendor/assets/javascripts/precompiled/minified/es5.js +7 -0
- data/vendor/assets/javascripts/precompiled/minified/function.js +4 -0
- data/vendor/assets/javascripts/precompiled/minified/inflections.js +11 -0
- data/vendor/assets/javascripts/precompiled/minified/language.js +19 -0
- data/vendor/assets/javascripts/precompiled/minified/number.js +5 -0
- data/vendor/assets/javascripts/precompiled/minified/object.js +6 -0
- data/vendor/assets/javascripts/precompiled/minified/regexp.js +2 -0
- data/vendor/assets/javascripts/precompiled/minified/string.js +12 -0
- data/vendor/assets/javascripts/precompiled/readme.txt +3 -0
- data/vendor/assets/javascripts/sugar-development.js +8054 -0
- data/vendor/assets/javascripts/sugar-full.js +179 -0
- data/vendor/assets/javascripts/sugar.js +111 -6211
- metadata +35 -9
- data/vendor/assets/javascripts/sugar-core.js +0 -4001
- data/vendor/assets/javascripts/sugar-dates-only.js +0 -3121
- data/vendor/assets/javascripts/sugar-dates.js +0 -2210
@@ -0,0 +1,329 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
/***
|
4
|
+
* @package Core
|
5
|
+
* @description Internal utility and common methods.
|
6
|
+
***/
|
7
|
+
|
8
|
+
|
9
|
+
// A few optimizations for Google Closure Compiler will save us a couple kb in the release script.
|
10
|
+
var object = Object, array = Array, regexp = RegExp, date = Date, string = String, number = Number, math = Math, Undefined;
|
11
|
+
|
12
|
+
// The global context
|
13
|
+
var globalContext = typeof global !== 'undefined' ? global : this;
|
14
|
+
|
15
|
+
// defineProperty exists in IE8 but will error when trying to define a property on
|
16
|
+
// native objects. IE8 does not have defineProperies, however, so this check saves a try/catch block.
|
17
|
+
var definePropertySupport = object.defineProperty && object.defineProperties;
|
18
|
+
|
19
|
+
// Class initializers and isClass type helpers
|
20
|
+
|
21
|
+
var ClassNames = 'Array,Boolean,Date,Function,Number,String,RegExp'.split(',');
|
22
|
+
|
23
|
+
var isArray = buildClassCheck(ClassNames[0]);
|
24
|
+
var isBoolean = buildClassCheck(ClassNames[1]);
|
25
|
+
var isDate = buildClassCheck(ClassNames[2]);
|
26
|
+
var isFunction = buildClassCheck(ClassNames[3]);
|
27
|
+
var isNumber = buildClassCheck(ClassNames[4]);
|
28
|
+
var isString = buildClassCheck(ClassNames[5]);
|
29
|
+
var isRegExp = buildClassCheck(ClassNames[6]);
|
30
|
+
|
31
|
+
function buildClassCheck(type) {
|
32
|
+
return function(obj) {
|
33
|
+
return isClass(obj, type);
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
function isClass(obj, str) {
|
38
|
+
return object.prototype.toString.call(obj) === '[object '+str+']';
|
39
|
+
}
|
40
|
+
|
41
|
+
function initializeClasses() {
|
42
|
+
initializeClass(object);
|
43
|
+
iterateOverObject(ClassNames, function(i,name) {
|
44
|
+
initializeClass(globalContext[name]);
|
45
|
+
});
|
46
|
+
}
|
47
|
+
|
48
|
+
function initializeClass(klass) {
|
49
|
+
if(klass['SugarMethods']) return;
|
50
|
+
defineProperty(klass, 'SugarMethods', {});
|
51
|
+
extend(klass, false, false, {
|
52
|
+
'restore': function() {
|
53
|
+
var all = arguments.length === 0, methods = multiArgs(arguments);
|
54
|
+
iterateOverObject(klass['SugarMethods'], function(name, m) {
|
55
|
+
if(all || methods.indexOf(name) > -1) {
|
56
|
+
defineProperty(m.instance ? klass.prototype : klass, name, m.method);
|
57
|
+
}
|
58
|
+
});
|
59
|
+
},
|
60
|
+
'extend': function(methods, override, instance) {
|
61
|
+
extend(klass, instance !== false, override, methods);
|
62
|
+
}
|
63
|
+
});
|
64
|
+
}
|
65
|
+
|
66
|
+
// Class extending methods
|
67
|
+
|
68
|
+
function extend(klass, instance, override, methods) {
|
69
|
+
var extendee = instance ? klass.prototype : klass, original;
|
70
|
+
initializeClass(klass);
|
71
|
+
iterateOverObject(methods, function(name, method) {
|
72
|
+
original = extendee[name];
|
73
|
+
if(typeof override === 'function') {
|
74
|
+
method = wrapNative(extendee[name], method, override);
|
75
|
+
}
|
76
|
+
if(override !== false || !extendee[name]) {
|
77
|
+
defineProperty(extendee, name, method);
|
78
|
+
}
|
79
|
+
// If the method is internal to Sugar, then store a reference so it can be restored later.
|
80
|
+
klass['SugarMethods'][name] = { instance: instance, method: method, original: original };
|
81
|
+
});
|
82
|
+
}
|
83
|
+
|
84
|
+
function extendSimilar(klass, instance, override, set, fn) {
|
85
|
+
var methods = {};
|
86
|
+
set = isString(set) ? set.split(',') : set;
|
87
|
+
set.forEach(function(name, i) {
|
88
|
+
fn(methods, name, i);
|
89
|
+
});
|
90
|
+
extend(klass, instance, override, methods);
|
91
|
+
}
|
92
|
+
|
93
|
+
function wrapNative(nativeFn, extendedFn, condition) {
|
94
|
+
return function() {
|
95
|
+
if(nativeFn && (condition === true || !condition.apply(this, arguments))) {
|
96
|
+
return nativeFn.apply(this, arguments);
|
97
|
+
} else {
|
98
|
+
return extendedFn.apply(this, arguments);
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
102
|
+
|
103
|
+
function defineProperty(target, name, method) {
|
104
|
+
if(definePropertySupport) {
|
105
|
+
object.defineProperty(target, name, { 'value': method, 'configurable': true, 'enumerable': false, 'writable': true });
|
106
|
+
} else {
|
107
|
+
target[name] = method;
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
|
112
|
+
// Argument helpers
|
113
|
+
|
114
|
+
function multiArgs(args, fn) {
|
115
|
+
var result = [], i = 0;
|
116
|
+
for(i = 0; i < args.length; i++) {
|
117
|
+
result.push(args[i]);
|
118
|
+
if(fn) fn.call(args, args[i], i);
|
119
|
+
}
|
120
|
+
return result;
|
121
|
+
}
|
122
|
+
|
123
|
+
|
124
|
+
// General helpers
|
125
|
+
|
126
|
+
function isDefined(o) {
|
127
|
+
return o !== Undefined;
|
128
|
+
}
|
129
|
+
|
130
|
+
function isUndefined(o) {
|
131
|
+
return o === Undefined;
|
132
|
+
}
|
133
|
+
|
134
|
+
|
135
|
+
// Object helpers
|
136
|
+
|
137
|
+
function isObjectPrimitive(obj) {
|
138
|
+
// Check for null
|
139
|
+
return obj && typeof obj === 'object';
|
140
|
+
}
|
141
|
+
|
142
|
+
function isObject(obj) {
|
143
|
+
// === on the constructor is not safe across iframes
|
144
|
+
return !!obj && isClass(obj, 'Object') && string(obj.constructor) === string(object);
|
145
|
+
}
|
146
|
+
|
147
|
+
function hasOwnProperty(obj, key) {
|
148
|
+
return object['hasOwnProperty'].call(obj, key);
|
149
|
+
}
|
150
|
+
|
151
|
+
function iterateOverObject(obj, fn) {
|
152
|
+
var key;
|
153
|
+
for(key in obj) {
|
154
|
+
if(!hasOwnProperty(obj, key)) continue;
|
155
|
+
if(fn.call(obj, key, obj[key]) === false) break;
|
156
|
+
}
|
157
|
+
}
|
158
|
+
|
159
|
+
function simpleMerge(target, source) {
|
160
|
+
iterateOverObject(source, function(key) {
|
161
|
+
target[key] = source[key];
|
162
|
+
});
|
163
|
+
return target;
|
164
|
+
}
|
165
|
+
|
166
|
+
// Hash definition
|
167
|
+
|
168
|
+
function Hash(obj) {
|
169
|
+
simpleMerge(this, obj);
|
170
|
+
};
|
171
|
+
|
172
|
+
Hash.prototype.constructor = object;
|
173
|
+
|
174
|
+
// Number helpers
|
175
|
+
|
176
|
+
function getRange(start, stop, fn, step) {
|
177
|
+
var arr = [], i = parseInt(start), down = step < 0;
|
178
|
+
while((!down && i <= stop) || (down && i >= stop)) {
|
179
|
+
arr.push(i);
|
180
|
+
if(fn) fn.call(this, i);
|
181
|
+
i += step || 1;
|
182
|
+
}
|
183
|
+
return arr;
|
184
|
+
}
|
185
|
+
|
186
|
+
function round(val, precision, method) {
|
187
|
+
var fn = math[method || 'round'];
|
188
|
+
var multiplier = math.pow(10, math.abs(precision || 0));
|
189
|
+
if(precision < 0) multiplier = 1 / multiplier;
|
190
|
+
return fn(val * multiplier) / multiplier;
|
191
|
+
}
|
192
|
+
|
193
|
+
function ceil(val, precision) {
|
194
|
+
return round(val, precision, 'ceil');
|
195
|
+
}
|
196
|
+
|
197
|
+
function floor(val, precision) {
|
198
|
+
return round(val, precision, 'floor');
|
199
|
+
}
|
200
|
+
|
201
|
+
function padNumber(num, place, sign, base) {
|
202
|
+
var str = math.abs(num).toString(base || 10);
|
203
|
+
str = repeatString(place - str.replace(/\.\d+/, '').length, '0') + str;
|
204
|
+
if(sign || num < 0) {
|
205
|
+
str = (num < 0 ? '-' : '+') + str;
|
206
|
+
}
|
207
|
+
return str;
|
208
|
+
}
|
209
|
+
|
210
|
+
function getOrdinalizedSuffix(num) {
|
211
|
+
if(num >= 11 && num <= 13) {
|
212
|
+
return 'th';
|
213
|
+
} else {
|
214
|
+
switch(num % 10) {
|
215
|
+
case 1: return 'st';
|
216
|
+
case 2: return 'nd';
|
217
|
+
case 3: return 'rd';
|
218
|
+
default: return 'th';
|
219
|
+
}
|
220
|
+
}
|
221
|
+
}
|
222
|
+
|
223
|
+
|
224
|
+
// String helpers
|
225
|
+
|
226
|
+
// WhiteSpace/LineTerminator as defined in ES5.1 plus Unicode characters in the Space, Separator category.
|
227
|
+
function getTrimmableCharacters() {
|
228
|
+
return '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u2028\u2029\u3000\uFEFF';
|
229
|
+
}
|
230
|
+
|
231
|
+
function repeatString(times, str) {
|
232
|
+
return array(math.max(0, isDefined(times) ? times : 1) + 1).join(str || '');
|
233
|
+
}
|
234
|
+
|
235
|
+
|
236
|
+
// RegExp helpers
|
237
|
+
|
238
|
+
function getRegExpFlags(reg, add) {
|
239
|
+
var flags = reg.toString().match(/[^/]*$/)[0];
|
240
|
+
if(add) {
|
241
|
+
flags = (flags + add).split('').sort().join('').replace(/([gimy])\1+/g, '$1');
|
242
|
+
}
|
243
|
+
return flags;
|
244
|
+
}
|
245
|
+
|
246
|
+
function escapeRegExp(str) {
|
247
|
+
if(!isString(str)) str = string(str);
|
248
|
+
return str.replace(/([\\/'*+?|()\[\]{}.^$])/g,'\\$1');
|
249
|
+
}
|
250
|
+
|
251
|
+
|
252
|
+
// Specialized helpers
|
253
|
+
|
254
|
+
|
255
|
+
// Used by Array#unique and Object.equal
|
256
|
+
|
257
|
+
function stringify(thing, stack) {
|
258
|
+
var value, klass, isObject, isArray, arr, i, key, type = typeof thing;
|
259
|
+
|
260
|
+
// Return quickly if string to save cycles
|
261
|
+
if(type === 'string') return thing;
|
262
|
+
|
263
|
+
klass = object.prototype.toString.call(thing)
|
264
|
+
isObject = klass === '[object Object]';
|
265
|
+
isArray = klass === '[object Array]';
|
266
|
+
|
267
|
+
if(thing != null && isObject || isArray) {
|
268
|
+
// This method for checking for cyclic structures was egregiously stolen from
|
269
|
+
// the ingenious method by @kitcambridge from the Underscore script:
|
270
|
+
// https://github.com/documentcloud/underscore/issues/240
|
271
|
+
if(!stack) stack = [];
|
272
|
+
// Allowing a step into the structure before triggering this
|
273
|
+
// script to save cycles on standard JSON structures and also to
|
274
|
+
// try as hard as possible to catch basic properties that may have
|
275
|
+
// been modified.
|
276
|
+
if(stack.length > 1) {
|
277
|
+
i = stack.length;
|
278
|
+
while (i--) {
|
279
|
+
if (stack[i] === thing) {
|
280
|
+
return 'CYC';
|
281
|
+
}
|
282
|
+
}
|
283
|
+
}
|
284
|
+
stack.push(thing);
|
285
|
+
value = string(thing.constructor);
|
286
|
+
arr = isArray ? thing : object.keys(thing).sort();
|
287
|
+
for(i = 0; i < arr.length; i++) {
|
288
|
+
key = isArray ? i : arr[i];
|
289
|
+
value += key + stringify(thing[key], stack);
|
290
|
+
}
|
291
|
+
stack.pop();
|
292
|
+
} else if(1 / thing === -Infinity) {
|
293
|
+
value = '-0';
|
294
|
+
} else {
|
295
|
+
value = string(thing && thing.valueOf());
|
296
|
+
}
|
297
|
+
return type + klass + value;
|
298
|
+
}
|
299
|
+
|
300
|
+
|
301
|
+
// Used by Array#at and String#at
|
302
|
+
|
303
|
+
function entryAtIndex(arr, args, str) {
|
304
|
+
var result = [], length = arr.length, loop = args[args.length - 1] !== false, r;
|
305
|
+
multiArgs(args, function(index) {
|
306
|
+
if(isBoolean(index)) return false;
|
307
|
+
if(loop) {
|
308
|
+
index = index % length;
|
309
|
+
if(index < 0) index = length + index;
|
310
|
+
}
|
311
|
+
r = str ? arr.charAt(index) || '' : arr[index];
|
312
|
+
result.push(r);
|
313
|
+
});
|
314
|
+
return result.length < 2 ? result[0] : result;
|
315
|
+
}
|
316
|
+
|
317
|
+
|
318
|
+
// Object class methods implemented as instance methods
|
319
|
+
|
320
|
+
function buildObjectInstanceMethods(set, target) {
|
321
|
+
extendSimilar(target, true, false, set, function(methods, name) {
|
322
|
+
methods[name + (name === 'equal' ? 's' : '')] = function() {
|
323
|
+
return object[name].apply(null, [this].concat(multiArgs(arguments)));
|
324
|
+
}
|
325
|
+
});
|
326
|
+
}
|
327
|
+
|
328
|
+
initializeClasses();
|
329
|
+
|
@@ -0,0 +1,2179 @@
|
|
1
|
+
|
2
|
+
/***
|
3
|
+
* @package Date
|
4
|
+
* @dependency core
|
5
|
+
* @description Date parsing and formatting, relative formats like "1 minute ago", Number methods like "daysAgo", localization support with default English locale definition.
|
6
|
+
*
|
7
|
+
***/
|
8
|
+
|
9
|
+
var English;
|
10
|
+
var CurrentLocalization;
|
11
|
+
|
12
|
+
var TimeFormat = ['ampm','hour','minute','second','ampm','utc','offset_sign','offset_hours','offset_minutes','ampm']
|
13
|
+
var FloatReg = '\\d{1,2}(?:[,.]\\d+)?';
|
14
|
+
var RequiredTime = '({t})?\\s*('+FloatReg+')(?:{h}('+FloatReg+')?{m}(?::?('+FloatReg+'){s})?\\s*(?:({t})|(Z)|(?:([+-])(\\d{2,2})(?::?(\\d{2,2}))?)?)?|\\s*({t}))';
|
15
|
+
|
16
|
+
var KanjiDigits = '〇一二三四五六七八九十百千万';
|
17
|
+
var FullWidthDigits = '0123456789';
|
18
|
+
var AsianDigitMap = {};
|
19
|
+
var AsianDigitReg;
|
20
|
+
|
21
|
+
var DateArgumentUnits;
|
22
|
+
var DateUnitsReversed;
|
23
|
+
var CoreDateFormats = [];
|
24
|
+
|
25
|
+
var DateOutputFormats = [
|
26
|
+
{
|
27
|
+
token: 'f{1,4}|ms|milliseconds',
|
28
|
+
format: function(d) {
|
29
|
+
return d.getMilliseconds();
|
30
|
+
}
|
31
|
+
},
|
32
|
+
{
|
33
|
+
token: 'ss?|seconds',
|
34
|
+
format: function(d, len) {
|
35
|
+
return d.getSeconds();
|
36
|
+
}
|
37
|
+
},
|
38
|
+
{
|
39
|
+
token: 'mm?|minutes',
|
40
|
+
format: function(d, len) {
|
41
|
+
return d.getMinutes();
|
42
|
+
}
|
43
|
+
},
|
44
|
+
{
|
45
|
+
token: 'hh?|hours|12hr',
|
46
|
+
format: function(d) {
|
47
|
+
return getShortHour(d);
|
48
|
+
}
|
49
|
+
},
|
50
|
+
{
|
51
|
+
token: 'HH?|24hr',
|
52
|
+
format: function(d) {
|
53
|
+
return d.getHours();
|
54
|
+
}
|
55
|
+
},
|
56
|
+
{
|
57
|
+
token: 'dd?|date|day',
|
58
|
+
format: function(d) {
|
59
|
+
return d.getDate();
|
60
|
+
}
|
61
|
+
},
|
62
|
+
{
|
63
|
+
token: 'dow|weekday',
|
64
|
+
word: true,
|
65
|
+
format: function(d, loc, n, t) {
|
66
|
+
return loc['weekdays'][d.getDay() + (n - 1) * 7];
|
67
|
+
}
|
68
|
+
},
|
69
|
+
{
|
70
|
+
token: 'MM?',
|
71
|
+
format: function(d) {
|
72
|
+
return d.getMonth() + 1;
|
73
|
+
}
|
74
|
+
},
|
75
|
+
{
|
76
|
+
token: 'mon|month',
|
77
|
+
word: true,
|
78
|
+
format: function(d, loc, n, len) {
|
79
|
+
return loc['months'][d.getMonth() + (n - 1) * 12];
|
80
|
+
}
|
81
|
+
},
|
82
|
+
{
|
83
|
+
token: 'y{2,4}|year',
|
84
|
+
format: function(d) {
|
85
|
+
return d.getFullYear();
|
86
|
+
}
|
87
|
+
},
|
88
|
+
{
|
89
|
+
token: '[Tt]{1,2}',
|
90
|
+
format: function(d, loc, n, format) {
|
91
|
+
var str = loc['ampm'][floor(d.getHours() / 12)];
|
92
|
+
if(format.length === 1) str = str.slice(0,1);
|
93
|
+
if(format.slice(0,1) === 'T') str = str.toUpperCase();
|
94
|
+
return str;
|
95
|
+
}
|
96
|
+
},
|
97
|
+
{
|
98
|
+
token: 'z{1,4}|tz|timezone',
|
99
|
+
text: true,
|
100
|
+
format: function(d, loc, n, format) {
|
101
|
+
var tz = d.getUTCOffset();
|
102
|
+
if(format == 'z' || format == 'zz') {
|
103
|
+
tz = tz.replace(/(\d{2})(\d{2})/, function(f,h,m) {
|
104
|
+
return padNumber(h, format.length);
|
105
|
+
});
|
106
|
+
}
|
107
|
+
return tz;
|
108
|
+
}
|
109
|
+
},
|
110
|
+
{
|
111
|
+
token: 'iso(tz|timezone)',
|
112
|
+
format: function(d) {
|
113
|
+
return d.getUTCOffset(true);
|
114
|
+
}
|
115
|
+
},
|
116
|
+
{
|
117
|
+
token: 'ord',
|
118
|
+
format: function(d) {
|
119
|
+
var d = d.getDate();
|
120
|
+
return d + getOrdinalizedSuffix(d);
|
121
|
+
}
|
122
|
+
}
|
123
|
+
];
|
124
|
+
|
125
|
+
var DateUnits = [
|
126
|
+
{
|
127
|
+
unit: 'year',
|
128
|
+
method: 'FullYear',
|
129
|
+
multiplier: function(d) {
|
130
|
+
var adjust = d ? (d.isLeapYear() ? 1 : 0) : 0.25;
|
131
|
+
return (365 + adjust) * 24 * 60 * 60 * 1000;
|
132
|
+
}
|
133
|
+
},
|
134
|
+
{
|
135
|
+
unit: 'month',
|
136
|
+
method: 'Month',
|
137
|
+
ambiguous: true,
|
138
|
+
multiplier: function(d, ms) {
|
139
|
+
var days = 30.4375, inMonth;
|
140
|
+
if(d) {
|
141
|
+
inMonth = d.daysInMonth();
|
142
|
+
if(ms <= inMonth.days()) {
|
143
|
+
days = inMonth;
|
144
|
+
}
|
145
|
+
}
|
146
|
+
return days * 24 * 60 * 60 * 1000;
|
147
|
+
}
|
148
|
+
},
|
149
|
+
{
|
150
|
+
unit: 'week',
|
151
|
+
method: 'Week',
|
152
|
+
multiplier: function() {
|
153
|
+
return 7 * 24 * 60 * 60 * 1000;
|
154
|
+
}
|
155
|
+
},
|
156
|
+
{
|
157
|
+
unit: 'day',
|
158
|
+
method: 'Date',
|
159
|
+
ambiguous: true,
|
160
|
+
multiplier: function() {
|
161
|
+
return 24 * 60 * 60 * 1000;
|
162
|
+
}
|
163
|
+
},
|
164
|
+
{
|
165
|
+
unit: 'hour',
|
166
|
+
method: 'Hours',
|
167
|
+
multiplier: function() {
|
168
|
+
return 60 * 60 * 1000;
|
169
|
+
}
|
170
|
+
},
|
171
|
+
{
|
172
|
+
unit: 'minute',
|
173
|
+
method: 'Minutes',
|
174
|
+
multiplier: function() {
|
175
|
+
return 60 * 1000;
|
176
|
+
}
|
177
|
+
},
|
178
|
+
{
|
179
|
+
unit: 'second',
|
180
|
+
method: 'Seconds',
|
181
|
+
multiplier: function() {
|
182
|
+
return 1000;
|
183
|
+
}
|
184
|
+
},
|
185
|
+
{
|
186
|
+
unit: 'millisecond',
|
187
|
+
method: 'Milliseconds',
|
188
|
+
multiplier: function() {
|
189
|
+
return 1;
|
190
|
+
}
|
191
|
+
}
|
192
|
+
];
|
193
|
+
|
194
|
+
|
195
|
+
|
196
|
+
|
197
|
+
// Date Localization
|
198
|
+
|
199
|
+
var Localizations = {};
|
200
|
+
|
201
|
+
// Localization object
|
202
|
+
|
203
|
+
function Localization(l) {
|
204
|
+
simpleMerge(this, l);
|
205
|
+
this.compiledFormats = CoreDateFormats.concat();
|
206
|
+
}
|
207
|
+
|
208
|
+
Localization.prototype = {
|
209
|
+
|
210
|
+
getMonth: function(n) {
|
211
|
+
if(isNumber(n)) {
|
212
|
+
return n - 1;
|
213
|
+
} else {
|
214
|
+
return this['months'].indexOf(n) % 12;
|
215
|
+
}
|
216
|
+
},
|
217
|
+
|
218
|
+
getWeekday: function(n) {
|
219
|
+
return this['weekdays'].indexOf(n) % 7;
|
220
|
+
},
|
221
|
+
|
222
|
+
getNumber: function(n) {
|
223
|
+
var i;
|
224
|
+
if(isNumber(n)) {
|
225
|
+
return n;
|
226
|
+
} else if(n && (i = this['numbers'].indexOf(n)) !== -1) {
|
227
|
+
return (i + 1) % 10;
|
228
|
+
} else {
|
229
|
+
return 1;
|
230
|
+
}
|
231
|
+
},
|
232
|
+
|
233
|
+
getNumericDate: function(n) {
|
234
|
+
var self = this;
|
235
|
+
return n.replace(regexp(this['num'], 'g'), function(d) {
|
236
|
+
var num = self.getNumber(d);
|
237
|
+
return num || '';
|
238
|
+
});
|
239
|
+
},
|
240
|
+
|
241
|
+
getEnglishUnit: function(n) {
|
242
|
+
return English['units'][this['units'].indexOf(n) % 8];
|
243
|
+
},
|
244
|
+
|
245
|
+
relative: function(adu) {
|
246
|
+
return this.convertAdjustedToFormat(adu, adu[2] > 0 ? 'future' : 'past');
|
247
|
+
},
|
248
|
+
|
249
|
+
getDuration: function(ms) {
|
250
|
+
return this.convertAdjustedToFormat(getAdjustedUnit(ms), 'duration');
|
251
|
+
},
|
252
|
+
|
253
|
+
hasVariant: function(code) {
|
254
|
+
code = code || this.code;
|
255
|
+
return code === 'en' || code === 'en-US' ? true : this['variant'];
|
256
|
+
},
|
257
|
+
|
258
|
+
matchPM: function(str) {
|
259
|
+
return str === this['ampm'][1];
|
260
|
+
},
|
261
|
+
|
262
|
+
convertAdjustedToFormat: function(adu, format) {
|
263
|
+
var num = adu[0], u = adu[1], ms = adu[2], sign, unit, last, mult;
|
264
|
+
if(this['code'] == 'ru') {
|
265
|
+
last = num.toString().slice(-1);
|
266
|
+
switch(true) {
|
267
|
+
case last == 1: mult = 1; break;
|
268
|
+
case last >= 2 && last <= 4: mult = 2; break;
|
269
|
+
default: mult = 3;
|
270
|
+
}
|
271
|
+
} else {
|
272
|
+
mult = this['plural'] && num > 1 ? 1 : 0;
|
273
|
+
}
|
274
|
+
unit = this['units'][mult * 8 + u] || this['units'][u];
|
275
|
+
if(this['capitalizeUnit']) unit = simpleCapitalize(unit);
|
276
|
+
sign = this['modifiers'].filter(function(m) { return m.name == 'sign' && m.value == (ms > 0 ? 1 : -1); })[0];
|
277
|
+
return this[format].replace(/\{(.*?)\}/g, function(full, match) {
|
278
|
+
switch(match) {
|
279
|
+
case 'num': return num;
|
280
|
+
case 'unit': return unit;
|
281
|
+
case 'sign': return sign.src;
|
282
|
+
}
|
283
|
+
});
|
284
|
+
},
|
285
|
+
|
286
|
+
getFormats: function() {
|
287
|
+
return this.cachedFormat ? [this.cachedFormat].concat(this.compiledFormats) : this.compiledFormats;
|
288
|
+
},
|
289
|
+
|
290
|
+
addFormat: function(src, allowsTime, match, variant, iso) {
|
291
|
+
var to = match || [], loc = this, time, timeMarkers, lastIsNumeral;
|
292
|
+
|
293
|
+
src = src.replace(/\s+/g, '[-,. ]*');
|
294
|
+
src = src.replace(/\{([^,]+?)\}/g, function(all, k) {
|
295
|
+
var opt = k.match(/\?$/), slice = k.match(/(\d)(?:-(\d))?/), nc = k.match(/^\d+$/), key = k.replace(/[^a-z]+$/, ''), value, arr;
|
296
|
+
if(nc) {
|
297
|
+
value = loc['optionals'][nc[0]];
|
298
|
+
} else if(loc[key]) {
|
299
|
+
value = loc[key];
|
300
|
+
} else if(loc[key + 's']) {
|
301
|
+
value = loc[key + 's'];
|
302
|
+
if(slice) {
|
303
|
+
// Can't use filter here as Prototype hijacks the method and doesn't
|
304
|
+
// pass an index, so use a simple loop instead!
|
305
|
+
arr = [];
|
306
|
+
value.forEach(function(m, i) {
|
307
|
+
var mod = i % (loc['units'] ? 8 : value.length);
|
308
|
+
if(mod >= slice[1] && mod <= (slice[2] || slice[1])) {
|
309
|
+
arr.push(m);
|
310
|
+
}
|
311
|
+
});
|
312
|
+
value = arr;
|
313
|
+
}
|
314
|
+
value = arrayToAlternates(value);
|
315
|
+
}
|
316
|
+
if(nc) {
|
317
|
+
return '(?:' + value + ')?';
|
318
|
+
} else {
|
319
|
+
if(!match) {
|
320
|
+
to.push(key);
|
321
|
+
}
|
322
|
+
return '(' + value + ')' + (opt ? '?' : '');
|
323
|
+
}
|
324
|
+
});
|
325
|
+
if(allowsTime) {
|
326
|
+
time = prepareTime(RequiredTime, loc, iso);
|
327
|
+
timeMarkers = ['t','[\\s\\u3000]'].concat(loc['timeMarker']);
|
328
|
+
lastIsNumeral = src.match(/\\d\{\d,\d\}\)+\??$/);
|
329
|
+
addDateInputFormat(loc, '(?:' + time + ')[,\\s\\u3000]+?' + src, TimeFormat.concat(to), variant);
|
330
|
+
addDateInputFormat(loc, src + '(?:[,\\s]*(?:' + timeMarkers.join('|') + (lastIsNumeral ? '+' : '*') +')' + time + ')?', to.concat(TimeFormat), variant);
|
331
|
+
} else {
|
332
|
+
addDateInputFormat(loc, src, to, variant);
|
333
|
+
}
|
334
|
+
}
|
335
|
+
|
336
|
+
};
|
337
|
+
|
338
|
+
|
339
|
+
// Localization helpers
|
340
|
+
|
341
|
+
function getLocalization(localeCode, fallback) {
|
342
|
+
var loc;
|
343
|
+
if(!isString(localeCode)) localeCode = '';
|
344
|
+
loc = Localizations[localeCode] || Localizations[localeCode.slice(0,2)];
|
345
|
+
if(fallback === false && !loc) {
|
346
|
+
throw new Error('Invalid locale.');
|
347
|
+
}
|
348
|
+
return loc || CurrentLocalization;
|
349
|
+
}
|
350
|
+
|
351
|
+
function setLocalization(localeCode, set) {
|
352
|
+
var loc;
|
353
|
+
|
354
|
+
function initializeField(name) {
|
355
|
+
var val = loc[name];
|
356
|
+
if(isString(val)) {
|
357
|
+
loc[name] = val.split(',');
|
358
|
+
} else if(!val) {
|
359
|
+
loc[name] = [];
|
360
|
+
}
|
361
|
+
}
|
362
|
+
|
363
|
+
function eachAlternate(str, fn) {
|
364
|
+
str = str.split('+').map(function(split) {
|
365
|
+
return split.replace(/(.+):(.+)$/, function(full, base, suffixes) {
|
366
|
+
return suffixes.split('|').map(function(suffix) {
|
367
|
+
return base + suffix;
|
368
|
+
}).join('|');
|
369
|
+
});
|
370
|
+
}).join('|');
|
371
|
+
return str.split('|').forEach(fn);
|
372
|
+
}
|
373
|
+
|
374
|
+
function setArray(name, abbreviate, multiple) {
|
375
|
+
var arr = [];
|
376
|
+
if(!loc[name]) return;
|
377
|
+
loc[name].forEach(function(el, i) {
|
378
|
+
eachAlternate(el, function(str, j) {
|
379
|
+
arr[j * multiple + i] = str.toLowerCase();
|
380
|
+
});
|
381
|
+
});
|
382
|
+
if(abbreviate) arr = arr.concat(loc[name].map(function(str) {
|
383
|
+
return str.slice(0,3).toLowerCase();
|
384
|
+
}));
|
385
|
+
return loc[name] = arr;
|
386
|
+
}
|
387
|
+
|
388
|
+
function getDigit(start, stop, allowNumbers) {
|
389
|
+
var str = '\\d{' + start + ',' + stop + '}';
|
390
|
+
if(allowNumbers) str += '|(?:' + arrayToAlternates(loc['numbers']) + ')+';
|
391
|
+
return str;
|
392
|
+
}
|
393
|
+
|
394
|
+
function getNum() {
|
395
|
+
var arr = ['\\d+'].concat(loc['articles']);
|
396
|
+
if(loc['numbers']) arr = arr.concat(loc['numbers']);
|
397
|
+
return arrayToAlternates(arr);
|
398
|
+
}
|
399
|
+
|
400
|
+
function setModifiers() {
|
401
|
+
var arr = [];
|
402
|
+
loc.modifiersByName = {};
|
403
|
+
loc['modifiers'].forEach(function(modifier) {
|
404
|
+
var name = modifier.name;
|
405
|
+
eachAlternate(modifier.src, function(t) {
|
406
|
+
var locEntry = loc[name];
|
407
|
+
loc.modifiersByName[t] = modifier;
|
408
|
+
arr.push({ name: name, src: t, value: modifier.value });
|
409
|
+
loc[name] = locEntry ? locEntry + '|' + t : t;
|
410
|
+
});
|
411
|
+
});
|
412
|
+
loc['day'] += '|' + arrayToAlternates(loc['weekdays']);
|
413
|
+
loc['modifiers'] = arr;
|
414
|
+
}
|
415
|
+
|
416
|
+
// Initialize the locale
|
417
|
+
loc = new Localization(set);
|
418
|
+
initializeField('modifiers');
|
419
|
+
'months,weekdays,units,numbers,articles,optionals,timeMarker,ampm,timeSuffixes,dateParse,timeParse'.split(',').forEach(initializeField);
|
420
|
+
|
421
|
+
setArray('months', true, 12);
|
422
|
+
setArray('weekdays', true, 7);
|
423
|
+
setArray('units', false, 8);
|
424
|
+
setArray('numbers', false, 10);
|
425
|
+
|
426
|
+
loc['code'] = localeCode;
|
427
|
+
loc['date'] = getDigit(1,2, loc['digitDate']);
|
428
|
+
loc['year'] = getDigit(4,4);
|
429
|
+
loc['num'] = getNum();
|
430
|
+
|
431
|
+
setModifiers();
|
432
|
+
|
433
|
+
if(loc['monthSuffix']) {
|
434
|
+
loc['month'] = getDigit(1,2);
|
435
|
+
loc['months'] = getRange(1, 12).map(function(n) { return n + loc['monthSuffix']; });
|
436
|
+
}
|
437
|
+
loc['full_month'] = getDigit(1,2) + '|' + arrayToAlternates(loc['months']);
|
438
|
+
|
439
|
+
// The order of these formats is very important. Order is reversed so formats that come
|
440
|
+
// later will take precedence over formats that come before. This generally means that
|
441
|
+
// more specific formats should come later, however, the {year} format should come before
|
442
|
+
// {day}, as 2011 needs to be parsed as a year (2011) and not date (20) + hours (11)
|
443
|
+
|
444
|
+
// If the locale has time suffixes then add a time only format for that locale
|
445
|
+
// that is separate from the core English-based one.
|
446
|
+
if(loc['timeSuffixes'].length > 0) {
|
447
|
+
loc.addFormat(prepareTime(RequiredTime, loc), false, TimeFormat)
|
448
|
+
}
|
449
|
+
|
450
|
+
loc.addFormat('{day}', true);
|
451
|
+
loc.addFormat('{month}' + (loc['monthSuffix'] || ''));
|
452
|
+
loc.addFormat('{year}' + (loc['yearSuffix'] || ''));
|
453
|
+
|
454
|
+
loc['timeParse'].forEach(function(src) {
|
455
|
+
loc.addFormat(src, true);
|
456
|
+
});
|
457
|
+
|
458
|
+
loc['dateParse'].forEach(function(src) {
|
459
|
+
loc.addFormat(src);
|
460
|
+
});
|
461
|
+
|
462
|
+
return Localizations[localeCode] = loc;
|
463
|
+
}
|
464
|
+
|
465
|
+
|
466
|
+
// General helpers
|
467
|
+
|
468
|
+
function addDateInputFormat(locale, format, match, variant) {
|
469
|
+
locale.compiledFormats.unshift({
|
470
|
+
variant: variant,
|
471
|
+
locale: locale,
|
472
|
+
reg: regexp('^' + format + '$', 'i'),
|
473
|
+
to: match
|
474
|
+
});
|
475
|
+
}
|
476
|
+
|
477
|
+
function simpleCapitalize(str) {
|
478
|
+
return str.slice(0,1).toUpperCase() + str.slice(1);
|
479
|
+
}
|
480
|
+
|
481
|
+
function arrayToAlternates(arr) {
|
482
|
+
return arr.filter(function(el) {
|
483
|
+
return !!el;
|
484
|
+
}).join('|');
|
485
|
+
}
|
486
|
+
|
487
|
+
// Date argument helpers
|
488
|
+
|
489
|
+
function collectDateArguments(args, allowDuration) {
|
490
|
+
var obj, arr;
|
491
|
+
if(isObject(args[0])) {
|
492
|
+
return args;
|
493
|
+
} else if (isNumber(args[0]) && !isNumber(args[1])) {
|
494
|
+
return [args[0]];
|
495
|
+
} else if (isString(args[0]) && allowDuration) {
|
496
|
+
return [getDateParamsFromString(args[0]), args[1]];
|
497
|
+
}
|
498
|
+
obj = {};
|
499
|
+
DateArgumentUnits.forEach(function(u,i) {
|
500
|
+
obj[u.unit] = args[i];
|
501
|
+
});
|
502
|
+
return [obj];
|
503
|
+
}
|
504
|
+
|
505
|
+
function getDateParamsFromString(str, num) {
|
506
|
+
var params = {};
|
507
|
+
match = str.match(/^(\d+)?\s?(\w+?)s?$/i);
|
508
|
+
if(isUndefined(num)) {
|
509
|
+
num = parseInt(match[1]) || 1;
|
510
|
+
}
|
511
|
+
params[match[2].toLowerCase()] = num;
|
512
|
+
return params;
|
513
|
+
}
|
514
|
+
|
515
|
+
// Date parsing helpers
|
516
|
+
|
517
|
+
function getFormatMatch(match, arr) {
|
518
|
+
var obj = {}, value, num;
|
519
|
+
arr.forEach(function(key, i) {
|
520
|
+
value = match[i + 1];
|
521
|
+
if(isUndefined(value) || value === '') return;
|
522
|
+
if(key === 'year') obj.yearAsString = value;
|
523
|
+
num = parseFloat(value.replace(/,/, '.'));
|
524
|
+
obj[key] = !isNaN(num) ? num : value.toLowerCase();
|
525
|
+
});
|
526
|
+
return obj;
|
527
|
+
}
|
528
|
+
|
529
|
+
function cleanDateInput(str) {
|
530
|
+
str = str.trim().replace(/^(just )?now|\.+$/i, '');
|
531
|
+
return convertAsianDigits(str);
|
532
|
+
}
|
533
|
+
|
534
|
+
function convertAsianDigits(str) {
|
535
|
+
return str.replace(AsianDigitReg, function(full, disallowed, match) {
|
536
|
+
var sum = 0, place = 1, lastWasHolder, lastHolder;
|
537
|
+
if(disallowed) return full;
|
538
|
+
match.split('').reverse().forEach(function(letter) {
|
539
|
+
var value = AsianDigitMap[letter], holder = value > 9;
|
540
|
+
if(holder) {
|
541
|
+
if(lastWasHolder) sum += place;
|
542
|
+
place *= value / (lastHolder || 1);
|
543
|
+
lastHolder = value;
|
544
|
+
} else {
|
545
|
+
if(lastWasHolder === false) {
|
546
|
+
place *= 10;
|
547
|
+
}
|
548
|
+
sum += place * value;
|
549
|
+
}
|
550
|
+
lastWasHolder = holder;
|
551
|
+
});
|
552
|
+
if(lastWasHolder) sum += place;
|
553
|
+
return sum;
|
554
|
+
});
|
555
|
+
}
|
556
|
+
|
557
|
+
function getExtendedDate(f, localeCode, prefer) {
|
558
|
+
var d = new date(), relative = false, baseLocalization, loc, format, set, unit, weekday, num, tmp, after;
|
559
|
+
if(isDate(f)) {
|
560
|
+
d = f.clone();
|
561
|
+
} else if(isNumber(f)) {
|
562
|
+
d = new date(f);
|
563
|
+
} else if(isObject(f)) {
|
564
|
+
d = new date().set(f, true);
|
565
|
+
set = f;
|
566
|
+
} else if(isString(f)) {
|
567
|
+
|
568
|
+
// The act of getting the localization will pre-initialize
|
569
|
+
// if it is missing and add the required formats.
|
570
|
+
baseLocalization = getLocalization(localeCode);
|
571
|
+
|
572
|
+
// Clean the input and convert Kanji based numerals if they exist.
|
573
|
+
f = cleanDateInput(f);
|
574
|
+
|
575
|
+
if(baseLocalization) {
|
576
|
+
iterateOverObject(baseLocalization.getFormats(), function(i, dif) {
|
577
|
+
var match = f.match(dif.reg);
|
578
|
+
if(match) {
|
579
|
+
format = dif;
|
580
|
+
loc = format.locale;
|
581
|
+
set = getFormatMatch(match, format.to, loc);
|
582
|
+
loc.cachedFormat = format;
|
583
|
+
|
584
|
+
if(set.timestamp) {
|
585
|
+
set = set.timestamp;
|
586
|
+
return false;
|
587
|
+
}
|
588
|
+
|
589
|
+
// If there's a variant (crazy Endian American format), swap the month and day.
|
590
|
+
if(format.variant && !isString(set['month']) && (isString(set['date']) || baseLocalization.hasVariant(localeCode))) {
|
591
|
+
tmp = set['month'];
|
592
|
+
set['month'] = set['date'];
|
593
|
+
set['date'] = tmp;
|
594
|
+
}
|
595
|
+
|
596
|
+
// If the year is 2 digits then get the implied century.
|
597
|
+
if(set['year'] && set.yearAsString.length === 2) {
|
598
|
+
set['year'] = getYearFromAbbreviation(set['year']);
|
599
|
+
}
|
600
|
+
|
601
|
+
// Set the month which may be localized.
|
602
|
+
if(set['month']) {
|
603
|
+
set['month'] = loc.getMonth(set['month']);
|
604
|
+
if(set['shift'] && !set['unit']) set['unit'] = loc['units'][7];
|
605
|
+
}
|
606
|
+
|
607
|
+
// If there is both a weekday and a date, the date takes precedence.
|
608
|
+
if(set['weekday'] && set['date']) {
|
609
|
+
delete set['weekday'];
|
610
|
+
// Otherwise set a localized weekday.
|
611
|
+
} else if(set['weekday']) {
|
612
|
+
set['weekday'] = loc.getWeekday(set['weekday']);
|
613
|
+
if(set['shift'] && !set['unit']) set['unit'] = loc['units'][5];
|
614
|
+
}
|
615
|
+
|
616
|
+
// Relative day localizations such as "today" and "tomorrow".
|
617
|
+
if(set['day'] && (tmp = loc.modifiersByName[set['day']])) {
|
618
|
+
set['day'] = tmp.value;
|
619
|
+
d.reset();
|
620
|
+
relative = true;
|
621
|
+
// If the day is a weekday, then set that instead.
|
622
|
+
} else if(set['day'] && (weekday = loc.getWeekday(set['day'])) > -1) {
|
623
|
+
delete set['day'];
|
624
|
+
if(set['num'] && set['month']) {
|
625
|
+
// If we have "the 2nd tuesday of June", set the day to the beginning of the month, then
|
626
|
+
// look ahead to set the weekday after all other properties have been set. The weekday needs
|
627
|
+
// to be set after the actual set because it requires overriding the "prefer" argument which
|
628
|
+
// could unintentionally send the year into the future, past, etc.
|
629
|
+
after = function() {
|
630
|
+
updateDate(d, { 'weekday': weekday + (7 * (set['num'] - 1)) }, false, false, false, 1);
|
631
|
+
}
|
632
|
+
set['day'] = 1;
|
633
|
+
} else {
|
634
|
+
set['weekday'] = weekday;
|
635
|
+
}
|
636
|
+
}
|
637
|
+
|
638
|
+
if(set['date'] && !isNumber(set['date'])) {
|
639
|
+
set['date'] = loc.getNumericDate(set['date']);
|
640
|
+
}
|
641
|
+
|
642
|
+
// If the time is 1pm-11pm advance the time by 12 hours.
|
643
|
+
if(loc.matchPM(set['ampm']) && set['hour'] < 12) {
|
644
|
+
set['hour'] += 12;
|
645
|
+
}
|
646
|
+
|
647
|
+
// Adjust for timezone offset
|
648
|
+
if('offset_hours' in set || 'offset_minutes' in set) {
|
649
|
+
set['utc'] = true;
|
650
|
+
set['offset_minutes'] = set['offset_minutes'] || 0;
|
651
|
+
set['offset_minutes'] += set['offset_hours'] * 60;
|
652
|
+
if(set['offset_sign'] === '-') {
|
653
|
+
set['offset_minutes'] *= -1;
|
654
|
+
}
|
655
|
+
set['minute'] -= set['offset_minutes'];
|
656
|
+
}
|
657
|
+
|
658
|
+
// Date has a unit like "days", "months", etc. are all relative to the current date.
|
659
|
+
if(set['unit']) {
|
660
|
+
relative = true;
|
661
|
+
num = loc.getNumber(set['num']);
|
662
|
+
unit = loc.getEnglishUnit(set['unit']);
|
663
|
+
|
664
|
+
// Shift and unit, ie "next month", "last week", etc.
|
665
|
+
if(set['shift'] || set['edge']) {
|
666
|
+
num *= (tmp = loc.modifiersByName[set['shift']]) ? tmp.value : 0;
|
667
|
+
|
668
|
+
// Relative month and static date: "the 15th of last month"
|
669
|
+
if(unit === 'month' && isDefined(set['date'])) {
|
670
|
+
d.set({ 'day': set['date'] }, true);
|
671
|
+
delete set['date'];
|
672
|
+
}
|
673
|
+
|
674
|
+
// Relative year and static month/date: "June 15th of last year"
|
675
|
+
if(unit === 'year' && isDefined(set['month'])) {
|
676
|
+
d.set({ 'month': set['month'], 'day': set['date'] }, true);
|
677
|
+
delete set['month'];
|
678
|
+
delete set['date'];
|
679
|
+
}
|
680
|
+
}
|
681
|
+
// Unit and sign, ie "months ago", "weeks from now", etc.
|
682
|
+
if(set['sign'] && (tmp = loc.modifiersByName[set['sign']])) {
|
683
|
+
num *= tmp.value;
|
684
|
+
}
|
685
|
+
|
686
|
+
// Units can be with non-relative dates, set here. ie "the day after monday"
|
687
|
+
if(isDefined(set['weekday'])) {
|
688
|
+
d.set({'weekday': set['weekday'] }, true);
|
689
|
+
delete set['weekday'];
|
690
|
+
}
|
691
|
+
|
692
|
+
// Finally shift the unit.
|
693
|
+
set[unit] = (set[unit] || 0) + num;
|
694
|
+
}
|
695
|
+
|
696
|
+
if(set['year_sign'] === '-') {
|
697
|
+
set['year'] *= -1;
|
698
|
+
}
|
699
|
+
|
700
|
+
DateUnitsReversed.slice(1,4).forEach(function(u, i) {
|
701
|
+
var value = set[u.unit], fraction = value % 1;
|
702
|
+
if(fraction) {
|
703
|
+
set[DateUnitsReversed[i].unit] = round(fraction * (u.unit === 'second' ? 1000 : 60));
|
704
|
+
set[u.unit] = floor(value);
|
705
|
+
}
|
706
|
+
});
|
707
|
+
return false;
|
708
|
+
}
|
709
|
+
});
|
710
|
+
}
|
711
|
+
if(!format) {
|
712
|
+
// The Date constructor does something tricky like checking the number
|
713
|
+
// of arguments so simply passing in undefined won't work.
|
714
|
+
d = f ? new date(f) : new date();
|
715
|
+
} else if(relative) {
|
716
|
+
d.advance(set);
|
717
|
+
} else {
|
718
|
+
if(set['utc']) {
|
719
|
+
// UTC times can traverse into other days or even months,
|
720
|
+
// so preemtively reset the time here to prevent this.
|
721
|
+
d.reset();
|
722
|
+
}
|
723
|
+
updateDate(d, set, true, set['utc'], false, prefer);
|
724
|
+
}
|
725
|
+
|
726
|
+
// If there is an "edge" it needs to be set after the
|
727
|
+
// other fields are set. ie "the end of February"
|
728
|
+
if(set && set['edge']) {
|
729
|
+
tmp = loc.modifiersByName[set['edge']];
|
730
|
+
iterateOverObject(DateUnitsReversed.slice(4), function(i, u) {
|
731
|
+
if(isDefined(set[u.unit])) {
|
732
|
+
unit = u.unit;
|
733
|
+
return false;
|
734
|
+
}
|
735
|
+
});
|
736
|
+
if(unit === 'year') set.specificity = 'month';
|
737
|
+
else if(unit === 'month' || unit === 'week') set.specificity = 'day';
|
738
|
+
d[(tmp.value < 0 ? 'endOf' : 'beginningOf') + simpleCapitalize(unit)]();
|
739
|
+
// This value of -2 is arbitrary but it's a nice clean way to hook into this system.
|
740
|
+
if(tmp.value === -2) d.reset();
|
741
|
+
}
|
742
|
+
if(after) {
|
743
|
+
after();
|
744
|
+
}
|
745
|
+
|
746
|
+
}
|
747
|
+
return {
|
748
|
+
date: d,
|
749
|
+
set: set
|
750
|
+
}
|
751
|
+
}
|
752
|
+
|
753
|
+
// If the year is two digits, add the most appropriate century prefix.
|
754
|
+
function getYearFromAbbreviation(year) {
|
755
|
+
return round(new date().getFullYear() / 100) * 100 - round(year / 100) * 100 + year;
|
756
|
+
}
|
757
|
+
|
758
|
+
function getShortHour(d, utc) {
|
759
|
+
var hours = callDateMethod(d, 'get', utc, 'Hours');
|
760
|
+
return hours === 0 ? 12 : hours - (floor(hours / 13) * 12);
|
761
|
+
}
|
762
|
+
|
763
|
+
// weeksSince won't work here as the result needs to be floored, not rounded.
|
764
|
+
function getWeekNumber(date) {
|
765
|
+
var dow = date.getDay() || 7;
|
766
|
+
date.addDays(4 - dow).reset();
|
767
|
+
return 1 + floor(date.daysSince(date.clone().beginningOfYear()) / 7);
|
768
|
+
}
|
769
|
+
|
770
|
+
function getAdjustedUnit(ms) {
|
771
|
+
var next, ams = math.abs(ms), value = ams, unit = 0;
|
772
|
+
DateUnitsReversed.slice(1).forEach(function(u, i) {
|
773
|
+
next = floor(round(ams / u.multiplier() * 10) / 10);
|
774
|
+
if(next >= 1) {
|
775
|
+
value = next;
|
776
|
+
unit = i + 1;
|
777
|
+
}
|
778
|
+
});
|
779
|
+
return [value, unit, ms];
|
780
|
+
}
|
781
|
+
|
782
|
+
|
783
|
+
// Date formatting helpers
|
784
|
+
|
785
|
+
function formatDate(date, format, relative, localeCode) {
|
786
|
+
var adu, loc = getLocalization(localeCode), caps = regexp(/^[A-Z]/), value, shortcut;
|
787
|
+
if(!date.isValid()) {
|
788
|
+
return 'Invalid Date';
|
789
|
+
} else if(Date[format]) {
|
790
|
+
format = Date[format];
|
791
|
+
} else if(isFunction(format)) {
|
792
|
+
adu = getAdjustedUnit(date.millisecondsFromNow());
|
793
|
+
format = format.apply(date, adu.concat(loc));
|
794
|
+
}
|
795
|
+
if(!format && relative) {
|
796
|
+
adu = adu || getAdjustedUnit(date.millisecondsFromNow());
|
797
|
+
// Adjust up if time is in ms, as this doesn't
|
798
|
+
// look very good for a standard relative date.
|
799
|
+
if(adu[1] === 0) {
|
800
|
+
adu[1] = 1;
|
801
|
+
adu[0] = 1;
|
802
|
+
}
|
803
|
+
return loc.relative(adu);
|
804
|
+
}
|
805
|
+
|
806
|
+
format = format || 'long';
|
807
|
+
format = loc[format] || format;
|
808
|
+
|
809
|
+
DateOutputFormats.forEach(function(dof) {
|
810
|
+
format = format.replace(regexp('\\{('+dof.token+')(\\d)?\\}', dof.word ? 'i' : ''), function(m,t,d) {
|
811
|
+
var val = dof.format(date, loc, d || 1, t), l = t.length, one = t.match(/^(.)\1+$/);
|
812
|
+
if(dof.word) {
|
813
|
+
if(l === 3) val = val.slice(0,3);
|
814
|
+
if(one || t.match(caps)) val = simpleCapitalize(val);
|
815
|
+
} else if(one && !dof.text) {
|
816
|
+
val = (isNumber(val) ? padNumber(val, l) : val.toString()).slice(-l);
|
817
|
+
}
|
818
|
+
return val;
|
819
|
+
});
|
820
|
+
});
|
821
|
+
return format;
|
822
|
+
}
|
823
|
+
|
824
|
+
// Date comparison helpers
|
825
|
+
|
826
|
+
function compareDate(d, find, buffer) {
|
827
|
+
var p = getExtendedDate(find), accuracy = 0, loBuffer = 0, hiBuffer = 0, override, capitalized;
|
828
|
+
if(buffer > 0) {
|
829
|
+
loBuffer = hiBuffer = buffer;
|
830
|
+
override = true;
|
831
|
+
}
|
832
|
+
if(!p.date.isValid()) return false;
|
833
|
+
if(p.set && p.set.specificity) {
|
834
|
+
DateUnits.forEach(function(u, i) {
|
835
|
+
if(u.unit === p.set.specificity) {
|
836
|
+
accuracy = u.multiplier(p.date, d - p.date) - 1;
|
837
|
+
}
|
838
|
+
});
|
839
|
+
capitalized = simpleCapitalize(p.set.specificity);
|
840
|
+
if(p.set['edge'] || p.set['shift']) {
|
841
|
+
p.date['beginningOf' + capitalized]();
|
842
|
+
}
|
843
|
+
if(p.set.specificity === 'month') {
|
844
|
+
max = p.date.clone()['endOf' + capitalized]().getTime();
|
845
|
+
}
|
846
|
+
if(!override && p.set['sign'] && p.set.specificity != 'millisecond') {
|
847
|
+
// If the time is relative, there can occasionally be an disparity between the relative date
|
848
|
+
// and "now", which it is being compared to, so set an extra buffer to account for this.
|
849
|
+
loBuffer = 50;
|
850
|
+
hiBuffer = -50;
|
851
|
+
}
|
852
|
+
}
|
853
|
+
var t = d.getTime();
|
854
|
+
var min = p.date.getTime();
|
855
|
+
var max = max || (min + accuracy);
|
856
|
+
// Offset any shift that may occur as a result of DST traversal.
|
857
|
+
return t >= (min - loBuffer) && t <= (max + hiBuffer);
|
858
|
+
}
|
859
|
+
|
860
|
+
function updateDate(d, params, reset, utc, advance, prefer) {
|
861
|
+
var weekday;
|
862
|
+
|
863
|
+
function getParam(key) {
|
864
|
+
return isDefined(params[key]) ? params[key] : params[key + 's'];
|
865
|
+
}
|
866
|
+
|
867
|
+
function paramExists(key) {
|
868
|
+
return isDefined(getParam(key));
|
869
|
+
}
|
870
|
+
|
871
|
+
function canDisambiguate(u, higherUnit) {
|
872
|
+
return prefer && u.ambiguous && !paramExists(higherUnit.unit);
|
873
|
+
}
|
874
|
+
|
875
|
+
if(isNumber(params) && advance) {
|
876
|
+
// If param is a number and we're advancing, the number is presumed to be milliseconds.
|
877
|
+
params = { 'milliseconds': params };
|
878
|
+
} else if(isNumber(params)) {
|
879
|
+
// Otherwise just set the timestamp and return.
|
880
|
+
d.setTime(params);
|
881
|
+
return d;
|
882
|
+
}
|
883
|
+
|
884
|
+
// "date" can also be passed for the day
|
885
|
+
if(params['date']) params['day'] = params['date'];
|
886
|
+
|
887
|
+
// Reset any unit lower than the least specific unit set. Do not do this for weeks
|
888
|
+
// or for years. This needs to be performed before the acutal setting of the date
|
889
|
+
// because the order needs to be reversed in order to get the lowest specificity,
|
890
|
+
// also because higher order units can be overwritten by lower order units, such
|
891
|
+
// as setting hour: 3, minute: 345, etc.
|
892
|
+
iterateOverObject(DateUnitsReversed, function(i,u) {
|
893
|
+
var isDay = u.unit === 'day';
|
894
|
+
if(paramExists(u.unit) || (isDay && paramExists('weekday'))) {
|
895
|
+
params.specificity = u.unit;
|
896
|
+
return false;
|
897
|
+
} else if(reset && u.unit !== 'week' && (!isDay || !paramExists('week'))) {
|
898
|
+
// Days are relative to months, not weeks, so don't reset if a week exists.
|
899
|
+
callDateMethod(d, 'set', utc, u.method, (isDay ? 1 : 0));
|
900
|
+
}
|
901
|
+
});
|
902
|
+
|
903
|
+
// Now actually set or advance the date in order, higher units first.
|
904
|
+
DateUnits.forEach(function(u,i) {
|
905
|
+
var unit = u.unit, method = u.method, higherUnit = DateUnits[i - 1], value;
|
906
|
+
value = getParam(unit)
|
907
|
+
if(isUndefined(value)) return;
|
908
|
+
if(canDisambiguate(u, higherUnit)) {
|
909
|
+
// Formats like "June" have an ambiguous year. If no preference is stated, this
|
910
|
+
// is fine as "June of this year", however in a future context, this would mean
|
911
|
+
// "the next June", which may be either this year or next year. If we have an
|
912
|
+
// ambiguity *and* a preference for resolving it, then advance or rewind the
|
913
|
+
// higher order as necessary. Note that weekdays are handled differently below.
|
914
|
+
var current = callDateMethod(new date, 'get', utc, u.method);
|
915
|
+
if(current >= value === (prefer === 1)) {
|
916
|
+
d[higherUnit.addMethod](prefer);
|
917
|
+
}
|
918
|
+
}
|
919
|
+
if(advance) {
|
920
|
+
if(unit === 'week') {
|
921
|
+
value = (params['day'] || 0) + (value * 7);
|
922
|
+
method = 'Date';
|
923
|
+
}
|
924
|
+
value = (value * advance) + callDateMethod(d, 'get', false, method);
|
925
|
+
} else if(unit === 'month' && paramExists('day')) {
|
926
|
+
// When setting the month, there is a chance that we will traverse into a new month.
|
927
|
+
// This happens in DST shifts, for example June 1st DST jumping to January 1st
|
928
|
+
// (non-DST) will have a shift of -1:00 which will traverse into the previous year.
|
929
|
+
// Prevent this by proactively setting the day when we know it will be set again anyway.
|
930
|
+
// It can also happen when there are not enough days in the target month. This second
|
931
|
+
// situation is identical to checkMonthTraversal below, however when we are advancing
|
932
|
+
// we want to reset the date to "the last date in the target month". In the case of
|
933
|
+
// DST shifts, however, we want to avoid the "edges" of months as that is where this
|
934
|
+
// unintended traversal can happen. This is the reason for the different handling of
|
935
|
+
// two similar but slightly different situations.
|
936
|
+
//
|
937
|
+
// TL;DR This method avoids the edges of a month IF not advancing and the date is going
|
938
|
+
// to be set anyway, while checkMonthTraversal resets the date to the last day if advancing.
|
939
|
+
//
|
940
|
+
d.setDate(15);
|
941
|
+
}
|
942
|
+
callDateMethod(d, 'set', utc, method, value);
|
943
|
+
if(advance && unit === 'month') {
|
944
|
+
checkMonthTraversal(d, value);
|
945
|
+
}
|
946
|
+
});
|
947
|
+
|
948
|
+
// If a weekday is included in the params, set it ahead of time and set the params
|
949
|
+
// to reflect the updated date so that resetting works properly.
|
950
|
+
if(!advance && !paramExists('day') && paramExists('weekday')) {
|
951
|
+
var weekday = getParam('weekday'), isAhead, futurePreferred;
|
952
|
+
if(isDefined(prefer)) {
|
953
|
+
// If there is a preference as to whether this weekday is in the future,
|
954
|
+
// then add an offset as needed. NOTE: Was previously doing something much
|
955
|
+
// more one-liner-hipster here, but it made Opera choke (order of operations
|
956
|
+
// bug??) ... better to be more explicit here anyway.
|
957
|
+
isAhead = callDateMethod(d, 'get', utc, 'Day') - (weekday % 7) >= 0;
|
958
|
+
futurePreferred = prefer === 1;
|
959
|
+
if(isAhead === futurePreferred) {
|
960
|
+
weekday += prefer * 7;
|
961
|
+
}
|
962
|
+
}
|
963
|
+
callDateMethod(d, 'set', utc, 'Weekday', weekday)
|
964
|
+
}
|
965
|
+
return d;
|
966
|
+
}
|
967
|
+
|
968
|
+
function callDateMethod(d, prefix, utc, method, value) {
|
969
|
+
return d[prefix + (utc ? 'UTC' : '') + method](value);
|
970
|
+
}
|
971
|
+
|
972
|
+
// The ISO format allows times strung together without a demarcating ":", so make sure
|
973
|
+
// that these markers are now optional.
|
974
|
+
function prepareTime(format, loc, iso) {
|
975
|
+
var timeSuffixMapping = {'h':0,'m':1,'s':2}, add;
|
976
|
+
loc = loc || English;
|
977
|
+
return format.replace(/{([a-z])}/g, function(full, token) {
|
978
|
+
var separators = [],
|
979
|
+
isHours = token === 'h',
|
980
|
+
tokenIsRequired = isHours && !iso;
|
981
|
+
if(token === 't') {
|
982
|
+
return loc['ampm'].join('|');
|
983
|
+
} else {
|
984
|
+
if(isHours) {
|
985
|
+
separators.push(':');
|
986
|
+
}
|
987
|
+
if(add = loc['timeSuffixes'][timeSuffixMapping[token]]) {
|
988
|
+
separators.push(add + '\\s*');
|
989
|
+
}
|
990
|
+
return separators.length === 0 ? '' : '(?:' + separators.join('|') + ')' + (tokenIsRequired ? '' : '?');
|
991
|
+
}
|
992
|
+
});
|
993
|
+
}
|
994
|
+
|
995
|
+
|
996
|
+
// If the month is being set, then we don't want to accidentally
|
997
|
+
// traverse into a new month just because the target month doesn't have enough
|
998
|
+
// days. In other words, "5 months ago" from July 30th is still February, even
|
999
|
+
// though there is no February 30th, so it will of necessity be February 28th
|
1000
|
+
// (or 29th in the case of a leap year).
|
1001
|
+
|
1002
|
+
function checkMonthTraversal(date, targetMonth) {
|
1003
|
+
if(targetMonth < 0) targetMonth += 12;
|
1004
|
+
if(targetMonth % 12 != date.getMonth()) {
|
1005
|
+
date.setDate(0);
|
1006
|
+
}
|
1007
|
+
}
|
1008
|
+
|
1009
|
+
function createDate(args, prefer) {
|
1010
|
+
var f;
|
1011
|
+
if(isNumber(args[1])) {
|
1012
|
+
// If the second argument is a number, then we have an enumerated constructor type as in "new Date(2003, 2, 12);"
|
1013
|
+
f = collectDateArguments(args)[0];
|
1014
|
+
} else {
|
1015
|
+
f = args[0];
|
1016
|
+
}
|
1017
|
+
return getExtendedDate(f, args[1], prefer).date;
|
1018
|
+
}
|
1019
|
+
|
1020
|
+
function buildDateUnits() {
|
1021
|
+
DateUnitsReversed = DateUnits.concat().reverse();
|
1022
|
+
DateArgumentUnits = DateUnits.concat();
|
1023
|
+
DateArgumentUnits.splice(2,1);
|
1024
|
+
}
|
1025
|
+
|
1026
|
+
|
1027
|
+
/***
|
1028
|
+
* @method [units]Since([d], [locale] = currentLocale)
|
1029
|
+
* @returns Number
|
1030
|
+
* @short Returns the time since [d] in the appropriate unit.
|
1031
|
+
* @extra [d] will accept a date object, timestamp, or text format. If not specified, [d] is assumed to be now. [locale] can be passed to specify the locale that the date is in. %[unit]Ago% is provided as an alias to make this more readable when [d] is assumed to be the current date. For more see @date_format.
|
1032
|
+
*
|
1033
|
+
* @set
|
1034
|
+
* millisecondsSince
|
1035
|
+
* secondsSince
|
1036
|
+
* minutesSince
|
1037
|
+
* hoursSince
|
1038
|
+
* daysSince
|
1039
|
+
* weeksSince
|
1040
|
+
* monthsSince
|
1041
|
+
* yearsSince
|
1042
|
+
*
|
1043
|
+
* @example
|
1044
|
+
*
|
1045
|
+
* Date.create().millisecondsSince('1 hour ago') -> 3,600,000
|
1046
|
+
* Date.create().daysSince('1 week ago') -> 7
|
1047
|
+
* Date.create().yearsSince('15 years ago') -> 15
|
1048
|
+
* Date.create('15 years ago').yearsAgo() -> 15
|
1049
|
+
*
|
1050
|
+
***
|
1051
|
+
* @method [units]Ago()
|
1052
|
+
* @returns Number
|
1053
|
+
* @short Returns the time ago in the appropriate unit.
|
1054
|
+
*
|
1055
|
+
* @set
|
1056
|
+
* millisecondsAgo
|
1057
|
+
* secondsAgo
|
1058
|
+
* minutesAgo
|
1059
|
+
* hoursAgo
|
1060
|
+
* daysAgo
|
1061
|
+
* weeksAgo
|
1062
|
+
* monthsAgo
|
1063
|
+
* yearsAgo
|
1064
|
+
*
|
1065
|
+
* @example
|
1066
|
+
*
|
1067
|
+
* Date.create('last year').millisecondsAgo() -> 3,600,000
|
1068
|
+
* Date.create('last year').daysAgo() -> 7
|
1069
|
+
* Date.create('last year').yearsAgo() -> 15
|
1070
|
+
*
|
1071
|
+
***
|
1072
|
+
* @method [units]Until([d], [locale] = currentLocale)
|
1073
|
+
* @returns Number
|
1074
|
+
* @short Returns the time until [d] in the appropriate unit.
|
1075
|
+
* @extra [d] will accept a date object, timestamp, or text format. If not specified, [d] is assumed to be now. [locale] can be passed to specify the locale that the date is in. %[unit]FromNow% is provided as an alias to make this more readable when [d] is assumed to be the current date. For more see @date_format.
|
1076
|
+
*
|
1077
|
+
* @set
|
1078
|
+
* millisecondsUntil
|
1079
|
+
* secondsUntil
|
1080
|
+
* minutesUntil
|
1081
|
+
* hoursUntil
|
1082
|
+
* daysUntil
|
1083
|
+
* weeksUntil
|
1084
|
+
* monthsUntil
|
1085
|
+
* yearsUntil
|
1086
|
+
*
|
1087
|
+
* @example
|
1088
|
+
*
|
1089
|
+
* Date.create().millisecondsUntil('1 hour from now') -> 3,600,000
|
1090
|
+
* Date.create().daysUntil('1 week from now') -> 7
|
1091
|
+
* Date.create().yearsUntil('15 years from now') -> 15
|
1092
|
+
* Date.create('15 years from now').yearsFromNow() -> 15
|
1093
|
+
*
|
1094
|
+
***
|
1095
|
+
* @method [units]FromNow()
|
1096
|
+
* @returns Number
|
1097
|
+
* @short Returns the time from now in the appropriate unit.
|
1098
|
+
*
|
1099
|
+
* @set
|
1100
|
+
* millisecondsFromNow
|
1101
|
+
* secondsFromNow
|
1102
|
+
* minutesFromNow
|
1103
|
+
* hoursFromNow
|
1104
|
+
* daysFromNow
|
1105
|
+
* weeksFromNow
|
1106
|
+
* monthsFromNow
|
1107
|
+
* yearsFromNow
|
1108
|
+
*
|
1109
|
+
* @example
|
1110
|
+
*
|
1111
|
+
* Date.create('next year').millisecondsFromNow() -> 3,600,000
|
1112
|
+
* Date.create('next year').daysFromNow() -> 7
|
1113
|
+
* Date.create('next year').yearsFromNow() -> 15
|
1114
|
+
*
|
1115
|
+
***
|
1116
|
+
* @method add[Units](<num>, [reset] = false)
|
1117
|
+
* @returns Date
|
1118
|
+
* @short Adds <num> of the unit to the date. If [reset] is true, all lower units will be reset.
|
1119
|
+
* @extra Note that "months" is ambiguous as a unit of time. If the target date falls on a day that does not exist (ie. August 31 -> February 31), the date will be shifted to the last day of the month. Don't use %addMonths% if you need precision.
|
1120
|
+
*
|
1121
|
+
* @set
|
1122
|
+
* addMilliseconds
|
1123
|
+
* addSeconds
|
1124
|
+
* addMinutes
|
1125
|
+
* addHours
|
1126
|
+
* addDays
|
1127
|
+
* addWeeks
|
1128
|
+
* addMonths
|
1129
|
+
* addYears
|
1130
|
+
*
|
1131
|
+
* @example
|
1132
|
+
*
|
1133
|
+
* Date.create().addMilliseconds(5) -> current time + 5 milliseconds
|
1134
|
+
* Date.create().addDays(5) -> current time + 5 days
|
1135
|
+
* Date.create().addYears(5) -> current time + 5 years
|
1136
|
+
*
|
1137
|
+
***
|
1138
|
+
* @method isLast[Unit]()
|
1139
|
+
* @returns Boolean
|
1140
|
+
* @short Returns true if the date is last week/month/year.
|
1141
|
+
*
|
1142
|
+
* @set
|
1143
|
+
* isLastWeek
|
1144
|
+
* isLastMonth
|
1145
|
+
* isLastYear
|
1146
|
+
*
|
1147
|
+
* @example
|
1148
|
+
*
|
1149
|
+
* Date.create('yesterday').isLastWeek() -> true or false?
|
1150
|
+
* Date.create('yesterday').isLastMonth() -> probably not...
|
1151
|
+
* Date.create('yesterday').isLastYear() -> even less likely...
|
1152
|
+
*
|
1153
|
+
***
|
1154
|
+
* @method isThis[Unit]()
|
1155
|
+
* @returns Boolean
|
1156
|
+
* @short Returns true if the date is this week/month/year.
|
1157
|
+
*
|
1158
|
+
* @set
|
1159
|
+
* isThisWeek
|
1160
|
+
* isThisMonth
|
1161
|
+
* isThisYear
|
1162
|
+
*
|
1163
|
+
* @example
|
1164
|
+
*
|
1165
|
+
* Date.create('tomorrow').isThisWeek() -> true or false?
|
1166
|
+
* Date.create('tomorrow').isThisMonth() -> probably...
|
1167
|
+
* Date.create('tomorrow').isThisYear() -> signs point to yes...
|
1168
|
+
*
|
1169
|
+
***
|
1170
|
+
* @method isNext[Unit]()
|
1171
|
+
* @returns Boolean
|
1172
|
+
* @short Returns true if the date is next week/month/year.
|
1173
|
+
*
|
1174
|
+
* @set
|
1175
|
+
* isNextWeek
|
1176
|
+
* isNextMonth
|
1177
|
+
* isNextYear
|
1178
|
+
*
|
1179
|
+
* @example
|
1180
|
+
*
|
1181
|
+
* Date.create('tomorrow').isNextWeek() -> true or false?
|
1182
|
+
* Date.create('tomorrow').isNextMonth() -> probably not...
|
1183
|
+
* Date.create('tomorrow').isNextYear() -> even less likely...
|
1184
|
+
*
|
1185
|
+
***
|
1186
|
+
* @method beginningOf[Unit]()
|
1187
|
+
* @returns Date
|
1188
|
+
* @short Sets the date to the beginning of the appropriate unit.
|
1189
|
+
*
|
1190
|
+
* @set
|
1191
|
+
* beginningOfDay
|
1192
|
+
* beginningOfWeek
|
1193
|
+
* beginningOfMonth
|
1194
|
+
* beginningOfYear
|
1195
|
+
*
|
1196
|
+
* @example
|
1197
|
+
*
|
1198
|
+
* Date.create().beginningOfDay() -> the beginning of today (resets the time)
|
1199
|
+
* Date.create().beginningOfWeek() -> the beginning of the week
|
1200
|
+
* Date.create().beginningOfMonth() -> the beginning of the month
|
1201
|
+
* Date.create().beginningOfYear() -> the beginning of the year
|
1202
|
+
*
|
1203
|
+
***
|
1204
|
+
* @method endOf[Unit]()
|
1205
|
+
* @returns Date
|
1206
|
+
* @short Sets the date to the end of the appropriate unit.
|
1207
|
+
*
|
1208
|
+
* @set
|
1209
|
+
* endOfDay
|
1210
|
+
* endOfWeek
|
1211
|
+
* endOfMonth
|
1212
|
+
* endOfYear
|
1213
|
+
*
|
1214
|
+
* @example
|
1215
|
+
*
|
1216
|
+
* Date.create().endOfDay() -> the end of today (sets the time to 23:59:59.999)
|
1217
|
+
* Date.create().endOfWeek() -> the end of the week
|
1218
|
+
* Date.create().endOfMonth() -> the end of the month
|
1219
|
+
* Date.create().endOfYear() -> the end of the year
|
1220
|
+
*
|
1221
|
+
***/
|
1222
|
+
|
1223
|
+
function buildDateMethods() {
|
1224
|
+
extendSimilar(date, true, false, DateUnits, function(methods, u, i) {
|
1225
|
+
var unit = u.unit, caps = simpleCapitalize(unit), multiplier = u.multiplier(), since, until;
|
1226
|
+
u.addMethod = 'add' + caps + 's';
|
1227
|
+
since = function(f, localeCode) {
|
1228
|
+
return round((this.getTime() - date.create(f, localeCode).getTime()) / multiplier);
|
1229
|
+
};
|
1230
|
+
until = function(f, localeCode) {
|
1231
|
+
return round((date.create(f, localeCode).getTime() - this.getTime()) / multiplier);
|
1232
|
+
};
|
1233
|
+
methods[unit+'sAgo'] = until;
|
1234
|
+
methods[unit+'sUntil'] = until;
|
1235
|
+
methods[unit+'sSince'] = since;
|
1236
|
+
methods[unit+'sFromNow'] = since;
|
1237
|
+
methods[u.addMethod] = function(num, reset) {
|
1238
|
+
var set = {};
|
1239
|
+
set[unit] = num;
|
1240
|
+
return this.advance(set, reset);
|
1241
|
+
};
|
1242
|
+
buildNumberToDateAlias(u, multiplier);
|
1243
|
+
if(i < 3) {
|
1244
|
+
['Last','This','Next'].forEach(function(shift) {
|
1245
|
+
methods['is' + shift + caps] = function() {
|
1246
|
+
return this.is(shift + ' ' + unit);
|
1247
|
+
};
|
1248
|
+
});
|
1249
|
+
}
|
1250
|
+
if(i < 4) {
|
1251
|
+
methods['beginningOf' + caps] = function() {
|
1252
|
+
var set = {};
|
1253
|
+
switch(unit) {
|
1254
|
+
case 'year': set['year'] = this.getFullYear(); break;
|
1255
|
+
case 'month': set['month'] = this.getMonth(); break;
|
1256
|
+
case 'day': set['day'] = this.getDate(); break;
|
1257
|
+
case 'week': set['weekday'] = 0; break;
|
1258
|
+
}
|
1259
|
+
return this.set(set, true);
|
1260
|
+
};
|
1261
|
+
methods['endOf' + caps] = function() {
|
1262
|
+
var set = { 'hours': 23, 'minutes': 59, 'seconds': 59, 'milliseconds': 999 };
|
1263
|
+
switch(unit) {
|
1264
|
+
case 'year': set['month'] = 11; set['day'] = 31; break;
|
1265
|
+
case 'month': set['day'] = this.daysInMonth(); break;
|
1266
|
+
case 'week': set['weekday'] = 6; break;
|
1267
|
+
}
|
1268
|
+
return this.set(set, true);
|
1269
|
+
};
|
1270
|
+
}
|
1271
|
+
});
|
1272
|
+
}
|
1273
|
+
|
1274
|
+
function buildCoreInputFormats() {
|
1275
|
+
English.addFormat('([+-])?(\\d{4,4})[-.]?{full_month}[-.]?(\\d{1,2})?', true, ['year_sign','year','month','date'], false, true);
|
1276
|
+
English.addFormat('(\\d{1,2})[-.\\/]{full_month}(?:[-.\\/](\\d{2,4}))?', true, ['date','month','year'], true);
|
1277
|
+
English.addFormat('{full_month}[-.](\\d{4,4})', false, ['month','year']);
|
1278
|
+
English.addFormat('\\/Date\\((\\d+(?:\\+\\d{4,4})?)\\)\\/', false, ['timestamp'])
|
1279
|
+
English.addFormat(prepareTime(RequiredTime, English), false, TimeFormat)
|
1280
|
+
|
1281
|
+
// When a new locale is initialized it will have the CoreDateFormats initialized by default.
|
1282
|
+
// From there, adding new formats will push them in front of the previous ones, so the core
|
1283
|
+
// formats will be the last to be reached. However, the core formats themselves have English
|
1284
|
+
// months in them, which means that English needs to first be initialized and creates a race
|
1285
|
+
// condition. I'm getting around this here by adding these generalized formats in the order
|
1286
|
+
// specific -> general, which will mean they will be added to the English localization in
|
1287
|
+
// general -> specific order, then chopping them off the front and reversing to get the correct
|
1288
|
+
// order. Note that there are 7 formats as 2 have times which adds a front and a back format.
|
1289
|
+
CoreDateFormats = English.compiledFormats.slice(0,7).reverse();
|
1290
|
+
English.compiledFormats = English.compiledFormats.slice(7).concat(CoreDateFormats);
|
1291
|
+
}
|
1292
|
+
|
1293
|
+
function buildDateOutputShortcuts() {
|
1294
|
+
extendSimilar(date, true, false, 'short,long,full', function(methods, name) {
|
1295
|
+
methods[name] = function(localeCode) {
|
1296
|
+
return formatDate(this, name, false, localeCode);
|
1297
|
+
}
|
1298
|
+
});
|
1299
|
+
}
|
1300
|
+
|
1301
|
+
function buildAsianDigits() {
|
1302
|
+
KanjiDigits.split('').forEach(function(digit, value) {
|
1303
|
+
var holder;
|
1304
|
+
if(value > 9) {
|
1305
|
+
value = math.pow(10, value - 9);
|
1306
|
+
}
|
1307
|
+
AsianDigitMap[digit] = value;
|
1308
|
+
});
|
1309
|
+
FullWidthDigits.split('').forEach(function(digit, value) {
|
1310
|
+
AsianDigitMap[digit] = value;
|
1311
|
+
});
|
1312
|
+
// Kanji numerals may also be included in phrases which are text-based rather
|
1313
|
+
// than actual numbers such as Chinese weekdays (上周三), and "the day before
|
1314
|
+
// yesterday" (一昨日) in Japanese, so don't match these.
|
1315
|
+
AsianDigitReg = regexp('([期週周])?([' + KanjiDigits + FullWidthDigits + ']+)(?!昨)', 'g');
|
1316
|
+
}
|
1317
|
+
|
1318
|
+
/***
|
1319
|
+
* @method is[Day]()
|
1320
|
+
* @returns Boolean
|
1321
|
+
* @short Returns true if the date falls on that day.
|
1322
|
+
* @extra Also available: %isYesterday%, %isToday%, %isTomorrow%, %isWeekday%, and %isWeekend%.
|
1323
|
+
*
|
1324
|
+
* @set
|
1325
|
+
* isToday
|
1326
|
+
* isYesterday
|
1327
|
+
* isTomorrow
|
1328
|
+
* isWeekday
|
1329
|
+
* isWeekend
|
1330
|
+
* isSunday
|
1331
|
+
* isMonday
|
1332
|
+
* isTuesday
|
1333
|
+
* isWednesday
|
1334
|
+
* isThursday
|
1335
|
+
* isFriday
|
1336
|
+
* isSaturday
|
1337
|
+
*
|
1338
|
+
* @example
|
1339
|
+
*
|
1340
|
+
* Date.create('tomorrow').isToday() -> false
|
1341
|
+
* Date.create('thursday').isTomorrow() -> ?
|
1342
|
+
* Date.create('yesterday').isWednesday() -> ?
|
1343
|
+
* Date.create('today').isWeekend() -> ?
|
1344
|
+
*
|
1345
|
+
***
|
1346
|
+
* @method isFuture()
|
1347
|
+
* @returns Boolean
|
1348
|
+
* @short Returns true if the date is in the future.
|
1349
|
+
* @example
|
1350
|
+
*
|
1351
|
+
* Date.create('next week').isFuture() -> true
|
1352
|
+
* Date.create('last week').isFuture() -> false
|
1353
|
+
*
|
1354
|
+
***
|
1355
|
+
* @method isPast()
|
1356
|
+
* @returns Boolean
|
1357
|
+
* @short Returns true if the date is in the past.
|
1358
|
+
* @example
|
1359
|
+
*
|
1360
|
+
* Date.create('last week').isPast() -> true
|
1361
|
+
* Date.create('next week').isPast() -> false
|
1362
|
+
*
|
1363
|
+
***/
|
1364
|
+
function buildRelativeAliases() {
|
1365
|
+
var special = 'today,yesterday,tomorrow,weekday,weekend,future,past'.split(',');
|
1366
|
+
var weekdays = English['weekdays'].slice(0,7);
|
1367
|
+
var months = English['months'].slice(0,12);
|
1368
|
+
extendSimilar(date, true, false, special.concat(weekdays).concat(months), function(methods, name) {
|
1369
|
+
methods['is'+ simpleCapitalize(name)] = function() {
|
1370
|
+
return this.is(name);
|
1371
|
+
};
|
1372
|
+
});
|
1373
|
+
}
|
1374
|
+
|
1375
|
+
function setDateProperties() {
|
1376
|
+
date.extend({
|
1377
|
+
'RFC1123': '{Dow}, {dd} {Mon} {yyyy} {HH}:{mm}:{ss} {tz}',
|
1378
|
+
'RFC1036': '{Weekday}, {dd}-{Mon}-{yy} {HH}:{mm}:{ss} {tz}',
|
1379
|
+
'ISO8601_DATE': '{yyyy}-{MM}-{dd}',
|
1380
|
+
'ISO8601_DATETIME': '{yyyy}-{MM}-{dd}T{HH}:{mm}:{ss}.{fff}{isotz}'
|
1381
|
+
}, false, false);
|
1382
|
+
}
|
1383
|
+
|
1384
|
+
function buildDate() {
|
1385
|
+
buildDateUnits();
|
1386
|
+
buildDateMethods();
|
1387
|
+
buildCoreInputFormats();
|
1388
|
+
buildDateOutputShortcuts();
|
1389
|
+
buildAsianDigits();
|
1390
|
+
buildRelativeAliases();
|
1391
|
+
setDateProperties();
|
1392
|
+
}
|
1393
|
+
|
1394
|
+
|
1395
|
+
date.extend({
|
1396
|
+
|
1397
|
+
/***
|
1398
|
+
* @method Date.create(<d>, [locale] = currentLocale)
|
1399
|
+
* @returns Date
|
1400
|
+
* @short Alternate Date constructor which understands many different text formats, a timestamp, or another date.
|
1401
|
+
* @extra If no argument is given, date is assumed to be now. %Date.create% additionally can accept enumerated parameters as with the standard date constructor. [locale] can be passed to specify the locale that the date is in. When unspecified, the current locale (default is English) is assumed. For more information, see @date_format.
|
1402
|
+
* @example
|
1403
|
+
*
|
1404
|
+
* Date.create('July') -> July of this year
|
1405
|
+
* Date.create('1776') -> 1776
|
1406
|
+
* Date.create('today') -> today
|
1407
|
+
* Date.create('wednesday') -> This wednesday
|
1408
|
+
* Date.create('next friday') -> Next friday
|
1409
|
+
* Date.create('July 4, 1776') -> July 4, 1776
|
1410
|
+
* Date.create(-446806800000) -> November 5, 1955
|
1411
|
+
* Date.create(1776, 6, 4) -> July 4, 1776
|
1412
|
+
* Date.create('1776年07月04日', 'ja') -> July 4, 1776
|
1413
|
+
*
|
1414
|
+
***/
|
1415
|
+
'create': function() {
|
1416
|
+
return createDate(arguments);
|
1417
|
+
},
|
1418
|
+
|
1419
|
+
/***
|
1420
|
+
* @method Date.past(<d>, [locale] = currentLocale)
|
1421
|
+
* @returns Date
|
1422
|
+
* @short Alternate form of %Date.create% with any ambiguity assumed to be the past.
|
1423
|
+
* @extra For example %"Sunday"% can be either "the Sunday coming up" or "the Sunday last" depending on context. Note that dates explicitly in the future ("next Sunday") will remain in the future. This method simply provides a hint when ambiguity exists.
|
1424
|
+
* @example
|
1425
|
+
*
|
1426
|
+
* Date.past('July') -> July of this year or last depending on the current month
|
1427
|
+
* Date.past('Wednesday') -> This wednesday or last depending on the current weekday
|
1428
|
+
*
|
1429
|
+
***/
|
1430
|
+
'past': function() {
|
1431
|
+
return createDate(arguments, -1);
|
1432
|
+
},
|
1433
|
+
|
1434
|
+
/***
|
1435
|
+
* @method Date.future(<d>, [locale] = currentLocale)
|
1436
|
+
* @returns Date
|
1437
|
+
* @short Alternate form of %Date.create% with any ambiguity assumed to be the future.
|
1438
|
+
* @extra For example %"Sunday"% can be either "the Sunday coming up" or "the Sunday last" depending on context. Note that dates explicitly in the past ("last Sunday") will remain in the past. This method simply provides a hint when ambiguity exists.
|
1439
|
+
* @example
|
1440
|
+
*
|
1441
|
+
* Date.future('July') -> July of this year or next depending on the current month
|
1442
|
+
* Date.future('Wednesday') -> This wednesday or next depending on the current weekday
|
1443
|
+
*
|
1444
|
+
***/
|
1445
|
+
'future': function() {
|
1446
|
+
return createDate(arguments, 1);
|
1447
|
+
},
|
1448
|
+
|
1449
|
+
/***
|
1450
|
+
* @method Date.addLocale(<code>, <set>)
|
1451
|
+
* @returns Locale
|
1452
|
+
* @short Adds a locale <set> to the locales understood by Sugar.
|
1453
|
+
* @extra For more see @date_format.
|
1454
|
+
*
|
1455
|
+
***/
|
1456
|
+
'addLocale': function(localeCode, set) {
|
1457
|
+
return setLocalization(localeCode, set);
|
1458
|
+
},
|
1459
|
+
|
1460
|
+
/***
|
1461
|
+
* @method Date.setLocale(<code>)
|
1462
|
+
* @returns Locale
|
1463
|
+
* @short Sets the current locale to be used with dates.
|
1464
|
+
* @extra Sugar has support for 13 locales that are available through the "Date Locales" package. In addition you can define a new locale with %Date.addLocale%. For more see @date_format.
|
1465
|
+
*
|
1466
|
+
***/
|
1467
|
+
'setLocale': function(localeCode, set) {
|
1468
|
+
var loc = getLocalization(localeCode, false);
|
1469
|
+
CurrentLocalization = loc;
|
1470
|
+
// The code is allowed to be more specific than the codes which are required:
|
1471
|
+
// i.e. zh-CN or en-US. Currently this only affects US date variants such as 8/10/2000.
|
1472
|
+
if(localeCode && localeCode != loc['code']) {
|
1473
|
+
loc['code'] = localeCode;
|
1474
|
+
}
|
1475
|
+
return loc;
|
1476
|
+
},
|
1477
|
+
|
1478
|
+
/***
|
1479
|
+
* @method Date.getLocale([code] = current)
|
1480
|
+
* @returns Locale
|
1481
|
+
* @short Gets the locale for the given code, or the current locale.
|
1482
|
+
* @extra The resulting locale object can be manipulated to provide more control over date localizations. For more about locales, see @date_format.
|
1483
|
+
*
|
1484
|
+
***/
|
1485
|
+
'getLocale': function(localeCode) {
|
1486
|
+
return !localeCode ? CurrentLocalization : getLocalization(localeCode, false);
|
1487
|
+
},
|
1488
|
+
|
1489
|
+
/**
|
1490
|
+
* @method Date.addFormat(<format>, <match>, [code] = null)
|
1491
|
+
* @returns Nothing
|
1492
|
+
* @short Manually adds a new date input format.
|
1493
|
+
* @extra This method allows fine grained control for alternate formats. <format> is a string that can have regex tokens inside. <match> is an array of the tokens that each regex capturing group will map to, for example %year%, %date%, etc. For more, see @date_format.
|
1494
|
+
*
|
1495
|
+
**/
|
1496
|
+
'addFormat': function(format, match, localeCode) {
|
1497
|
+
addDateInputFormat(getLocalization(localeCode), format, match);
|
1498
|
+
}
|
1499
|
+
|
1500
|
+
}, false, false);
|
1501
|
+
|
1502
|
+
date.extend({
|
1503
|
+
|
1504
|
+
/***
|
1505
|
+
* @method set(<set>, [reset] = false)
|
1506
|
+
* @returns Date
|
1507
|
+
* @short Sets the date object.
|
1508
|
+
* @extra This method can accept multiple formats including a single number as a timestamp, an object, or enumerated parameters (as with the Date constructor). If [reset] is %true%, any units more specific than those passed will be reset. %setUTC% will set the date according to universal time.
|
1509
|
+
*
|
1510
|
+
* @set
|
1511
|
+
* setUTC
|
1512
|
+
*
|
1513
|
+
* @example
|
1514
|
+
*
|
1515
|
+
* new Date().set({ year: 2011, month: 11, day: 31 }) -> December 31, 2011
|
1516
|
+
* new Date().set(2011, 11, 31) -> December 31, 2011
|
1517
|
+
* new Date().set(86400000) -> 1 day after Jan 1, 1970
|
1518
|
+
* new Date().set({ year: 2004, month: 6 }, true) -> June 1, 2004, 00:00:00.000
|
1519
|
+
*
|
1520
|
+
***/
|
1521
|
+
'set': function() {
|
1522
|
+
var args = collectDateArguments(arguments);
|
1523
|
+
return updateDate(this, args[0], args[1])
|
1524
|
+
},
|
1525
|
+
|
1526
|
+
'setUTC': function() {
|
1527
|
+
var args = collectDateArguments(arguments);
|
1528
|
+
return updateDate(this, args[0], args[1], true)
|
1529
|
+
},
|
1530
|
+
|
1531
|
+
/***
|
1532
|
+
* @method setWeekday()
|
1533
|
+
* @returns Nothing
|
1534
|
+
* @short Sets the weekday of the date.
|
1535
|
+
* @extra %setUTCWeekday% sets according to universal time.
|
1536
|
+
*
|
1537
|
+
* @set
|
1538
|
+
* setUTCWeekday
|
1539
|
+
*
|
1540
|
+
* @example
|
1541
|
+
*
|
1542
|
+
* d = new Date(); d.setWeekday(1); d; -> Monday of this week
|
1543
|
+
* d = new Date(); d.setWeekday(6); d; -> Saturday of this week
|
1544
|
+
*
|
1545
|
+
***/
|
1546
|
+
'setWeekday': function(dow) {
|
1547
|
+
if(isUndefined(dow)) return;
|
1548
|
+
this.setDate(this.getDate() + dow - this.getDay());
|
1549
|
+
},
|
1550
|
+
|
1551
|
+
'setUTCWeekday': function(dow) {
|
1552
|
+
if(isUndefined(dow)) return;
|
1553
|
+
this.setDate(this.getUTCDate() + dow - this.getDay());
|
1554
|
+
},
|
1555
|
+
|
1556
|
+
/***
|
1557
|
+
* @method setWeek()
|
1558
|
+
* @returns Nothing
|
1559
|
+
* @short Sets the week (of the year).
|
1560
|
+
* @extra %setUTCWeek% sets according to universal time.
|
1561
|
+
*
|
1562
|
+
* @set
|
1563
|
+
* setUTCWeek
|
1564
|
+
*
|
1565
|
+
* @example
|
1566
|
+
*
|
1567
|
+
* d = new Date(); d.setWeek(15); d; -> 15th week of the year
|
1568
|
+
*
|
1569
|
+
***/
|
1570
|
+
'setWeek': function(week) {
|
1571
|
+
if(isUndefined(week)) return;
|
1572
|
+
var date = this.getDate();
|
1573
|
+
this.setMonth(0);
|
1574
|
+
this.setDate((week * 7) + 1);
|
1575
|
+
},
|
1576
|
+
|
1577
|
+
'setUTCWeek': function(week) {
|
1578
|
+
if(isUndefined(week)) return;
|
1579
|
+
var date = this.getUTCDate();
|
1580
|
+
this.setMonth(0);
|
1581
|
+
this.setUTCDate((week * 7) + 1);
|
1582
|
+
},
|
1583
|
+
|
1584
|
+
/***
|
1585
|
+
* @method getWeek()
|
1586
|
+
* @returns Number
|
1587
|
+
* @short Gets the date's week (of the year).
|
1588
|
+
* @extra %getUTCWeek% gets the week according to universal time.
|
1589
|
+
*
|
1590
|
+
* @set
|
1591
|
+
* getUTCWeek
|
1592
|
+
*
|
1593
|
+
* @example
|
1594
|
+
*
|
1595
|
+
* new Date().getWeek() -> today's week of the year
|
1596
|
+
* new Date().getUTCWeek() -> today's week of the year
|
1597
|
+
*
|
1598
|
+
***/
|
1599
|
+
'getWeek': function() {
|
1600
|
+
return getWeekNumber(this);
|
1601
|
+
},
|
1602
|
+
|
1603
|
+
'getUTCWeek': function() {
|
1604
|
+
return getWeekNumber(this.toUTC());
|
1605
|
+
},
|
1606
|
+
|
1607
|
+
/***
|
1608
|
+
* @method getUTCOffset([iso])
|
1609
|
+
* @returns String
|
1610
|
+
* @short Returns a string representation of the offset from UTC time. If [iso] is true the offset will be in ISO8601 format.
|
1611
|
+
* @example
|
1612
|
+
*
|
1613
|
+
* new Date().getUTCOffset() -> "+0900"
|
1614
|
+
* new Date().getUTCOffset(true) -> "+09:00"
|
1615
|
+
*
|
1616
|
+
***/
|
1617
|
+
'getUTCOffset': function(iso) {
|
1618
|
+
var offset = this.utc ? 0 : this.getTimezoneOffset();
|
1619
|
+
var colon = iso === true ? ':' : '';
|
1620
|
+
if(!offset && iso) return 'Z';
|
1621
|
+
return padNumber(round(-offset / 60), 2, true) + colon + padNumber(offset % 60, 2);
|
1622
|
+
},
|
1623
|
+
|
1624
|
+
/***
|
1625
|
+
* @method toUTC()
|
1626
|
+
* @returns Date
|
1627
|
+
* @short Converts the date to UTC time, effectively subtracting the timezone offset.
|
1628
|
+
* @extra Note here that the method %getTimezoneOffset% will still show an offset even after this method is called, as this method effectively just rewinds the date. %format% however, will correctly set the %{tz}% (timezone) token as UTC once this method has been called on the date, and %isUTC% will return %true%. Once a date is set to UTC the only way to unset is the %clone% method.
|
1629
|
+
* @example
|
1630
|
+
*
|
1631
|
+
* new Date().toUTC() -> current time in UTC
|
1632
|
+
*
|
1633
|
+
***/
|
1634
|
+
'toUTC': function() {
|
1635
|
+
if(this.utc) return this;
|
1636
|
+
var d = this.clone().addMinutes(this.getTimezoneOffset());
|
1637
|
+
d.utc = true;
|
1638
|
+
return d;
|
1639
|
+
},
|
1640
|
+
|
1641
|
+
/***
|
1642
|
+
* @method isUTC()
|
1643
|
+
* @returns Boolean
|
1644
|
+
* @short Returns true if the date has no timezone offset.
|
1645
|
+
* @extra This will also return true for a date that has had %toUTC% called on it. This is intended to help approximate shifting timezones which is not possible in client-side Javascript. Note that the native method %getTimezoneOffset% will always report the same thing, even if %isUTC% becomes true.
|
1646
|
+
* @example
|
1647
|
+
*
|
1648
|
+
* new Date().isUTC() -> true or false?
|
1649
|
+
* new Date().toUTC().isUTC() -> true
|
1650
|
+
*
|
1651
|
+
***/
|
1652
|
+
'isUTC': function() {
|
1653
|
+
return this.utc || this.getTimezoneOffset() === 0;
|
1654
|
+
},
|
1655
|
+
|
1656
|
+
/***
|
1657
|
+
* @method advance(<set>, [reset] = false)
|
1658
|
+
* @returns Date
|
1659
|
+
* @short Sets the date forward.
|
1660
|
+
* @extra This method can accept multiple formats including an object, a string in the format %3 days%, a single number as milliseconds, or enumerated parameters (as with the Date constructor). If [reset] is %true%, any units more specific than those passed will be reset. For more see @date_format.
|
1661
|
+
* @example
|
1662
|
+
*
|
1663
|
+
* new Date().advance({ year: 2 }) -> 2 years in the future
|
1664
|
+
* new Date().advance('2 days') -> 2 days in the future
|
1665
|
+
* new Date().advance(0, 2, 3) -> 2 months 3 days in the future
|
1666
|
+
* new Date().advance(86400000) -> 1 day in the future
|
1667
|
+
*
|
1668
|
+
***/
|
1669
|
+
'advance': function() {
|
1670
|
+
var args = collectDateArguments(arguments, true);
|
1671
|
+
return updateDate(this, args[0], args[1], false, 1);
|
1672
|
+
},
|
1673
|
+
|
1674
|
+
/***
|
1675
|
+
* @method rewind(<set>, [reset] = false)
|
1676
|
+
* @returns Date
|
1677
|
+
* @short Sets the date back.
|
1678
|
+
* @extra This method can accept multiple formats including a single number as a timestamp, an object, or enumerated parameters (as with the Date constructor). If [reset] is %true%, any units more specific than those passed will be reset. For more see @date_format.
|
1679
|
+
* @example
|
1680
|
+
*
|
1681
|
+
* new Date().rewind({ year: 2 }) -> 2 years in the past
|
1682
|
+
* new Date().rewind(0, 2, 3) -> 2 months 3 days in the past
|
1683
|
+
* new Date().rewind(86400000) -> 1 day in the past
|
1684
|
+
*
|
1685
|
+
***/
|
1686
|
+
'rewind': function() {
|
1687
|
+
var args = collectDateArguments(arguments, true);
|
1688
|
+
return updateDate(this, args[0], args[1], false, -1);
|
1689
|
+
},
|
1690
|
+
|
1691
|
+
/***
|
1692
|
+
* @method isValid()
|
1693
|
+
* @returns Boolean
|
1694
|
+
* @short Returns true if the date is valid.
|
1695
|
+
* @example
|
1696
|
+
*
|
1697
|
+
* new Date().isValid() -> true
|
1698
|
+
* new Date('flexor').isValid() -> false
|
1699
|
+
*
|
1700
|
+
***/
|
1701
|
+
'isValid': function() {
|
1702
|
+
return !isNaN(this.getTime());
|
1703
|
+
},
|
1704
|
+
|
1705
|
+
/***
|
1706
|
+
* @method isAfter(<d>, [margin] = 0)
|
1707
|
+
* @returns Boolean
|
1708
|
+
* @short Returns true if the date is after the <d>.
|
1709
|
+
* @extra [margin] is to allow extra margin of error (in ms). <d> will accept a date object, timestamp, or text format. If not specified, <d> is assumed to be now. See @date_format for more information.
|
1710
|
+
* @example
|
1711
|
+
*
|
1712
|
+
* new Date().isAfter('tomorrow') -> false
|
1713
|
+
* new Date().isAfter('yesterday') -> true
|
1714
|
+
*
|
1715
|
+
***/
|
1716
|
+
'isAfter': function(d, margin) {
|
1717
|
+
return this.getTime() > date.create(d).getTime() - (margin || 0);
|
1718
|
+
},
|
1719
|
+
|
1720
|
+
/***
|
1721
|
+
* @method isBefore(<d>, [margin] = 0)
|
1722
|
+
* @returns Boolean
|
1723
|
+
* @short Returns true if the date is before <d>.
|
1724
|
+
* @extra [margin] is to allow extra margin of error (in ms). <d> will accept a date object, timestamp, or text format. If not specified, <d> is assumed to be now. See @date_format for more information.
|
1725
|
+
* @example
|
1726
|
+
*
|
1727
|
+
* new Date().isBefore('tomorrow') -> true
|
1728
|
+
* new Date().isBefore('yesterday') -> false
|
1729
|
+
*
|
1730
|
+
***/
|
1731
|
+
'isBefore': function(d, margin) {
|
1732
|
+
return this.getTime() < date.create(d).getTime() + (margin || 0);
|
1733
|
+
},
|
1734
|
+
|
1735
|
+
/***
|
1736
|
+
* @method isBetween(<d1>, <d2>, [margin] = 0)
|
1737
|
+
* @returns Boolean
|
1738
|
+
* @short Returns true if the date falls between <d1> and <d2>.
|
1739
|
+
* @extra [margin] is to allow extra margin of error (in ms). <d1> and <d2> will accept a date object, timestamp, or text format. If not specified, they are assumed to be now. See @date_format for more information.
|
1740
|
+
* @example
|
1741
|
+
*
|
1742
|
+
* new Date().isBetween('yesterday', 'tomorrow') -> true
|
1743
|
+
* new Date().isBetween('last year', '2 years ago') -> false
|
1744
|
+
*
|
1745
|
+
***/
|
1746
|
+
'isBetween': function(d1, d2, margin) {
|
1747
|
+
var t = this.getTime();
|
1748
|
+
var t1 = date.create(d1).getTime();
|
1749
|
+
var t2 = date.create(d2).getTime();
|
1750
|
+
var lo = math.min(t1, t2);
|
1751
|
+
var hi = math.max(t1, t2);
|
1752
|
+
margin = margin || 0;
|
1753
|
+
return (lo - margin < t) && (hi + margin > t);
|
1754
|
+
},
|
1755
|
+
|
1756
|
+
/***
|
1757
|
+
* @method isLeapYear()
|
1758
|
+
* @returns Boolean
|
1759
|
+
* @short Returns true if the date is a leap year.
|
1760
|
+
* @example
|
1761
|
+
*
|
1762
|
+
* Date.create('2000').isLeapYear() -> true
|
1763
|
+
*
|
1764
|
+
***/
|
1765
|
+
'isLeapYear': function() {
|
1766
|
+
var year = this.getFullYear();
|
1767
|
+
return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
|
1768
|
+
},
|
1769
|
+
|
1770
|
+
/***
|
1771
|
+
* @method daysInMonth()
|
1772
|
+
* @returns Number
|
1773
|
+
* @short Returns the number of days in the date's month.
|
1774
|
+
* @example
|
1775
|
+
*
|
1776
|
+
* Date.create('May').daysInMonth() -> 31
|
1777
|
+
* Date.create('February, 2000').daysInMonth() -> 29
|
1778
|
+
*
|
1779
|
+
***/
|
1780
|
+
'daysInMonth': function() {
|
1781
|
+
return 32 - new date(this.getFullYear(), this.getMonth(), 32).getDate();
|
1782
|
+
},
|
1783
|
+
|
1784
|
+
/***
|
1785
|
+
* @method format(<format>, [locale] = currentLocale)
|
1786
|
+
* @returns String
|
1787
|
+
* @short Formats and outputs the date.
|
1788
|
+
* @extra <format> can be a number of pre-determined formats or a string of tokens. Locale-specific formats are %short%, %long%, and %full% which have their own aliases and can be called with %date.short()%, etc. If <format> is not specified the %long% format is assumed. [locale] specifies a locale code to use (if not specified the current locale is used). See @date_format for more details.
|
1789
|
+
*
|
1790
|
+
* @set
|
1791
|
+
* short
|
1792
|
+
* long
|
1793
|
+
* full
|
1794
|
+
*
|
1795
|
+
* @example
|
1796
|
+
*
|
1797
|
+
* Date.create().format() -> ex. July 4, 2003
|
1798
|
+
* Date.create().format('{Weekday} {d} {Month}, {yyyy}') -> ex. Monday July 4, 2003
|
1799
|
+
* Date.create().format('{hh}:{mm}') -> ex. 15:57
|
1800
|
+
* Date.create().format('{12hr}:{mm}{tt}') -> ex. 3:57pm
|
1801
|
+
* Date.create().format(Date.ISO8601_DATETIME) -> ex. 2011-07-05 12:24:55.528Z
|
1802
|
+
* Date.create('last week').format('short', 'ja') -> ex. 先週
|
1803
|
+
* Date.create('yesterday').format(function(value,unit,ms,loc) {
|
1804
|
+
* // value = 1, unit = 3, ms = -86400000, loc = [current locale object]
|
1805
|
+
* }); -> ex. 1 day ago
|
1806
|
+
*
|
1807
|
+
***/
|
1808
|
+
'format': function(f, localeCode) {
|
1809
|
+
return formatDate(this, f, false, localeCode);
|
1810
|
+
},
|
1811
|
+
|
1812
|
+
/***
|
1813
|
+
* @method relative([fn], [locale] = currentLocale)
|
1814
|
+
* @returns String
|
1815
|
+
* @short Returns a relative date string offset to the current time.
|
1816
|
+
* @extra [fn] can be passed to provide for more granular control over the resulting string. [fn] is passed 4 arguments: the adjusted value, unit, offset in milliseconds, and a localization object. As an alternate syntax, [locale] can also be passed as the first (and only) parameter. For more information, see @date_format.
|
1817
|
+
* @example
|
1818
|
+
*
|
1819
|
+
* Date.create('90 seconds ago').relative() -> 1 minute ago
|
1820
|
+
* Date.create('January').relative() -> ex. 5 months ago
|
1821
|
+
* Date.create('January').relative('ja') -> 3ヶ月前
|
1822
|
+
* Date.create('120 minutes ago').relative(function(val,unit,ms,loc) {
|
1823
|
+
* // value = 2, unit = 3, ms = -7200, loc = [current locale object]
|
1824
|
+
* }); -> ex. 5 months ago
|
1825
|
+
*
|
1826
|
+
***/
|
1827
|
+
'relative': function(f, localeCode) {
|
1828
|
+
if(isString(f)) {
|
1829
|
+
localeCode = f;
|
1830
|
+
f = null;
|
1831
|
+
}
|
1832
|
+
return formatDate(this, f, true, localeCode);
|
1833
|
+
},
|
1834
|
+
|
1835
|
+
/***
|
1836
|
+
* @method is(<d>, [margin] = 0)
|
1837
|
+
* @returns Boolean
|
1838
|
+
* @short Returns true if the date is <d>.
|
1839
|
+
* @extra <d> will accept a date object, timestamp, or text format. %is% additionally understands more generalized expressions like month/weekday names, 'today', etc, and compares to the precision implied in <d>. [margin] allows an extra margin of error in milliseconds. For more information, see @date_format.
|
1840
|
+
* @example
|
1841
|
+
*
|
1842
|
+
* Date.create().is('July') -> true or false?
|
1843
|
+
* Date.create().is('1776') -> false
|
1844
|
+
* Date.create().is('today') -> true
|
1845
|
+
* Date.create().is('weekday') -> true or false?
|
1846
|
+
* Date.create().is('July 4, 1776') -> false
|
1847
|
+
* Date.create().is(-6106093200000) -> false
|
1848
|
+
* Date.create().is(new Date(1776, 6, 4)) -> false
|
1849
|
+
*
|
1850
|
+
***/
|
1851
|
+
'is': function(d, margin) {
|
1852
|
+
var tmp;
|
1853
|
+
if(!this.isValid()) return;
|
1854
|
+
if(isString(d)) {
|
1855
|
+
d = d.trim().toLowerCase();
|
1856
|
+
switch(true) {
|
1857
|
+
case d === 'future': return this.getTime() > new date().getTime();
|
1858
|
+
case d === 'past': return this.getTime() < new date().getTime();
|
1859
|
+
case d === 'weekday': return this.getDay() > 0 && this.getDay() < 6;
|
1860
|
+
case d === 'weekend': return this.getDay() === 0 || this.getDay() === 6;
|
1861
|
+
case (tmp = English['weekdays'].indexOf(d) % 7) > -1: return this.getDay() === tmp;
|
1862
|
+
case (tmp = English['months'].indexOf(d) % 12) > -1: return this.getMonth() === tmp;
|
1863
|
+
}
|
1864
|
+
}
|
1865
|
+
return compareDate(this, d, margin);
|
1866
|
+
},
|
1867
|
+
|
1868
|
+
/***
|
1869
|
+
* @method reset([unit] = 'hours')
|
1870
|
+
* @returns Date
|
1871
|
+
* @short Resets the unit passed and all smaller units. Default is "hours", effectively resetting the time.
|
1872
|
+
* @example
|
1873
|
+
*
|
1874
|
+
* Date.create().reset('day') -> Beginning of today
|
1875
|
+
* Date.create().reset('month') -> 1st of the month
|
1876
|
+
*
|
1877
|
+
***/
|
1878
|
+
'reset': function(unit) {
|
1879
|
+
var params = {}, recognized;
|
1880
|
+
unit = unit || 'hours';
|
1881
|
+
if(unit === 'date') unit = 'days';
|
1882
|
+
recognized = DateUnits.some(function(u) {
|
1883
|
+
return unit === u.unit || unit === u.unit + 's';
|
1884
|
+
});
|
1885
|
+
params[unit] = unit.match(/^days?/) ? 1 : 0;
|
1886
|
+
return recognized ? this.set(params, true) : this;
|
1887
|
+
},
|
1888
|
+
|
1889
|
+
/***
|
1890
|
+
* @method clone()
|
1891
|
+
* @returns Date
|
1892
|
+
* @short Clones the date.
|
1893
|
+
* @example
|
1894
|
+
*
|
1895
|
+
* Date.create().clone() -> Copy of now
|
1896
|
+
*
|
1897
|
+
***/
|
1898
|
+
'clone': function() {
|
1899
|
+
return new date(this.getTime());
|
1900
|
+
}
|
1901
|
+
|
1902
|
+
});
|
1903
|
+
|
1904
|
+
|
1905
|
+
// Instance aliases
|
1906
|
+
date.extend({
|
1907
|
+
|
1908
|
+
/***
|
1909
|
+
* @method iso()
|
1910
|
+
* @alias toISOString
|
1911
|
+
*
|
1912
|
+
***/
|
1913
|
+
'iso': function() {
|
1914
|
+
return this.toISOString();
|
1915
|
+
},
|
1916
|
+
|
1917
|
+
/***
|
1918
|
+
* @method getWeekday()
|
1919
|
+
* @returns Number
|
1920
|
+
* @short Alias for %getDay%.
|
1921
|
+
* @set
|
1922
|
+
* getUTCWeekday
|
1923
|
+
*
|
1924
|
+
* @example
|
1925
|
+
*
|
1926
|
+
+ Date.create().getWeekday(); -> (ex.) 3
|
1927
|
+
+ Date.create().getUTCWeekday(); -> (ex.) 3
|
1928
|
+
*
|
1929
|
+
***/
|
1930
|
+
'getWeekday': date.prototype.getDay,
|
1931
|
+
'getUTCWeekday': date.prototype.getUTCDay
|
1932
|
+
|
1933
|
+
});
|
1934
|
+
|
1935
|
+
|
1936
|
+
|
1937
|
+
/***
|
1938
|
+
* Number module
|
1939
|
+
*
|
1940
|
+
***/
|
1941
|
+
|
1942
|
+
/***
|
1943
|
+
* @method [unit]()
|
1944
|
+
* @returns Number
|
1945
|
+
* @short Takes the number as a corresponding unit of time and converts to milliseconds.
|
1946
|
+
* @extra Method names can be both singular and plural. Note that as "a month" is ambiguous as a unit of time, %months% will be equivalent to 30.4375 days, the average number in a month. Be careful using %months% if you need exact precision.
|
1947
|
+
*
|
1948
|
+
* @set
|
1949
|
+
* millisecond
|
1950
|
+
* milliseconds
|
1951
|
+
* second
|
1952
|
+
* seconds
|
1953
|
+
* minute
|
1954
|
+
* minutes
|
1955
|
+
* hour
|
1956
|
+
* hours
|
1957
|
+
* day
|
1958
|
+
* days
|
1959
|
+
* week
|
1960
|
+
* weeks
|
1961
|
+
* month
|
1962
|
+
* months
|
1963
|
+
* year
|
1964
|
+
* years
|
1965
|
+
*
|
1966
|
+
* @example
|
1967
|
+
*
|
1968
|
+
* (5).milliseconds() -> 5
|
1969
|
+
* (10).hours() -> 36000000
|
1970
|
+
* (1).day() -> 86400000
|
1971
|
+
*
|
1972
|
+
***
|
1973
|
+
* @method [unit]Before([d], [locale] = currentLocale)
|
1974
|
+
* @returns Date
|
1975
|
+
* @short Returns a date that is <n> units before [d], where <n> is the number.
|
1976
|
+
* @extra [d] will accept a date object, timestamp, or text format. Note that "months" is ambiguous as a unit of time. If the target date falls on a day that does not exist (ie. August 31 -> February 31), the date will be shifted to the last day of the month. Be careful using %monthsBefore% if you need exact precision. See @date_format for more information.
|
1977
|
+
*
|
1978
|
+
* @set
|
1979
|
+
* millisecondBefore
|
1980
|
+
* millisecondsBefore
|
1981
|
+
* secondBefore
|
1982
|
+
* secondsBefore
|
1983
|
+
* minuteBefore
|
1984
|
+
* minutesBefore
|
1985
|
+
* hourBefore
|
1986
|
+
* hoursBefore
|
1987
|
+
* dayBefore
|
1988
|
+
* daysBefore
|
1989
|
+
* weekBefore
|
1990
|
+
* weeksBefore
|
1991
|
+
* monthBefore
|
1992
|
+
* monthsBefore
|
1993
|
+
* yearBefore
|
1994
|
+
* yearsBefore
|
1995
|
+
*
|
1996
|
+
* @example
|
1997
|
+
*
|
1998
|
+
* (5).daysBefore('tuesday') -> 5 days before tuesday of this week
|
1999
|
+
* (1).yearBefore('January 23, 1997') -> January 23, 1996
|
2000
|
+
*
|
2001
|
+
***
|
2002
|
+
* @method [unit]Ago()
|
2003
|
+
* @returns Date
|
2004
|
+
* @short Returns a date that is <n> units ago.
|
2005
|
+
* @extra Note that "months" is ambiguous as a unit of time. If the target date falls on a day that does not exist (ie. August 31 -> February 31), the date will be shifted to the last day of the month. Be careful using %monthsAgo% if you need exact precision.
|
2006
|
+
*
|
2007
|
+
* @set
|
2008
|
+
* millisecondAgo
|
2009
|
+
* millisecondsAgo
|
2010
|
+
* secondAgo
|
2011
|
+
* secondsAgo
|
2012
|
+
* minuteAgo
|
2013
|
+
* minutesAgo
|
2014
|
+
* hourAgo
|
2015
|
+
* hoursAgo
|
2016
|
+
* dayAgo
|
2017
|
+
* daysAgo
|
2018
|
+
* weekAgo
|
2019
|
+
* weeksAgo
|
2020
|
+
* monthAgo
|
2021
|
+
* monthsAgo
|
2022
|
+
* yearAgo
|
2023
|
+
* yearsAgo
|
2024
|
+
*
|
2025
|
+
* @example
|
2026
|
+
*
|
2027
|
+
* (5).weeksAgo() -> 5 weeks ago
|
2028
|
+
* (1).yearAgo() -> January 23, 1996
|
2029
|
+
*
|
2030
|
+
***
|
2031
|
+
* @method [unit]After([d], [locale] = currentLocale)
|
2032
|
+
* @returns Date
|
2033
|
+
* @short Returns a date <n> units after [d], where <n> is the number.
|
2034
|
+
* @extra [d] will accept a date object, timestamp, or text format. Note that "months" is ambiguous as a unit of time. If the target date falls on a day that does not exist (ie. August 31 -> February 31), the date will be shifted to the last day of the month. Be careful using %monthsAfter% if you need exact precision. See @date_format for more information.
|
2035
|
+
*
|
2036
|
+
* @set
|
2037
|
+
* millisecondAfter
|
2038
|
+
* millisecondsAfter
|
2039
|
+
* secondAfter
|
2040
|
+
* secondsAfter
|
2041
|
+
* minuteAfter
|
2042
|
+
* minutesAfter
|
2043
|
+
* hourAfter
|
2044
|
+
* hoursAfter
|
2045
|
+
* dayAfter
|
2046
|
+
* daysAfter
|
2047
|
+
* weekAfter
|
2048
|
+
* weeksAfter
|
2049
|
+
* monthAfter
|
2050
|
+
* monthsAfter
|
2051
|
+
* yearAfter
|
2052
|
+
* yearsAfter
|
2053
|
+
*
|
2054
|
+
* @example
|
2055
|
+
*
|
2056
|
+
* (5).daysAfter('tuesday') -> 5 days after tuesday of this week
|
2057
|
+
* (1).yearAfter('January 23, 1997') -> January 23, 1998
|
2058
|
+
*
|
2059
|
+
***
|
2060
|
+
* @method [unit]FromNow()
|
2061
|
+
* @returns Date
|
2062
|
+
* @short Returns a date <n> units from now.
|
2063
|
+
* @extra Note that "months" is ambiguous as a unit of time. If the target date falls on a day that does not exist (ie. August 31 -> February 31), the date will be shifted to the last day of the month. Be careful using %monthsFromNow% if you need exact precision.
|
2064
|
+
*
|
2065
|
+
* @set
|
2066
|
+
* millisecondFromNow
|
2067
|
+
* millisecondsFromNow
|
2068
|
+
* secondFromNow
|
2069
|
+
* secondsFromNow
|
2070
|
+
* minuteFromNow
|
2071
|
+
* minutesFromNow
|
2072
|
+
* hourFromNow
|
2073
|
+
* hoursFromNow
|
2074
|
+
* dayFromNow
|
2075
|
+
* daysFromNow
|
2076
|
+
* weekFromNow
|
2077
|
+
* weeksFromNow
|
2078
|
+
* monthFromNow
|
2079
|
+
* monthsFromNow
|
2080
|
+
* yearFromNow
|
2081
|
+
* yearsFromNow
|
2082
|
+
*
|
2083
|
+
* @example
|
2084
|
+
*
|
2085
|
+
* (5).weeksFromNow() -> 5 weeks ago
|
2086
|
+
* (1).yearFromNow() -> January 23, 1998
|
2087
|
+
*
|
2088
|
+
***/
|
2089
|
+
function buildNumberToDateAlias(u, multiplier) {
|
2090
|
+
var unit = u.unit, methods = {};
|
2091
|
+
function base() { return round(this * multiplier); }
|
2092
|
+
function after() { return createDate(arguments)[u.addMethod](this); }
|
2093
|
+
function before() { return createDate(arguments)[u.addMethod](-this); }
|
2094
|
+
methods[unit] = base;
|
2095
|
+
methods[unit + 's'] = base;
|
2096
|
+
methods[unit + 'Before'] = before;
|
2097
|
+
methods[unit + 'sBefore'] = before;
|
2098
|
+
methods[unit + 'Ago'] = before;
|
2099
|
+
methods[unit + 'sAgo'] = before;
|
2100
|
+
methods[unit + 'After'] = after;
|
2101
|
+
methods[unit + 'sAfter'] = after;
|
2102
|
+
methods[unit + 'FromNow'] = after;
|
2103
|
+
methods[unit + 'sFromNow'] = after;
|
2104
|
+
number.extend(methods);
|
2105
|
+
}
|
2106
|
+
|
2107
|
+
number.extend({
|
2108
|
+
|
2109
|
+
/***
|
2110
|
+
* @method duration([locale] = currentLocale)
|
2111
|
+
* @returns String
|
2112
|
+
* @short Takes the number as milliseconds and returns a unit-adjusted localized string.
|
2113
|
+
* @extra This method is the same as %Date#relative% without the localized equivalent of "from now" or "ago". [locale] can be passed as the first (and only) parameter. Note that this method is only available when the dates package is included.
|
2114
|
+
* @example
|
2115
|
+
*
|
2116
|
+
* (500).duration() -> '500 milliseconds'
|
2117
|
+
* (1200).duration() -> '1 second'
|
2118
|
+
* (75).minutes().duration() -> '1 hour'
|
2119
|
+
* (75).minutes().duration('es') -> '1 hora'
|
2120
|
+
*
|
2121
|
+
***/
|
2122
|
+
'duration': function(localeCode) {
|
2123
|
+
return getLocalization(localeCode).getDuration(this);
|
2124
|
+
}
|
2125
|
+
|
2126
|
+
});
|
2127
|
+
|
2128
|
+
|
2129
|
+
English = CurrentLocalization = date.addLocale('en', {
|
2130
|
+
'plural': true,
|
2131
|
+
'timeMarker': 'at',
|
2132
|
+
'ampm': 'am,pm',
|
2133
|
+
'months': 'January,February,March,April,May,June,July,August,September,October,November,December',
|
2134
|
+
'weekdays': 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday',
|
2135
|
+
'units': 'millisecond:|s,second:|s,minute:|s,hour:|s,day:|s,week:|s,month:|s,year:|s',
|
2136
|
+
'numbers': 'one,two,three,four,five,six,seven,eight,nine,ten',
|
2137
|
+
'articles': 'a,an,the',
|
2138
|
+
'optionals': 'the,st|nd|rd|th,of',
|
2139
|
+
'short': '{Month} {d}, {yyyy}',
|
2140
|
+
'long': '{Month} {d}, {yyyy} {h}:{mm}{tt}',
|
2141
|
+
'full': '{Weekday} {Month} {d}, {yyyy} {h}:{mm}:{ss}{tt}',
|
2142
|
+
'past': '{num} {unit} {sign}',
|
2143
|
+
'future': '{num} {unit} {sign}',
|
2144
|
+
'duration': '{num} {unit}',
|
2145
|
+
'modifiers': [
|
2146
|
+
{ 'name': 'day', 'src': 'yesterday', 'value': -1 },
|
2147
|
+
{ 'name': 'day', 'src': 'today', 'value': 0 },
|
2148
|
+
{ 'name': 'day', 'src': 'tomorrow', 'value': 1 },
|
2149
|
+
{ 'name': 'sign', 'src': 'ago|before', 'value': -1 },
|
2150
|
+
{ 'name': 'sign', 'src': 'from now|after|from|in', 'value': 1 },
|
2151
|
+
{ 'name': 'edge', 'src': 'last day', 'value': -2 },
|
2152
|
+
{ 'name': 'edge', 'src': 'end', 'value': -1 },
|
2153
|
+
{ 'name': 'edge', 'src': 'first day|beginning', 'value': 1 },
|
2154
|
+
{ 'name': 'shift', 'src': 'last', 'value': -1 },
|
2155
|
+
{ 'name': 'shift', 'src': 'the|this', 'value': 0 },
|
2156
|
+
{ 'name': 'shift', 'src': 'next', 'value': 1 }
|
2157
|
+
],
|
2158
|
+
'dateParse': [
|
2159
|
+
'{num} {unit} {sign}',
|
2160
|
+
'{sign} {num} {unit}',
|
2161
|
+
'{num} {unit=4-5} {sign} {day}',
|
2162
|
+
'{month} {year}',
|
2163
|
+
'{shift} {unit=5-7}',
|
2164
|
+
'{0} {edge} of {shift?} {unit=4-7?}{month?}{year?}'
|
2165
|
+
],
|
2166
|
+
'timeParse': [
|
2167
|
+
'{0} {num}{1} {day} of {month} {year?}',
|
2168
|
+
'{weekday?} {month} {date}{1} {year?}',
|
2169
|
+
'{date} {month} {year}',
|
2170
|
+
'{shift} {weekday}',
|
2171
|
+
'{shift} week {weekday}',
|
2172
|
+
'{weekday} {2} {shift} week',
|
2173
|
+
'{0} {date}{1} of {month}',
|
2174
|
+
'{0}{month?} {date?}{1} of {shift} {unit=6-7}'
|
2175
|
+
]
|
2176
|
+
});
|
2177
|
+
|
2178
|
+
buildDate();
|
2179
|
+
|