momentjs-rails 1.6.2 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. data/README.md +1 -1
  2. data/changelog.md +4 -0
  3. data/vendor/assets/javascripts/moment.js +407 -219
  4. data/vendor/assets/javascripts/moment/bg.js +66 -0
  5. data/vendor/assets/javascripts/moment/ca.js +5 -1
  6. data/vendor/assets/javascripts/moment/cv.js +54 -0
  7. data/vendor/assets/javascripts/moment/da.js +6 -2
  8. data/vendor/assets/javascripts/moment/de.js +5 -1
  9. data/vendor/assets/javascripts/moment/en-ca.js +58 -0
  10. data/vendor/assets/javascripts/moment/en-gb.js +5 -1
  11. data/vendor/assets/javascripts/moment/es.js +5 -1
  12. data/vendor/assets/javascripts/moment/eu.js +5 -1
  13. data/vendor/assets/javascripts/moment/fi.js +6 -2
  14. data/vendor/assets/javascripts/moment/fr-ca.js +54 -0
  15. data/vendor/assets/javascripts/moment/fr.js +5 -1
  16. data/vendor/assets/javascripts/moment/gl.js +5 -1
  17. data/vendor/assets/javascripts/moment/hu.js +108 -0
  18. data/vendor/assets/javascripts/moment/is.js +5 -1
  19. data/vendor/assets/javascripts/moment/it.js +8 -4
  20. data/vendor/assets/javascripts/moment/ja.js +61 -0
  21. data/vendor/assets/javascripts/moment/jp.js +12 -5
  22. data/vendor/assets/javascripts/moment/ko.js +58 -0
  23. data/vendor/assets/javascripts/moment/kr.js +9 -2
  24. data/vendor/assets/javascripts/moment/nb.js +5 -1
  25. data/vendor/assets/javascripts/moment/nl.js +15 -3
  26. data/vendor/assets/javascripts/moment/pl.js +5 -1
  27. data/vendor/assets/javascripts/moment/pt-br.js +58 -0
  28. data/vendor/assets/javascripts/moment/pt.js +6 -2
  29. data/vendor/assets/javascripts/moment/ru.js +38 -8
  30. data/vendor/assets/javascripts/moment/sv.js +5 -1
  31. data/vendor/assets/javascripts/moment/tr.js +40 -6
  32. data/vendor/assets/javascripts/moment/zh-cn.js +6 -2
  33. data/vendor/assets/javascripts/moment/zh-tw.js +5 -1
  34. metadata +12 -4
data/README.md CHANGED
@@ -24,7 +24,7 @@ If you want to include a localization file, also add the following directive:
24
24
 
25
25
  ## Versioning
26
26
 
27
- momentjs-rails 1.6.2 == Moment.js 1.6.2
27
+ momentjs-rails 1.7.0 == Moment.js 1.7.0
28
28
 
29
29
  Every attempt is made to mirror the currently shipping Momentum.js version number wherever possible.
30
30
  The major, minor, and patch version numbers will always represent the Momentum.js version. Should a gem
@@ -10,3 +10,7 @@
10
10
  ### Version 1.6.2 (2012-06-07)
11
11
  - Upgraded Moment.js to 1.6.2
12
12
  - Added localization files
13
+
14
+ ### Version 1.7.0 (2012-08-06)
15
+ - Upgrade Moment.js to 1.7.0
16
+ - Upgrade localization files to 1.7.0 tagged versions.
@@ -1,29 +1,38 @@
1
1
  // moment.js
2
- // version : 1.6.2
2
+ // version : 1.7.0
3
3
  // author : Tim Wood
4
4
  // license : MIT
5
5
  // momentjs.com
6
6
 
