momentjs-rails 1.6.2 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
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);