vis.js is a dynamic, browser-based visualization library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1400 lines
43 KiB

11 years ago
  1. // moment.js
  2. // version : 2.0.0
  3. // author : Tim Wood
  4. // license : MIT
  5. // momentjs.com
  6. (function (undefined) {
  7. /************************************
  8. Constants
  9. ************************************/
  10. var moment,
  11. VERSION = "2.0.0",
  12. round = Math.round, i,
  13. // internal storage for language config files
  14. languages = {},
  15. // check for nodeJS
  16. hasModule = (typeof module !== 'undefined' && module.exports),
  17. // ASP.NET json date format regex
  18. aspNetJsonRegex = /^\/?Date\((\-?\d+)/i,
  19. // format tokens
  20. formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYY|YYYY|YY|a|A|hh?|HH?|mm?|ss?|SS?S?|X|zz?|ZZ?|.)/g,
  21. localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,
  22. // parsing tokens
  23. parseMultipleFormatChunker = /([0-9a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)/gi,
  24. // parsing token regexes
  25. parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99
  26. parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999
  27. parseTokenThreeDigits = /\d{3}/, // 000 - 999
  28. parseTokenFourDigits = /\d{1,4}/, // 0 - 9999
  29. parseTokenSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999
  30. parseTokenWord = /[0-9]*[a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF]+\s*?[\u0600-\u06FF]+/i, // any word (or two) characters or numbers including two word month in arabic.
  31. parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/i, // +00:00 -00:00 +0000 -0000 or Z
  32. parseTokenT = /T/i, // T (ISO seperator)
  33. parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123
  34. // preliminary iso regex
  35. // 0000-00-00 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000
  36. isoRegex = /^\s*\d{4}-\d\d-\d\d((T| )(\d\d(:\d\d(:\d\d(\.\d\d?\d?)?)?)?)?([\+\-]\d\d:?\d\d)?)?/,
  37. isoFormat = 'YYYY-MM-DDTHH:mm:ssZ',
  38. // iso time formats and regexes
  39. isoTimes = [
  40. ['HH:mm:ss.S', /(T| )\d\d:\d\d:\d\d\.\d{1,3}/],
  41. ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/],
  42. ['HH:mm', /(T| )\d\d:\d\d/],
  43. ['HH', /(T| )\d\d/]
  44. ],
  45. // timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"]
  46. parseTimezoneChunker = /([\+\-]|\d\d)/gi,
  47. // getter and setter names
  48. proxyGettersAndSetters = 'Month|Date|Hours|Minutes|Seconds|Milliseconds'.split('|'),
  49. unitMillisecondFactors = {
  50. 'Milliseconds' : 1,
  51. 'Seconds' : 1e3,
  52. 'Minutes' : 6e4,
  53. 'Hours' : 36e5,
  54. 'Days' : 864e5,
  55. 'Months' : 2592e6,
  56. 'Years' : 31536e6
  57. },
  58. // format function strings
  59. formatFunctions = {},
  60. // tokens to ordinalize and pad
  61. ordinalizeTokens = 'DDD w W M D d'.split(' '),
  62. paddedTokens = 'M D H h m s w W'.split(' '),
  63. formatTokenFunctions = {
  64. M : function () {
  65. return this.month() + 1;
  66. },
  67. MMM : function (format) {
  68. return this.lang().monthsShort(this, format);
  69. },
  70. MMMM : function (format) {
  71. return this.lang().months(this, format);
  72. },
  73. D : function () {
  74. return this.date();
  75. },
  76. DDD : function () {
  77. return this.dayOfYear();
  78. },
  79. d : function () {
  80. return this.day();
  81. },
  82. dd : function (format) {
  83. return this.lang().weekdaysMin(this, format);
  84. },
  85. ddd : function (format) {
  86. return this.lang().weekdaysShort(this, format);
  87. },
  88. dddd : function (format) {
  89. return this.lang().weekdays(this, format);
  90. },
  91. w : function () {
  92. return this.week();
  93. },
  94. W : function () {
  95. return this.isoWeek();
  96. },
  97. YY : function () {
  98. return leftZeroFill(this.year() % 100, 2);
  99. },
  100. YYYY : function () {
  101. return leftZeroFill(this.year(), 4);
  102. },
  103. YYYYY : function () {
  104. return leftZeroFill(this.year(), 5);
  105. },
  106. a : function () {
  107. return this.lang().meridiem(this.hours(), this.minutes(), true);
  108. },
  109. A : function () {
  110. return this.lang().meridiem(this.hours(), this.minutes(), false);
  111. },
  112. H : function () {
  113. return this.hours();
  114. },
  115. h : function () {
  116. return this.hours() % 12 || 12;
  117. },
  118. m : function () {
  119. return this.minutes();
  120. },
  121. s : function () {
  122. return this.seconds();
  123. },
  124. S : function () {
  125. return ~~(this.milliseconds() / 100);
  126. },
  127. SS : function () {
  128. return leftZeroFill(~~(this.milliseconds() / 10), 2);
  129. },
  130. SSS : function () {
  131. return leftZeroFill(this.milliseconds(), 3);
  132. },
  133. Z : function () {
  134. var a = -this.zone(),
  135. b = "+";
  136. if (a < 0) {
  137. a = -a;
  138. b = "-";
  139. }
  140. return b + leftZeroFill(~~(a / 60), 2) + ":" + leftZeroFill(~~a % 60, 2);
  141. },
  142. ZZ : function () {
  143. var a = -this.zone(),
  144. b = "+";
  145. if (a < 0) {
  146. a = -a;
  147. b = "-";
  148. }
  149. return b + leftZeroFill(~~(10 * a / 6), 4);
  150. },
  151. X : function () {
  152. return this.unix();
  153. }
  154. };
  155. function padToken(func, count) {
  156. return function (a) {
  157. return leftZeroFill(func.call(this, a), count);
  158. };
  159. }
  160. function ordinalizeToken(func) {
  161. return function (a) {
  162. return this.lang().ordinal(func.call(this, a));
  163. };
  164. }
  165. while (ordinalizeTokens.length) {
  166. i = ordinalizeTokens.pop();
  167. formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i]);
  168. }
  169. while (paddedTokens.length) {
  170. i = paddedTokens.pop();
  171. formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2);
  172. }
  173. formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3);
  174. /************************************
  175. Constructors
  176. ************************************/
  177. function Language() {
  178. }
  179. // Moment prototype object
  180. function Moment(config) {
  181. extend(this, config);
  182. }
  183. // Duration Constructor
  184. function Duration(duration) {
  185. var data = this._data = {},
  186. years = duration.years || duration.year || duration.y || 0,
  187. months = duration.months || duration.month || duration.M || 0,
  188. weeks = duration.weeks || duration.week || duration.w || 0,
  189. days = duration.days || duration.day || duration.d || 0,
  190. hours = duration.hours || duration.hour || duration.h || 0,
  191. minutes = duration.minutes || duration.minute || duration.m || 0,
  192. seconds = duration.seconds || duration.second || duration.s || 0,
  193. milliseconds = duration.milliseconds || duration.millisecond || duration.ms || 0;
  194. // representation for dateAddRemove
  195. this._milliseconds = milliseconds +
  196. seconds * 1e3 + // 1000
  197. minutes * 6e4 + // 1000 * 60
  198. hours * 36e5; // 1000 * 60 * 60
  199. // Because of dateAddRemove treats 24 hours as different from a
  200. // day when working around DST, we need to store them separately
  201. this._days = days +
  202. weeks * 7;
  203. // It is impossible translate months into days without knowing
  204. // which months you are are talking about, so we have to store
  205. // it separately.
  206. this._months = months +
  207. years * 12;
  208. // The following code bubbles up values, see the tests for
  209. // examples of what that means.
  210. data.milliseconds = milliseconds % 1000;
  211. seconds += absRound(milliseconds / 1000);
  212. data.seconds = seconds % 60;
  213. minutes += absRound(seconds / 60);
  214. data.minutes = minutes % 60;
  215. hours += absRound(minutes / 60);
  216. data.hours = hours % 24;
  217. days += absRound(hours / 24);
  218. days += weeks * 7;
  219. data.days = days % 30;
  220. months += absRound(days / 30);
  221. data.months = months % 12;
  222. years += absRound(months / 12);
  223. data.years = years;
  224. }
  225. /************************************
  226. Helpers
  227. ************************************/
  228. function extend(a, b) {
  229. for (var i in b) {
  230. if (b.hasOwnProperty(i)) {
  231. a[i] = b[i];
  232. }
  233. }
  234. return a;
  235. }
  236. function absRound(number) {
  237. if (number < 0) {
  238. return Math.ceil(number);
  239. } else {
  240. return Math.floor(number);
  241. }
  242. }
  243. // left zero fill a number
  244. // see http://jsperf.com/left-zero-filling for performance comparison
  245. function leftZeroFill(number, targetLength) {
  246. var output = number + '';
  247. while (output.length < targetLength) {
  248. output = '0' + output;
  249. }
  250. return output;
  251. }
  252. // helper function for _.addTime and _.subtractTime
  253. function addOrSubtractDurationFromMoment(mom, duration, isAdding) {
  254. var ms = duration._milliseconds,
  255. d = duration._days,
  256. M = duration._months,
  257. currentDate;
  258. if (ms) {
  259. mom._d.setTime(+mom + ms * isAdding);
  260. }
  261. if (d) {
  262. mom.date(mom.date() + d * isAdding);
  263. }
  264. if (M) {
  265. currentDate = mom.date();
  266. mom.date(1)
  267. .month(mom.month() + M * isAdding)
  268. .date(Math.min(currentDate, mom.daysInMonth()));
  269. }
  270. }
  271. // check if is an array
  272. function isArray(input) {
  273. return Object.prototype.toString.call(input) === '[object Array]';
  274. }
  275. // compare two arrays, return the number of differences
  276. function compareArrays(array1, array2) {
  277. var len = Math.min(array1.length, array2.length),
  278. lengthDiff = Math.abs(array1.length - array2.length),
  279. diffs = 0,
  280. i;
  281. for (i = 0; i < len; i++) {
  282. if (~~array1[i] !== ~~array2[i]) {
  283. diffs++;
  284. }
  285. }
  286. return diffs + lengthDiff;
  287. }
  288. /************************************
  289. Languages
  290. ************************************/
  291. Language.prototype = {
  292. set : function (config) {
  293. var prop, i;
  294. for (i in config) {
  295. prop = config[i];
  296. if (typeof prop === 'function') {
  297. this[i] = prop;
  298. } else {
  299. this['_' + i] = prop;
  300. }
  301. }
  302. },
  303. _months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"),
  304. months : function (m) {
  305. return this._months[m.month()];
  306. },
  307. _monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),
  308. monthsShort : function (m) {
  309. return this._monthsShort[m.month()];
  310. },
  311. monthsParse : function (monthName) {
  312. var i, mom, regex, output;
  313. if (!this._monthsParse) {
  314. this._monthsParse = [];
  315. }
  316. for (i = 0; i < 12; i++) {
  317. // make the regex if we don't have it already
  318. if (!this._monthsParse[i]) {
  319. mom = moment([2000, i]);
  320. regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
  321. this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
  322. }
  323. // test the regex
  324. if (this._monthsParse[i].test(monthName)) {
  325. return i;
  326. }
  327. }
  328. },
  329. _weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
  330. weekdays : function (m) {
  331. return this._weekdays[m.day()];
  332. },
  333. _weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),
  334. weekdaysShort : function (m) {
  335. return this._weekdaysShort[m.day()];
  336. },
  337. _weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"),
  338. weekdaysMin : function (m) {
  339. return this._weekdaysMin[m.day()];
  340. },
  341. _longDateFormat : {
  342. LT : "h:mm A",
  343. L : "MM/DD/YYYY",
  344. LL : "MMMM D YYYY",
  345. LLL : "MMMM D YYYY LT",
  346. LLLL : "dddd, MMMM D YYYY LT"
  347. },
  348. longDateFormat : function (key) {
  349. var output = this._longDateFormat[key];
  350. if (!output && this._longDateFormat[key.toUpperCase()]) {
  351. output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) {
  352. return val.slice(1);
  353. });
  354. this._longDateFormat[key] = output;
  355. }
  356. return output;
  357. },
  358. meridiem : function (hours, minutes, isLower) {
  359. if (hours > 11) {
  360. return isLower ? 'pm' : 'PM';
  361. } else {
  362. return isLower ? 'am' : 'AM';
  363. }
  364. },
  365. _calendar : {
  366. sameDay : '[Today at] LT',
  367. nextDay : '[Tomorrow at] LT',
  368. nextWeek : 'dddd [at] LT',
  369. lastDay : '[Yesterday at] LT',
  370. lastWeek : '[last] dddd [at] LT',
  371. sameElse : 'L'
  372. },
  373. calendar : function (key, mom) {
  374. var output = this._calendar[key];
  375. return typeof output === 'function' ? output.apply(mom) : output;
  376. },
  377. _relativeTime : {
  378. future : "in %s",
  379. past : "%s ago",
  380. s : "a few seconds",
  381. m : "a minute",
  382. mm : "%d minutes",
  383. h : "an hour",
  384. hh : "%d hours",
  385. d : "a day",
  386. dd : "%d days",
  387. M : "a month",
  388. MM : "%d months",
  389. y : "a year",
  390. yy : "%d years"
  391. },
  392. relativeTime : function (number, withoutSuffix, string, isFuture) {
  393. var output = this._relativeTime[string];
  394. return (typeof output === 'function') ?
  395. output(number, withoutSuffix, string, isFuture) :
  396. output.replace(/%d/i, number);
  397. },
  398. pastFuture : function (diff, output) {
  399. var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
  400. return typeof format === 'function' ? format(output) : format.replace(/%s/i, output);
  401. },
  402. ordinal : function (number) {
  403. return this._ordinal.replace("%d", number);
  404. },
  405. _ordinal : "%d",
  406. preparse : function (string) {
  407. return string;
  408. },
  409. postformat : function (string) {
  410. return string;
  411. },
  412. week : function (mom) {
  413. return weekOfYear(mom, this._week.dow, this._week.doy);
  414. },
  415. _week : {
  416. dow : 0, // Sunday is the first day of the week.
  417. doy : 6 // The week that contains Jan 1st is the first week of the year.
  418. }
  419. };
  420. // Loads a language definition into the `languages` cache. The function
  421. // takes a key and optionally values. If not in the browser and no values
  422. // are provided, it will load the language file module. As a convenience,
  423. // this function also returns the language values.
  424. function loadLang(key, values) {
  425. values.abbr = key;
  426. if (!languages[key]) {
  427. languages[key] = new Language();
  428. }
  429. languages[key].set(values);
  430. return languages[key];
  431. }
  432. // Determines which language definition to use and returns it.
  433. //
  434. // With no parameters, it will return the global language. If you
  435. // pass in a language key, such as 'en', it will return the
  436. // definition for 'en', so long as 'en' has already been loaded using
  437. // moment.lang.
  438. function getLangDefinition(key) {
  439. if (!key) {
  440. return moment.fn._lang;
  441. }
  442. if (!languages[key] && hasModule) {
  443. require('./lang/' + key);
  444. }
  445. return languages[key];
  446. }
  447. /************************************
  448. Formatting
  449. ************************************/
  450. function removeFormattingTokens(input) {
  451. if (input.match(/\[.*\]/)) {
  452. return input.replace(/^\[|\]$/g, "");
  453. }
  454. return input.replace(/\\/g, "");
  455. }
  456. function makeFormatFunction(format) {
  457. var array = format.match(formattingTokens), i, length;
  458. for (i = 0, length = array.length; i < length; i++) {
  459. if (formatTokenFunctions[array[i]]) {
  460. array[i] = formatTokenFunctions[array[i]];
  461. } else {
  462. array[i] = removeFormattingTokens(array[i]);
  463. }
  464. }
  465. return function (mom) {
  466. var output = "";
  467. for (i = 0; i < length; i++) {
  468. output += typeof array[i].call === 'function' ? array[i].call(mom, format) : array[i];
  469. }
  470. return output;
  471. };
  472. }
  473. // format date using native date object
  474. function formatMoment(m, format) {
  475. var i = 5;
  476. function replaceLongDateFormatTokens(input) {
  477. return m.lang().longDateFormat(input) || input;
  478. }
  479. while (i-- && localFormattingTokens.test(format)) {
  480. format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
  481. }
  482. if (!formatFunctions[format]) {
  483. formatFunctions[format] = makeFormatFunction(format);
  484. }
  485. return formatFunctions[format](m);
  486. }
  487. /************************************
  488. Parsing
  489. ************************************/
  490. // get the regex to find the next token
  491. function getParseRegexForToken(token) {
  492. switch (token) {
  493. case 'DDDD':
  494. return parseTokenThreeDigits;
  495. case 'YYYY':
  496. return parseTokenFourDigits;
  497. case 'YYYYY':
  498. return parseTokenSixDigits;
  499. case 'S':
  500. case 'SS':
  501. case 'SSS':
  502. case 'DDD':
  503. return parseTokenOneToThreeDigits;
  504. case 'MMM':
  505. case 'MMMM':
  506. case 'dd':
  507. case 'ddd':
  508. case 'dddd':
  509. case 'a':
  510. case 'A':
  511. return parseTokenWord;
  512. case 'X':
  513. return parseTokenTimestampMs;
  514. case 'Z':
  515. case 'ZZ':
  516. return parseTokenTimezone;
  517. case 'T':
  518. return parseTokenT;
  519. case 'MM':
  520. case 'DD':
  521. case 'YY':
  522. case 'HH':
  523. case 'hh':
  524. case 'mm':
  525. case 'ss':
  526. case 'M':
  527. case 'D':
  528. case 'd':
  529. case 'H':
  530. case 'h':
  531. case 'm':
  532. case 's':
  533. return parseTokenOneOrTwoDigits;
  534. default :
  535. return new RegExp(token.replace('\\', ''));
  536. }
  537. }
  538. // function to convert string input to date
  539. function addTimeToArrayFromToken(token, input, config) {
  540. var a, b,
  541. datePartArray = config._a;
  542. switch (token) {
  543. // MONTH
  544. case 'M' : // fall through to MM
  545. case 'MM' :
  546. datePartArray[1] = (input == null) ? 0 : ~~input - 1;
  547. break;
  548. case 'MMM' : // fall through to MMMM
  549. case 'MMMM' :
  550. a = getLangDefinition(config._l).monthsParse(input);
  551. // if we didn't find a month name, mark the date as invalid.
  552. if (a != null) {
  553. datePartArray[1] = a;
  554. } else {
  555. config._isValid = false;
  556. }
  557. break;
  558. // DAY OF MONTH
  559. case 'D' : // fall through to DDDD
  560. case 'DD' : // fall through to DDDD
  561. case 'DDD' : // fall through to DDDD
  562. case 'DDDD' :
  563. if (input != null) {
  564. datePartArray[2] = ~~input;
  565. }
  566. break;
  567. // YEAR
  568. case 'YY' :
  569. datePartArray[0] = ~~input + (~~input > 68 ? 1900 : 2000);
  570. break;
  571. case 'YYYY' :
  572. case 'YYYYY' :
  573. datePartArray[0] = ~~input;
  574. break;
  575. // AM / PM
  576. case 'a' : // fall through to A
  577. case 'A' :
  578. config._isPm = ((input + '').toLowerCase() === 'pm');
  579. break;
  580. // 24 HOUR
  581. case 'H' : // fall through to hh
  582. case 'HH' : // fall through to hh
  583. case 'h' : // fall through to hh
  584. case 'hh' :
  585. datePartArray[3] = ~~input;
  586. break;
  587. // MINUTE
  588. case 'm' : // fall through to mm
  589. case 'mm' :
  590. datePartArray[4] = ~~input;
  591. break;
  592. // SECOND
  593. case 's' : // fall through to ss
  594. case 'ss' :
  595. datePartArray[5] = ~~input;
  596. break;
  597. // MILLISECOND
  598. case 'S' :
  599. case 'SS' :
  600. case 'SSS' :
  601. datePartArray[6] = ~~ (('0.' + input) * 1000);
  602. break;
  603. // UNIX TIMESTAMP WITH MS
  604. case 'X':
  605. config._d = new Date(parseFloat(input) * 1000);
  606. break;
  607. // TIMEZONE
  608. case 'Z' : // fall through to ZZ
  609. case 'ZZ' :
  610. config._useUTC = true;
  611. a = (input + '').match(parseTimezoneChunker);
  612. if (a && a[1]) {
  613. config._tzh = ~~a[1];
  614. }
  615. if (a && a[2]) {
  616. config._tzm = ~~a[2];
  617. }
  618. // reverse offsets
  619. if (a && a[0] === '+') {
  620. config._tzh = -config._tzh;
  621. config._tzm = -config._tzm;
  622. }
  623. break;
  624. }
  625. // if the input is null, the date is not valid
  626. if (input == null) {
  627. config._isValid = false;
  628. }
  629. }
  630. // convert an array to a date.
  631. // the array should mirror the parameters below
  632. // note: all values past the year are optional and will default to the lowest possible value.
  633. // [year, month, day , hour, minute, second, millisecond]
  634. function dateFromArray(config) {
  635. var i, date, input = [];
  636. if (config._d) {
  637. return;
  638. }
  639. for (i = 0; i < 7; i++) {
  640. config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
  641. }
  642. // add the offsets to the time to be parsed so that we can have a clean array for checking isValid
  643. input[3] += config._tzh || 0;
  644. input[4] += config._tzm || 0;
  645. date = new Date(0);
  646. if (config._useUTC) {
  647. date.setUTCFullYear(input[0], input[1], input[2]);
  648. date.setUTCHours(input[3], input[4], input[5], input[6]);
  649. } else {
  650. date.setFullYear(input[0], input[1], input[2]);
  651. date.setHours(input[3], input[4], input[5], input[6]);
  652. }
  653. config._d = date;
  654. }
  655. // date from string and format string
  656. function makeDateFromStringAndFormat(config) {
  657. // This array is used to make a Date, either with `new Date` or `Date.UTC`
  658. var tokens = config._f.match(formattingTokens),
  659. string = config._i,
  660. i, parsedInput;
  661. config._a = [];
  662. for (i = 0; i < tokens.length; i++) {
  663. parsedInput = (getParseRegexForToken(tokens[i]).exec(string) || [])[0];
  664. if (parsedInput) {
  665. string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
  666. }
  667. // don't parse if its not a known token
  668. if (formatTokenFunctions[tokens[i]]) {
  669. addTimeToArrayFromToken(tokens[i], parsedInput, config);
  670. }
  671. }
  672. // handle am pm
  673. if (config._isPm && config._a[3] < 12) {
  674. config._a[3] += 12;
  675. }
  676. // if is 12 am, change hours to 0
  677. if (config._isPm === false && config._a[3] === 12) {
  678. config._a[3] = 0;
  679. }
  680. // return
  681. dateFromArray(config);
  682. }
  683. // date from string and array of format strings
  684. function makeDateFromStringAndArray(config) {
  685. var tempConfig,
  686. tempMoment,
  687. bestMoment,
  688. scoreToBeat = 99,
  689. i,
  690. currentDate,
  691. currentScore;
  692. while (config._f.length) {
  693. tempConfig = extend({}, config);
  694. tempConfig._f = config._f.pop();
  695. makeDateFromStringAndFormat(tempConfig);
  696. tempMoment = new Moment(tempConfig);
  697. if (tempMoment.isValid()) {
  698. bestMoment = tempMoment;
  699. break;
  700. }
  701. currentScore = compareArrays(tempConfig._a, tempMoment.toArray());
  702. if (currentScore < scoreToBeat) {
  703. scoreToBeat = currentScore;
  704. bestMoment = tempMoment;
  705. }
  706. }
  707. extend(config, bestMoment);
  708. }
  709. // date from iso format
  710. function makeDateFromString(config) {
  711. var i,
  712. string = config._i;
  713. if (isoRegex.exec(string)) {
  714. config._f = 'YYYY-MM-DDT';
  715. for (i = 0; i < 4; i++) {
  716. if (isoTimes[i][1].exec(string)) {
  717. config._f += isoTimes[i][0];
  718. break;
  719. }
  720. }
  721. if (parseTokenTimezone.exec(string)) {
  722. config._f += " Z";
  723. }
  724. makeDateFromStringAndFormat(config);
  725. } else {
  726. config._d = new Date(string);
  727. }
  728. }
  729. function makeDateFromInput(config) {
  730. var input = config._i,
  731. matched = aspNetJsonRegex.exec(input);
  732. if (input === undefined) {
  733. config._d = new Date();
  734. } else if (matched) {
  735. config._d = new Date(+matched[1]);
  736. } else if (typeof input === 'string') {
  737. makeDateFromString(config);
  738. } else if (isArray(input)) {
  739. config._a = input.slice(0);
  740. dateFromArray(config);
  741. } else {
  742. config._d = input instanceof Date ? new Date(+input) : new Date(input);
  743. }
  744. }
  745. /************************************
  746. Relative Time
  747. ************************************/
  748. // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
  749. function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) {
  750. return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
  751. }
  752. function relativeTime(milliseconds, withoutSuffix, lang) {
  753. var seconds = round(Math.abs(milliseconds) / 1000),
  754. minutes = round(seconds / 60),
  755. hours = round(minutes / 60),
  756. days = round(hours / 24),
  757. years = round(days / 365),
  758. args = seconds < 45 && ['s', seconds] ||
  759. minutes === 1 && ['m'] ||
  760. minutes < 45 && ['mm', minutes] ||
  761. hours === 1 && ['h'] ||
  762. hours < 22 && ['hh', hours] ||
  763. days === 1 && ['d'] ||
  764. days <= 25 && ['dd', days] ||
  765. days <= 45 && ['M'] ||
  766. days < 345 && ['MM', round(days / 30)] ||
  767. years === 1 && ['y'] || ['yy', years];
  768. args[2] = withoutSuffix;
  769. args[3] = milliseconds > 0;
  770. args[4] = lang;
  771. return substituteTimeAgo.apply({}, args);
  772. }
  773. /************************************
  774. Week of Year
  775. ************************************/
  776. // firstDayOfWeek 0 = sun, 6 = sat
  777. // the day of the week that starts the week
  778. // (usually sunday or monday)
  779. // firstDayOfWeekOfYear 0 = sun, 6 = sat
  780. // the first week is the week that contains the first
  781. // of this day of the week
  782. // (eg. ISO weeks use thursday (4))
  783. function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) {
  784. var end = firstDayOfWeekOfYear - firstDayOfWeek,
  785. daysToDayOfWeek = firstDayOfWeekOfYear - mom.day();
  786. if (daysToDayOfWeek > end) {
  787. daysToDayOfWeek -= 7;
  788. }
  789. if (daysToDayOfWeek < end - 7) {
  790. daysToDayOfWeek += 7;
  791. }
  792. return Math.ceil(moment(mom).add('d', daysToDayOfWeek).dayOfYear() / 7);
  793. }
  794. /************************************
  795. Top Level Functions
  796. ************************************/
  797. function makeMoment(config) {
  798. var input = config._i,
  799. format = config._f;
  800. if (input === null || input === '') {
  801. return null;
  802. }
  803. if (typeof input === 'string') {
  804. config._i = input = getLangDefinition().preparse(input);
  805. }
  806. if (moment.isMoment(input)) {
  807. config = extend({}, input);
  808. config._d = new Date(+input._d);
  809. } else if (format) {
  810. if (isArray(format)) {
  811. makeDateFromStringAndArray(config);
  812. } else {
  813. makeDateFromStringAndFormat(config);
  814. }
  815. } else {
  816. makeDateFromInput(config);
  817. }
  818. return new Moment(config);
  819. }
  820. moment = function (input, format, lang) {
  821. return makeMoment({
  822. _i : input,
  823. _f : format,
  824. _l : lang,
  825. _isUTC : false
  826. });
  827. };
  828. // creating with utc
  829. moment.utc = function (input, format, lang) {
  830. return makeMoment({
  831. _useUTC : true,
  832. _isUTC : true,
  833. _l : lang,
  834. _i : input,
  835. _f : format
  836. });
  837. };
  838. // creating with unix timestamp (in seconds)
  839. moment.unix = function (input) {
  840. return moment(input * 1000);
  841. };
  842. // duration
  843. moment.duration = function (input, key) {
  844. var isDuration = moment.isDuration(input),
  845. isNumber = (typeof input === 'number'),
  846. duration = (isDuration ? input._data : (isNumber ? {} : input)),
  847. ret;
  848. if (isNumber) {
  849. if (key) {
  850. duration[key] = input;
  851. } else {
  852. duration.milliseconds = input;
  853. }
  854. }
  855. ret = new Duration(duration);
  856. if (isDuration && input.hasOwnProperty('_lang')) {
  857. ret._lang = input._lang;
  858. }
  859. return ret;
  860. };
  861. // version number
  862. moment.version = VERSION;
  863. // default format
  864. moment.defaultFormat = isoFormat;
  865. // This function will load languages and then set the global language. If
  866. // no arguments are passed in, it will simply return the current global
  867. // language key.
  868. moment.lang = function (key, values) {
  869. var i;
  870. if (!key) {
  871. return moment.fn._lang._abbr;
  872. }
  873. if (values) {
  874. loadLang(key, values);
  875. } else if (!languages[key]) {
  876. getLangDefinition(key);
  877. }
  878. moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key);
  879. };
  880. // returns language data
  881. moment.langData = function (key) {
  882. if (key && key._lang && key._lang._abbr) {
  883. key = key._lang._abbr;
  884. }
  885. return getLangDefinition(key);
  886. };
  887. // compare moment object
  888. moment.isMoment = function (obj) {
  889. return obj instanceof Moment;
  890. };
  891. // for typechecking Duration objects
  892. moment.isDuration = function (obj) {
  893. return obj instanceof Duration;
  894. };
  895. /************************************
  896. Moment Prototype
  897. ************************************/
  898. moment.fn = Moment.prototype = {
  899. clone : function () {
  900. return moment(this);
  901. },
  902. valueOf : function () {
  903. return +this._d;
  904. },
  905. unix : function () {
  906. return Math.floor(+this._d / 1000);
  907. },
  908. toString : function () {
  909. return this.format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ");
  910. },
  911. toDate : function () {
  912. return this._d;
  913. },
  914. toJSON : function () {
  915. return moment.utc(this).format('YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
  916. },
  917. toArray : function () {
  918. var m = this;
  919. return [
  920. m.year(),
  921. m.month(),
  922. m.date(),
  923. m.hours(),
  924. m.minutes(),
  925. m.seconds(),
  926. m.milliseconds()
  927. ];
  928. },
  929. isValid : function () {
  930. if (this._isValid == null) {
  931. if (this._a) {
  932. this._isValid = !compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray());
  933. } else {
  934. this._isValid = !isNaN(this._d.getTime());
  935. }
  936. }
  937. return !!this._isValid;
  938. },
  939. utc : function () {
  940. this._isUTC = true;
  941. return this;
  942. },
  943. local : function () {
  944. this._isUTC = false;
  945. return this;
  946. },
  947. format : function (inputString) {
  948. var output = formatMoment(this, inputString || moment.defaultFormat);
  949. return this.lang().postformat(output);
  950. },
  951. add : function (input, val) {
  952. var dur;
  953. // switch args to support add('s', 1) and add(1, 's')
  954. if (typeof input === 'string') {
  955. dur = moment.duration(+val, input);
  956. } else {
  957. dur = moment.duration(input, val);
  958. }
  959. addOrSubtractDurationFromMoment(this, dur, 1);
  960. return this;
  961. },
  962. subtract : function (input, val) {
  963. var dur;
  964. // switch args to support subtract('s', 1) and subtract(1, 's')
  965. if (typeof input === 'string') {
  966. dur = moment.duration(+val, input);
  967. } else {
  968. dur = moment.duration(input, val);
  969. }
  970. addOrSubtractDurationFromMoment(this, dur, -1);
  971. return this;
  972. },
  973. diff : function (input, units, asFloat) {
  974. var that = this._isUTC ? moment(input).utc() : moment(input).local(),
  975. zoneDiff = (this.zone() - that.zone()) * 6e4,
  976. diff, output;
  977. if (units) {
  978. // standardize on singular form
  979. units = units.replace(/s$/, '');
  980. }
  981. if (units === 'year' || units === 'month') {
  982. diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2
  983. output = ((this.year() - that.year()) * 12) + (this.month() - that.month());
  984. output += ((this - moment(this).startOf('month')) - (that - moment(that).startOf('month'))) / diff;
  985. if (units === 'year') {
  986. output = output / 12;
  987. }
  988. } else {
  989. diff = (this - that) - zoneDiff;
  990. output = units === 'second' ? diff / 1e3 : // 1000
  991. units === 'minute' ? diff / 6e4 : // 1000 * 60
  992. units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60
  993. units === 'day' ? diff / 864e5 : // 1000 * 60 * 60 * 24
  994. units === 'week' ? diff / 6048e5 : // 1000 * 60 * 60 * 24 * 7
  995. diff;
  996. }
  997. return asFloat ? output : absRound(output);
  998. },
  999. from : function (time, withoutSuffix) {
  1000. return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix);
  1001. },
  1002. fromNow : function (withoutSuffix) {
  1003. return this.from(moment(), withoutSuffix);
  1004. },
  1005. calendar : function () {
  1006. var diff = this.diff(moment().startOf('day'), 'days', true),
  1007. format = diff < -6 ? 'sameElse' :
  1008. diff < -1 ? 'lastWeek' :
  1009. diff < 0 ? 'lastDay' :
  1010. diff < 1 ? 'sameDay' :
  1011. diff < 2 ? 'nextDay' :
  1012. diff < 7 ? 'nextWeek' : 'sameElse';
  1013. return this.format(this.lang().calendar(format, this));
  1014. },
  1015. isLeapYear : function () {
  1016. var year = this.year();
  1017. return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
  1018. },
  1019. isDST : function () {
  1020. return (this.zone() < moment([this.year()]).zone() ||
  1021. this.zone() < moment([this.year(), 5]).zone());
  1022. },
  1023. day : function (input) {
  1024. var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
  1025. return input == null ? day :
  1026. this.add({ d : input - day });
  1027. },
  1028. startOf: function (units) {
  1029. units = units.replace(/s$/, '');
  1030. // the following switch intentionally omits break keywords
  1031. // to utilize falling through the cases.
  1032. switch (units) {
  1033. case 'year':
  1034. this.month(0);
  1035. /* falls through */
  1036. case 'month':
  1037. this.date(1);
  1038. /* falls through */
  1039. case 'week':
  1040. case 'day':
  1041. this.hours(0);
  1042. /* falls through */
  1043. case 'hour':
  1044. this.minutes(0);
  1045. /* falls through */
  1046. case 'minute':
  1047. this.seconds(0);
  1048. /* falls through */
  1049. case 'second':
  1050. this.milliseconds(0);
  1051. /* falls through */
  1052. }
  1053. // weeks are a special case
  1054. if (units === 'week') {
  1055. this.day(0);
  1056. }
  1057. return this;
  1058. },
  1059. endOf: function (units) {
  1060. return this.startOf(units).add(units.replace(/s?$/, 's'), 1).subtract('ms', 1);
  1061. },
  1062. isAfter: function (input, units) {
  1063. units = typeof units !== 'undefined' ? units : 'millisecond';
  1064. return +this.clone().startOf(units) > +moment(input).startOf(units);
  1065. },
  1066. isBefore: function (input, units) {
  1067. units = typeof units !== 'undefined' ? units : 'millisecond';
  1068. return +this.clone().startOf(units) < +moment(input).startOf(units);
  1069. },
  1070. isSame: function (input, units) {
  1071. units = typeof units !== 'undefined' ? units : 'millisecond';
  1072. return +this.clone().startOf(units) === +moment(input).startOf(units);
  1073. },
  1074. zone : function () {
  1075. return this._isUTC ? 0 : this._d.getTimezoneOffset();
  1076. },
  1077. daysInMonth : function () {
  1078. return moment.utc([this.year(), this.month() + 1, 0]).date();
  1079. },
  1080. dayOfYear : function (input) {
  1081. var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1;
  1082. return input == null ? dayOfYear : this.add("d", (input - dayOfYear));
  1083. },
  1084. isoWeek : function (input) {
  1085. var week = weekOfYear(this, 1, 4);
  1086. return input == null ? week : this.add("d", (input - week) * 7);
  1087. },
  1088. week : function (input) {
  1089. var week = this.lang().week(this);
  1090. return input == null ? week : this.add("d", (input - week) * 7);
  1091. },
  1092. // If passed a language key, it will set the language for this
  1093. // instance. Otherwise, it will return the language configuration
  1094. // variables for this instance.
  1095. lang : function (key) {
  1096. if (key === undefined) {
  1097. return this._lang;
  1098. } else {
  1099. this._lang = getLangDefinition(key);
  1100. return this;
  1101. }
  1102. }
  1103. };
  1104. // helper for adding shortcuts
  1105. function makeGetterAndSetter(name, key) {
  1106. moment.fn[name] = moment.fn[name + 's'] = function (input) {
  1107. var utc = this._isUTC ? 'UTC' : '';
  1108. if (input != null) {
  1109. this._d['set' + utc + key](input);
  1110. return this;
  1111. } else {
  1112. return this._d['get' + utc + key]();
  1113. }
  1114. };
  1115. }
  1116. // loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds)
  1117. for (i = 0; i < proxyGettersAndSetters.length; i ++) {
  1118. makeGetterAndSetter(proxyGettersAndSetters[i].toLowerCase().replace(/s$/, ''), proxyGettersAndSetters[i]);
  1119. }
  1120. // add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear')
  1121. makeGetterAndSetter('year', 'FullYear');
  1122. // add plural methods
  1123. moment.fn.days = moment.fn.day;
  1124. moment.fn.weeks = moment.fn.week;
  1125. moment.fn.isoWeeks = moment.fn.isoWeek;
  1126. /************************************
  1127. Duration Prototype
  1128. ************************************/
  1129. moment.duration.fn = Duration.prototype = {
  1130. weeks : function () {
  1131. return absRound(this.days() / 7);
  1132. },
  1133. valueOf : function () {
  1134. return this._milliseconds +
  1135. this._days * 864e5 +
  1136. this._months * 2592e6;
  1137. },
  1138. humanize : function (withSuffix) {
  1139. var difference = +this,
  1140. output = relativeTime(difference, !withSuffix, this.lang());
  1141. if (withSuffix) {
  1142. output = this.lang().pastFuture(difference, output);
  1143. }
  1144. return this.lang().postformat(output);
  1145. },
  1146. lang : moment.fn.lang
  1147. };
  1148. function makeDurationGetter(name) {
  1149. moment.duration.fn[name] = function () {
  1150. return this._data[name];
  1151. };
  1152. }
  1153. function makeDurationAsGetter(name, factor) {
  1154. moment.duration.fn['as' + name] = function () {
  1155. return +this / factor;
  1156. };
  1157. }
  1158. for (i in unitMillisecondFactors) {
  1159. if (unitMillisecondFactors.hasOwnProperty(i)) {
  1160. makeDurationAsGetter(i, unitMillisecondFactors[i]);
  1161. makeDurationGetter(i.toLowerCase());
  1162. }
  1163. }
  1164. makeDurationAsGetter('Weeks', 6048e5);
  1165. /************************************
  1166. Default Lang
  1167. ************************************/
  1168. // Set default language, other languages will inherit from English.
  1169. moment.lang('en', {
  1170. ordinal : function (number) {
  1171. var b = number % 10,
  1172. output = (~~ (number % 100 / 10) === 1) ? 'th' :
  1173. (b === 1) ? 'st' :
  1174. (b === 2) ? 'nd' :
  1175. (b === 3) ? 'rd' : 'th';
  1176. return number + output;
  1177. }
  1178. });
  1179. /************************************
  1180. Exposing Moment
  1181. ************************************/
  1182. // CommonJS module is defined
  1183. if (hasModule) {
  1184. module.exports = moment;
  1185. }
  1186. /*global ender:false */
  1187. if (typeof ender === 'undefined') {
  1188. // here, `this` means `window` in the browser, or `global` on the server
  1189. // add `moment` as a global object via a string identifier,
  1190. // for Closure Compiler "advanced" mode
  1191. this['moment'] = moment;
  1192. }
  1193. /*global define:false */
  1194. if (typeof define === "function" && define.amd) {
  1195. define("moment", [], function () {
  1196. return moment;
  1197. });
  1198. }
  1199. }).call(this);