7
7
  (function (Date, undefined) {
8
8
 
9
+ /************************************
10
+ Constants
11
+ ************************************/
12
+
9
13
  var moment,
10
- VERSION = "1.6.2",
14
+ VERSION = "1.7.0",
11
15
  round = Math.round, i,
12
16
  // internal storage for language config files
13
17
  languages = {},
14
18
  currentLanguage = 'en',
15
19
 
16
20
  // check for nodeJS
17
- hasModule = (typeof module !== 'undefined'),
21
+ hasModule = (typeof module !== 'undefined' && module.exports),
18
22
 
19
- // parameters to check for on the lang config
20
- langConfigProperties = 'months|monthsShort|monthsParse|weekdays|weekdaysShort|longDateFormat|calendar|relativeTime|ordinal|meridiem'.split('|'),
23
+ // Parameters to check for on the lang config. This list of properties
24
+ // will be inherited from English if not provided in a language
25
+ // definition. monthsParse is also a lang config property, but it
26
+ // cannot be inherited and as such cannot be enumerated here.
27
+ langConfigProperties = 'months|monthsShort|weekdays|weekdaysShort|weekdaysMin|longDateFormat|calendar|relativeTime|ordinal|meridiem'.split('|'),
21
28
 
22
29
  // ASP.NET json date format regex
23
30
  aspNetJsonRegex = /^\/?Date\((\-?\d+)/i,
24
31
 
25
32
  // format tokens
26
- formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|dddd?|do?|w[o|w]?|YYYY|YY|a|A|hh?|HH?|mm?|ss?|SS?S?|zz?|ZZ?|LT|LL?L?L?)/g,
33
+ formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|YYYY|YY|a|A|hh?|HH?|mm?|ss?|SS?S?|zz?|ZZ?)/g,
34
+ localFormattingTokens = /(LT|LL?L?L?)/g,
35
+ formattingRemoveEscapes = /(^\[)|(\\)|\]$/g,
27
36
 
28
37
  // parsing tokens
29
38
  parseMultipleFormatChunker = /([0-9a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)/gi,
@@ -32,7 +41,7 @@
32
41
  parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99
33
42
  parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999
34
43
  parseTokenThreeDigits = /\d{3}/, // 000 - 999
35
- parseTokenFourDigits = /\d{4}/, // 0000 - 9999
44
+ parseTokenFourDigits = /\d{1,4}/, // 0 - 9999
36
45
  parseTokenWord = /[0-9a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+/i, // any word characters or numbers
37
46
  parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/i, // +00:00 -00:00 +0000 -0000 or Z
38
47
  parseTokenT = /T/i, // T (ISO seperator)
@@ -63,20 +72,77 @@
63
72
  'Days' : 864e5,
64
73
  'Months' : 2592e6,
65
74
  'Years' : 31536e6
66
- };
75
+ },
76
+
77
+ // format function strings
78
+ formatFunctions = {},
79
+
80
+ /*
81
+ * moment.fn.format uses new Function() to create an inlined formatting function.
82
+ * Results are a 3x speed boost
83
+ * http://jsperf.com/momentjs-cached-format-functions
84
+ *
85
+ * These strings are appended into a function using replaceFormatTokens and makeFormatFunction
86
+ */
87
+ formatFunctionStrings = {
88
+ // a = placeholder
89
+ // b = placeholder
90
+ // t = the current moment being formatted
91
+ // v = getValueAtKey function
92
+ // o = language.ordinal function
93
+ // p = leftZeroFill function
94
+ // m = language.meridiem value or function
95
+ M : '(a=t.month()+1)',
96
+ MMM : 'v("monthsShort",t.month())',
97
+ MMMM : 'v("months",t.month())',
98
+ D : '(a=t.date())',
99
+ DDD : '(a=new Date(t.year(),t.month(),t.date()),b=new Date(t.year(),0,1),a=~~(((a-b)/864e5)+1.5))',
100
+ d : '(a=t.day())',
101
+ dd : 'v("weekdaysMin",t.day())',
102
+ ddd : 'v("weekdaysShort",t.day())',
103
+ dddd : 'v("weekdays",t.day())',
104
+ w : '(a=new Date(t.year(),t.month(),t.date()-t.day()+5),b=new Date(a.getFullYear(),0,4),a=~~((a-b)/864e5/7+1.5))',
105
+ YY : 'p(t.year()%100,2)',
106
+ YYYY : 'p(t.year(),4)',
107
+ a : 'm(t.hours(),t.minutes(),!0)',
108
+ A : 'm(t.hours(),t.minutes(),!1)',
109
+ H : 't.hours()',
110
+ h : 't.hours()%12||12',
111
+ m : 't.minutes()',
112
+ s : 't.seconds()',
113
+ S : '~~(t.milliseconds()/100)',
114
+ SS : 'p(~~(t.milliseconds()/10),2)',
115
+ SSS : 'p(t.milliseconds(),3)',
116
+ Z : '((a=-t.zone())<0?((a=-a),"-"):"+")+p(~~(a/60),2)+":"+p(~~a%60,2)',
117
+ ZZ : '((a=-t.zone())<0?((a=-a),"-"):"+")+p(~~(10*a/6),4)'
118
+ },
119
+
120
+ ordinalizeTokens = 'DDD w M D d'.split(' '),
121
+ paddedTokens = 'M D H h m s w'.split(' ');
122
+
123
+ while (ordinalizeTokens.length) {
124
+ i = ordinalizeTokens.pop();
125
+ formatFunctionStrings[i + 'o'] = formatFunctionStrings[i] + '+o(a)';
126
+ }
127
+ while (paddedTokens.length) {
128
+ i = paddedTokens.pop();
129
+ formatFunctionStrings[i + i] = 'p(' + formatFunctionStrings[i] + ',2)';
130
+ }
131
+ formatFunctionStrings.DDDD = 'p(' + formatFunctionStrings.DDD + ',3)';
132
+
133
+
134
+ /************************************
135
+ Constructors
136
+ ************************************/
137
+
67
138
 
68
139
  // Moment prototype object
69
- function Moment(date, isUTC) {
140
+ function Moment(date, isUTC, lang) {
70
141
  this._d = date;
71
142
  this._isUTC = !!isUTC;
72
- }
73
-
74
- function absRound(number) {
75
- if (number < 0) {
76
- return Math.ceil(number);
77
- } else {
78
- return Math.floor(number);
79
- }
143
+ this._a = date._a || null;
144
+ date._a = null;
145
+ this._lang = lang || false;
80
146
  }
81
147
 
82
148
  // Duration Constructor
@@ -129,6 +195,22 @@
129
195
  years += absRound(months / 12);
130
196
 
131
197
  data.years = years;
198
+
199
+ this._lang = false;
200
+ }
201
+
202
+
203
+ /************************************
204
+ Helpers
205
+ ************************************/
206
+
207
+
208
+ function absRound(number) {
209
+ if (number < 0) {
210
+ return Math.ceil(number);
211
+ } else {
212
+ return Math.floor(number);
213
+ }
132
214
  }
133
215
 
134
216
  // left zero fill a number
@@ -167,141 +249,152 @@
167
249
  return Object.prototype.toString.call(input) === '[object Array]';
168
250
  }
169
251
 
252
+ // compare two arrays, return the number of differences
253
+ function compareArrays(array1, array2) {
254
+ var len = Math.min(array1.length, array2.length),
255
+ lengthDiff = Math.abs(array1.length - array2.length),
256
+ diffs = 0,
257
+ i;
258
+ for (i = 0; i < len; i++) {
259
+ if (~~array1[i] !== ~~array2[i]) {
260
+ diffs++;
261
+ }
262
+ }
263
+ return diffs + lengthDiff;
264
+ }
265
+
170
266
  // convert an array to a date.
171
267
  // the array should mirror the parameters below
172
268
  // note: all values past the year are optional and will default to the lowest possible value.
173
269
  // [year, month, day , hour, minute, second, millisecond]
174
- function dateFromArray(input) {
175
- return new Date(input[0], input[1] || 0, input[2] || 1, input[3] || 0, input[4] || 0, input[5] || 0, input[6] || 0);
270
+ function dateFromArray(input, asUTC) {
271
+ var i, date;
272
+ for (i = 1; i < 7; i++) {
273
+ input[i] = (input[i] == null) ? (i === 2 ? 1 : 0) : input[i];
274
+ }
275
+ // we store whether we used utc or not in the input array
276
+ input[7] = asUTC;
277
+ date = new Date(0);
278
+ if (asUTC) {
279
+ date.setUTCFullYear(input[0], input[1], input[2]);
280
+ date.setUTCHours(input[3], input[4], input[5], input[6]);
281
+ } else {
282
+ date.setFullYear(input[0], input[1], input[2]);
283
+ date.setHours(input[3], input[4], input[5], input[6]);
284
+ }
285
+ date._a = input;
286
+ return date;
287
+ }
288
+
289
+ // Loads a language definition into the `languages` cache. The function
290
+ // takes a key and optionally values. If not in the browser and no values
291
+ // are provided, it will load the language file module. As a convenience,
292
+ // this function also returns the language values.
293
+ function loadLang(key, values) {
294
+ var i, m,
295
+ parse = [];
296
+
297
+ if (!values && hasModule) {
298
+ values = require('./lang/' + key);
299
+ }
300
+
301
+ for (i = 0; i < langConfigProperties.length; i++) {
302
+ // If a language definition does not provide a value, inherit
303
+ // from English
304
+ values[langConfigProperties[i]] = values[langConfigProperties[i]] ||
305
+ languages.en[langConfigProperties[i]];
306
+ }
307
+
308
+ for (i = 0; i < 12; i++) {
309
+ m = moment([2000, i]);
310
+ parse[i] = new RegExp('^' + (values.months[i] || values.months(m, '')) +
311
+ '|^' + (values.monthsShort[i] || values.monthsShort(m, '')).replace('.', ''), 'i');
312
+ }
313
+ values.monthsParse = values.monthsParse || parse;
314
+
315
+ languages[key] = values;
316
+
317
+ return values;
318
+ }
319
+
320
+ // Determines which language definition to use and returns it.
321
+ //
322
+ // With no parameters, it will return the global language. If you
323
+ // pass in a language key, such as 'en', it will return the
324
+ // definition for 'en', so long as 'en' has already been loaded using
325
+ // moment.lang. If you pass in a moment or duration instance, it
326
+ // will decide the language based on that, or default to the global
327
+ // language.
328
+ function getLangDefinition(m) {
329
+ var langKey = (typeof m === 'string') && m ||
330
+ m && m._lang ||
331
+ null;
332
+
333
+ return langKey ? (languages[langKey] || loadLang(langKey)) : moment;
334
+ }
335
+
336
+
337
+ /************************************
338
+ Formatting
339
+ ************************************/
340
+
341
+
342
+ // helper for building inline formatting functions
343
+ function replaceFormatTokens(token) {
344
+ return formatFunctionStrings[token] ?
345
+ ("'+(" + formatFunctionStrings[token] + ")+'") :
346
+ token.replace(formattingRemoveEscapes, "").replace(/\\?'/g, "\\'");
347
+ }
348
+
349
+ // helper for recursing long date formatting tokens
350
+ function replaceLongDateFormatTokens(input) {
351
+ return getLangDefinition().longDateFormat[input] || input;
352
+ }
353
+
354
+ function makeFormatFunction(format) {
355
+ var output = "var a,b;return '" +
356
+ format.replace(formattingTokens, replaceFormatTokens) + "';",
357
+ Fn = Function; // get around jshint
358
+ // t = the current moment being formatted
359
+ // v = getValueAtKey function
360
+ // o = language.ordinal function
361
+ // p = leftZeroFill function
362
+ // m = language.meridiem value or function
363
+ return new Fn('t', 'v', 'o', 'p', 'm', output);
364
+ }
365
+
366
+ function makeOrGetFormatFunction(format) {
367
+ if (!formatFunctions[format]) {
368
+ formatFunctions[format] = makeFormatFunction(format);
369
+ }
370
+ return formatFunctions[format];
176
371
  }
177
372
 
178
373
  // format date using native date object
179
- function formatMoment(m, inputString) {
180
- var currentMonth = m.month(),
181
- currentDate = m.date(),
182
- currentYear = m.year(),
183
- currentDay = m.day(),
184
- currentHours = m.hours(),
185
- currentMinutes = m.minutes(),
186
- currentSeconds = m.seconds(),
187
- currentMilliseconds = m.milliseconds(),
188
- currentZone = -m.zone(),
189
- ordinal = moment.ordinal,
190
- meridiem = moment.meridiem;
191
- // check if the character is a format
192
- // return formatted string or non string.
193
- //
194
- // uses switch/case instead of an object of named functions (like http://phpjs.org/functions/date:380)
195
- // for minification and performance
196
- // see http://jsperf.com/object-of-functions-vs-switch for performance comparison
197
- function replaceFunction(input) {
198
- // create a couple variables to be used later inside one of the cases.
199
- var a, b;
200
- switch (input) {
201
- // MONTH
202
- case 'M' :
203
- return currentMonth + 1;
204
- case 'Mo' :
205
- return (currentMonth + 1) + ordinal(currentMonth + 1);
206
- case 'MM' :
207
- return leftZeroFill(currentMonth + 1, 2);
208
- case 'MMM' :
209
- return moment.monthsShort[currentMonth];
210
- case 'MMMM' :
211
- return moment.months[currentMonth];
212
- // DAY OF MONTH
213
- case 'D' :
214
- return currentDate;
215
- case 'Do' :
216
- return currentDate + ordinal(currentDate);
217
- case 'DD' :
218
- return leftZeroFill(currentDate, 2);
219
- // DAY OF YEAR
220
- case 'DDD' :
221
- a = new Date(currentYear, currentMonth, currentDate);
222
- b = new Date(currentYear, 0, 1);
223
- return ~~ (((a - b) / 864e5) + 1.5);
224
- case 'DDDo' :
225
- a = replaceFunction('DDD');
226
- return a + ordinal(a);
227
- case 'DDDD' :
228
- return leftZeroFill(replaceFunction('DDD'), 3);
229
- // WEEKDAY
230
- case 'd' :
231
- return currentDay;
232
- case 'do' :
233
- return currentDay + ordinal(currentDay);
234
- case 'ddd' :
235
- return moment.weekdaysShort[currentDay];
236
- case 'dddd' :
237
- return moment.weekdays[currentDay];
238
- // WEEK OF YEAR
239
- case 'w' :
240
- a = new Date(currentYear, currentMonth, currentDate - currentDay + 5);
241
- b = new Date(a.getFullYear(), 0, 4);
242
- return ~~ ((a - b) / 864e5 / 7 + 1.5);
243
- case 'wo' :
244
- a = replaceFunction('w');
245
- return a + ordinal(a);
246
- case 'ww' :
247
- return leftZeroFill(replaceFunction('w'), 2);
248
- // YEAR
249
- case 'YY' :
250
- return leftZeroFill(currentYear % 100, 2);
251
- case 'YYYY' :
252
- return currentYear;
253
- // AM / PM
254
- case 'a' :
255
- return meridiem ? meridiem(currentHours, currentMinutes, false) : (currentHours > 11 ? 'pm' : 'am');
256
- case 'A' :
257
- return meridiem ? meridiem(currentHours, currentMinutes, true) : (currentHours > 11 ? 'PM' : 'AM');
258
- // 24 HOUR
259
- case 'H' :
260
- return currentHours;
261
- case 'HH' :
262
- return leftZeroFill(currentHours, 2);
263
- // 12 HOUR
264
- case 'h' :
265
- return currentHours % 12 || 12;
266
- case 'hh' :
267
- return leftZeroFill(currentHours % 12 || 12, 2);
268
- // MINUTE
269
- case 'm' :
270
- return currentMinutes;
271
- case 'mm' :
272
- return leftZeroFill(currentMinutes, 2);
273
- // SECOND
274
- case 's' :
275
- return currentSeconds;
276
- case 'ss' :
277
- return leftZeroFill(currentSeconds, 2);
278
- // MILLISECONDS
279
- case 'S' :
280
- return ~~ (currentMilliseconds / 100);
281
- case 'SS' :
282
- return leftZeroFill(~~(currentMilliseconds / 10), 2);
283
- case 'SSS' :
284
- return leftZeroFill(currentMilliseconds, 3);
285
- // TIMEZONE
286
- case 'Z' :
287
- return (currentZone < 0 ? '-' : '+') + leftZeroFill(~~(Math.abs(currentZone) / 60), 2) + ':' + leftZeroFill(~~(Math.abs(currentZone) % 60), 2);
288
- case 'ZZ' :
289
- return (currentZone < 0 ? '-' : '+') + leftZeroFill(~~(10 * Math.abs(currentZone) / 6), 4);
290
- // LONG DATES
291
- case 'L' :
292
- case 'LL' :
293
- case 'LLL' :
294
- case 'LLLL' :
295
- case 'LT' :
296
- return formatMoment(m, moment.longDateFormat[input]);
297
- // DEFAULT
298
- default :
299
- return input.replace(/(^\[)|(\\)|\]$/g, "");
300
- }
374
+ function formatMoment(m, format) {
375
+ var lang = getLangDefinition(m);
376
+
377
+ function getValueFromArray(key, index) {
378
+ return lang[key].call ? lang[key](m, format) : lang[key][index];
379
+ }
380
+
381
+ while (localFormattingTokens.test(format)) {
382
+ format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
383
+ }
384
+
385
+ if (!formatFunctions[format]) {
386
+ formatFunctions[format] = makeFormatFunction(format);
301
387
  }
302
- return inputString.replace(formattingTokens, replaceFunction);
388
+
389
+ return formatFunctions[format](m, getValueFromArray, lang.ordinal, leftZeroFill, lang.meridiem);
303
390
  }
304
391
 
392
+
393
+ /************************************
394
+ Parsing
395
+ ************************************/
396
+
397
+
305
398
  // get the regex to find the next token
306
399
  function getParseRegexForToken(token) {
307
400
  switch (token) {
@@ -316,6 +409,7 @@
316
409
  return parseTokenOneToThreeDigits;
317
410
  case 'MMM':
318
411
  case 'MMMM':
412
+ case 'dd':
319
413
  case 'ddd':
320
414
  case 'dddd':
321
415
  case 'a':
@@ -328,7 +422,6 @@
328
422
  return parseTokenT;
329
423
  case 'MM':
330
424
  case 'DD':
331
- case 'dd':
332
425
  case 'YY':
333
426
  case 'HH':
334
427
  case 'hh':
@@ -360,7 +453,7 @@
360
453
  case 'MMM' : // fall through to MMMM
361
454
  case 'MMMM' :
362
455
  for (a = 0; a < 12; a++) {
363
- if (moment.monthsParse[a].test(input)) {
456
+ if (getLangDefinition().monthsParse[a].test(input)) {
364
457
  datePartArray[1] = a;
365
458
  break;
366
459
  }
@@ -371,7 +464,9 @@
371
464
  case 'DD' : // fall through to DDDD
372
465
  case 'DDD' : // fall through to DDDD
373
466
  case 'DDDD' :
374
- datePartArray[2] = ~~input;
467
+ if (input != null) {
468
+ datePartArray[2] = ~~input;
469
+ }
375
470
  break;
376
471
  // YEAR
377
472
  case 'YY' :
@@ -456,21 +551,7 @@
456
551
  datePartArray[3] += config.tzh;
457
552
  datePartArray[4] += config.tzm;
458
553
  // return
459
- return config.isUTC ? new Date(Date.UTC.apply({}, datePartArray)) : dateFromArray(datePartArray);
460
- }
461
-
462
- // compare two arrays, return the number of differences
463
- function compareArrays(array1, array2) {
464
- var len = Math.min(array1.length, array2.length),
465
- lengthDiff = Math.abs(array1.length - array2.length),
466
- diffs = 0,
467
- i;
468
- for (i = 0; i < len; i++) {
469
- if (~~array1[i] !== ~~array2[i]) {
470
- diffs++;
471
- }
472
- }
473
- return diffs + lengthDiff;
554
+ return dateFromArray(datePartArray, config.isUTC);
474
555
  }
475
556
 
476
557
  // date from string and array of format strings
@@ -512,15 +593,21 @@
512
593
  return new Date(string);
513
594
  }
514
595
 
596
+
597
+ /************************************
598
+ Relative Time
599
+ ************************************/
600
+
601
+
515
602
  // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
516
- function substituteTimeAgo(string, number, withoutSuffix, isFuture) {
517
- var rt = moment.relativeTime[string];
603
+ function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) {
604
+ var rt = lang.relativeTime[string];
518
605
  return (typeof rt === 'function') ?
519
606
  rt(number || 1, !!withoutSuffix, string, isFuture) :
520
607
  rt.replace(/%d/i, number || 1);
521
608
  }
522
609
 
523
- function relativeTime(milliseconds, withoutSuffix) {
610
+ function relativeTime(milliseconds, withoutSuffix, lang) {
524
611
  var seconds = round(Math.abs(milliseconds) / 1000),
525
612
  minutes = round(seconds / 60),
526
613
  hours = round(minutes / 60),
@@ -538,20 +625,25 @@
538
625
  years === 1 && ['y'] || ['yy', years];
539
626
  args[2] = withoutSuffix;
540
627
  args[3] = milliseconds > 0;
628
+ args[4] = lang;
541
629
  return substituteTimeAgo.apply({}, args);
542
630
  }
543
631
 
632
+
633
+ /************************************
634
+ Top Level Functions
635
+ ************************************/
636
+
637
+
544
638
  moment = function (input, format) {
545
639
  if (input === null || input === '') {
546
640
  return null;
547
641
  }
548
642
  var date,
549
- matched,
550
- isUTC;
643
+ matched;
551
644
  // parse Moment object
552
645
  if (moment.isMoment(input)) {
553
- date = new Date(+input._d);
554
- isUTC = input._isUTC;
646
+ return new Moment(new Date(+input._d), input._isUTC, input._lang);
555
647
  // parse string and format
556
648
  } else if (format) {
557
649
  if (isArray(format)) {
@@ -569,17 +661,23 @@
569
661
  typeof input === 'string' ? makeDateFromString(input) :
570
662
  new Date(input);
571
663
  }
572
- return new Moment(date, isUTC);
664
+
665
+ return new Moment(date);
573
666
  };
574
667
 
575
668
  // creating with utc
576
669
  moment.utc = function (input, format) {
577
670
  if (isArray(input)) {
578
- return new Moment(new Date(Date.UTC.apply({}, input)), true);
671
+ return new Moment(dateFromArray(input, true), true);
672
+ }
673
+ // if we don't have a timezone, we need to add one to trigger parsing into utc
674
+ if (typeof input === 'string' && !parseTokenTimezone.exec(input)) {
675
+ input += ' +0000';
676
+ if (format) {
677
+ format += ' Z';
678
+ }
579
679
  }
580
- return (format && input) ?
581
- moment(input + ' +0000', format + ' Z').utc() :
582
- moment(input && !parseTokenTimezone.exec(input) ? input + '+0000' : input).utc();
680
+ return moment(input, format).utc();
583
681
  };
584
682
 
585
683
  // creating with unix timestamp (in seconds)
@@ -591,7 +689,8 @@
591
689
  moment.duration = function (input, key) {
592
690
  var isDuration = moment.isDuration(input),
593
691
  isNumber = (typeof input === 'number'),
594
- duration = (isDuration ? input._data : (isNumber ? {} : input));
692
+ duration = (isDuration ? input._data : (isNumber ? {} : input)),
693
+ ret;
595
694
 
596
695
  if (isNumber) {
597
696
  if (key) {
@@ -601,7 +700,13 @@
601
700
  }
602
701
  }
603
702
 
604
- return new Duration(duration);
703
+ ret = new Duration(duration);
704
+
705
+ if (isDuration) {
706
+ ret._lang = input._lang;
707
+ }
708
+
709
+ return ret;
605
710
  };
606
711
 
607
712
  // humanizeDuration
@@ -617,40 +722,49 @@
617
722
  // default format
618
723
  moment.defaultFormat = isoFormat;
619
724
 
620
- // language switching and caching
725
+ // This function will load languages and then set the global language. If
726
+ // no arguments are passed in, it will simply return the current global
727
+ // language key.
621
728
  moment.lang = function (key, values) {
622
- var i, req,
623
- parse = [];
729
+ var i;
730
+
624
731
  if (!key) {
625
732
  return currentLanguage;
626
733
  }
627
- if (values) {
628
- for (i = 0; i < 12; i++) {
629
- parse[i] = new RegExp('^' + values.months[i] + '|^' + values.monthsShort[i].replace('.', ''), 'i');
630
- }
631
- values.monthsParse = values.monthsParse || parse;
632
- languages[key] = values;
734
+ if (values || !languages[key]) {
735
+ loadLang(key, values);
633
736
  }
634
737
  if (languages[key]) {
738
+ // deprecated, to get the language definition variables, use the
739
+ // moment.fn.lang method or the getLangDefinition function.
635
740
  for (i = 0; i < langConfigProperties.length; i++) {
636
- moment[langConfigProperties[i]] = languages[key][langConfigProperties[i]] ||
637
- languages.en[langConfigProperties[i]];
741
+ moment[langConfigProperties[i]] = languages[key][langConfigProperties[i]];
638
742
  }
743
+ moment.monthsParse = languages[key].monthsParse;
639
744
  currentLanguage = key;
640
- } else {
641
- if (hasModule) {
642
- req = require('./lang/' + key);
643
- moment.lang(key, req);
644
- }
645
745
  }
646
746
  };
647
747
 
648
- // set default language
748
+ // returns language data
749
+ moment.langData = getLangDefinition;
750
+
751
+ // compare moment object
752
+ moment.isMoment = function (obj) {
753
+ return obj instanceof Moment;
754
+ };
755
+
756
+ // for typechecking Duration objects
757
+ moment.isDuration = function (obj) {
758
+ return obj instanceof Duration;
759
+ };
760
+
761
+ // Set default language, other languages will inherit from English.
649
762
  moment.lang('en', {
650
763
  months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"),
651
764
  monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),
652
765
  weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
653
766
  weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),
767
+ weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"),
654
768
  longDateFormat : {
655
769
  LT : "h:mm A",
656
770
  L : "MM/DD/YYYY",
@@ -658,7 +772,13 @@
658
772
  LLL : "MMMM D YYYY LT",
659
773
  LLLL : "dddd, MMMM D YYYY LT"
660
774
  },
661
- meridiem : false,
775
+ meridiem : function (hours, minutes, isLower) {
776
+ if (hours > 11) {
777
+ return isLower ? 'pm' : 'PM';
778
+ } else {
779
+ return isLower ? 'am' : 'AM';
780
+ }
781
+ },
662
782
  calendar : {
663
783
  sameDay : '[Today at] LT',
664
784
  nextDay : '[Tomorrow at] LT',
@@ -691,17 +811,12 @@
691
811
  }
692
812
  });
693
813
 
694
- // compare moment object
695
- moment.isMoment = function (obj) {
696
- return obj instanceof Moment;
697
- };
698
814
 
699
- // for typechecking Duration objects
700
- moment.isDuration = function (obj) {
701
- return obj instanceof Duration;
702
- };
815
+ /************************************
816
+ Moment Prototype
817
+ ************************************/
818
+
703
819
 
704
- // shortcut for prototype
705
820
  moment.fn = Moment.prototype = {
706
821
 
707
822
  clone : function () {
@@ -724,6 +839,27 @@
724
839
  return this._d;
725
840
  },
726
841
 
842
+ toArray : function () {
843
+ var m = this;
844
+ return [
845
+ m.year(),
846
+ m.month(),
847
+ m.date(),
848
+ m.hours(),
849
+ m.minutes(),
850
+ m.seconds(),
851
+ m.milliseconds(),
852
+ !!this._isUTC
853
+ ];
854
+ },
855
+
856
+ isValid : function () {
857
+ if (this._a) {
858
+ return !compareArrays(this._a, (this._a[7] ? moment.utc(this) : this).toArray());
859
+ }
860
+ return !isNaN(this._d.getTime());
861
+ },
862
+
727
863
  utc : function () {
728
864
  this._isUTC = true;
729
865
  return this;
@@ -774,7 +910,7 @@
774
910
  },
775
911
 
776
912
  from : function (time, withoutSuffix) {
777
- return moment.duration(this.diff(time)).humanize(!withoutSuffix);
913
+ return moment.duration(this.diff(time)).lang(this._lang).humanize(!withoutSuffix);
778
914
  },
779
915
 
780
916
  fromNow : function (withoutSuffix) {
@@ -783,7 +919,7 @@
783
919
 
784
920
  calendar : function () {
785
921
  var diff = this.diff(moment().sod(), 'days', true),
786
- calendar = moment.calendar,
922
+ calendar = this.lang().calendar,
787
923
  allElse = calendar.sameElse,
788
924
  format = diff < -6 ? allElse :
789
925
  diff < -1 ? calendar.lastWeek :
@@ -810,20 +946,43 @@
810
946
  this.add({ d : input - day });
811
947
  },
812
948
 
949
+ startOf: function (val) {
950
+ // the following switch intentionally omits break keywords
951
+ // to utilize falling through the cases.
952
+ switch (val.replace(/s$/, '')) {
953
+ case 'year':
954
+ this.month(0);
955
+ /* falls through */
956
+ case 'month':
957
+ this.date(1);
958
+ /* falls through */
959
+ case 'day':
960
+ this.hours(0);
961
+ /* falls through */
962
+ case 'hour':
963
+ this.minutes(0);
964
+ /* falls through */
965
+ case 'minute':
966
+ this.seconds(0);
967
+ /* falls through */
968
+ case 'second':
969
+ this.milliseconds(0);
970
+ /* falls through */
971
+ }
972
+ return this;
973
+ },
974
+
975
+ endOf: function (val) {
976
+ return this.startOf(val).add(val.replace(/s?$/, 's'), 1).subtract('ms', 1);
977
+ },
978
+
813
979
  sod: function () {
814
- return moment(this)
815
- .hours(0)
816
- .minutes(0)
817
- .seconds(0)
818
- .milliseconds(0);
980
+ return this.clone().startOf('day');
819
981
  },
820
982
 
821
983
  eod: function () {
822
984
  // end of day = start of day plus 1 day, minus 1 millisecond
823
- return this.sod().add({
824
- d : 1,
825
- ms : -1
826
- });
985
+ return this.clone().endOf('day');
827
986
  },
828
987
 
829
988
  zone : function () {
@@ -831,7 +990,19 @@
831
990
  },
832
991
 
833
992
  daysInMonth : function () {
834
- return moment(this).month(this.month() + 1).date(0).date();
993
+ return moment.utc([this.year(), this.month() + 1, 0]).date();
994
+ },
995
+
996
+ // If passed a language key, it will set the language for this
997
+ // instance. Otherwise, it will return the language configuration
998
+ // variables for this instance.
999
+ lang : function (lang) {
1000
+ if (lang === undefined) {
1001
+ return getLangDefinition(this);
1002
+ } else {
1003
+ this._lang = lang;
1004
+ return this;
1005
+ }
835
1006
  }
836
1007
  };
837
1008
 
@@ -856,6 +1027,12 @@
856
1027
  // add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear')
857
1028
  makeGetterAndSetter('year', 'FullYear');
858
1029
 
1030
+
1031
+ /************************************
1032
+ Duration Prototype
1033
+ ************************************/
1034
+
1035
+
859
1036
  moment.duration.fn = Duration.prototype = {
860
1037
  weeks : function () {
861
1038
  return absRound(this.days() / 7);
@@ -869,15 +1046,17 @@
869
1046
 
870
1047
  humanize : function (withSuffix) {
871
1048
  var difference = +this,
872
- rel = moment.relativeTime,
873
- output = relativeTime(difference, !withSuffix);
1049
+ rel = this.lang().relativeTime,
1050
+ output = relativeTime(difference, !withSuffix, this.lang());
874
1051
 
875
1052
  if (withSuffix) {
876
1053
  output = (difference <= 0 ? rel.past : rel.future).replace(/%s/i, output);
877
1054
  }
878
1055
 
879
1056
  return output;
880
- }
1057
+ },
1058
+
1059
+ lang : moment.fn.lang
881
1060
  };
882
1061
 
883
1062
  function makeDurationGetter(name) {
@@ -901,13 +1080,22 @@
901
1080
 
902
1081
  makeDurationAsGetter('Weeks', 6048e5);
903
1082
 
1083
+
1084
+ /************************************
1085
+ Exposing Moment
1086
+ ************************************/
1087
+
1088
+
904
1089
  // CommonJS module is defined
905
1090
  if (hasModule) {
906
1091
  module.exports = moment;
907
1092
  }
908
1093
  /*global ender:false */
909
- if (typeof window !== 'undefined' && typeof ender === 'undefined') {
910
- window.moment = moment;
1094
+ if (typeof ender === 'undefined') {
1095
+ // here, `this` means `window` in the browser, or `global` on the server
1096
+ // add `moment` as a global object via a string identifier,
1097
+ // for Closure Compiler "advanced" mode
1098
+ this['moment'] = moment;
911
1099
  }
912
1100
  /*global define:false */
913
1101
  if (typeof define === "function" && define.amd) {
@@ -915,4 +1103,4 @@
915
1103
  return moment;
916
1104
  });
917
1105
  }
918
- })(Date);
1106
+ }).call(this, Date);