jquery.dateformat.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. /*!
  2. * Date formatting plugin
  3. *
  4. * Copyright (c) Eric Garside
  5. * Dual licensed under:
  6. * MIT: http://www.opensource.org/licenses/mit-license.php
  7. * GPLv3: http://www.opensource.org/licenses/gpl-3.0.html
  8. */
  9. "use strict";
  10. /*global jQuery */
  11. /*jslint white: true, browser: true, onevar: true, undef: true, eqeqeq: true, bitwise: true, regexp: true, strict: true, newcap: true, immed: true, maxerr: 50, indent: 4 */
  12. (function ($) {
  13. //------------------------------
  14. //
  15. // Property Declaration
  16. //
  17. //------------------------------
  18. /**
  19. * String formatting for each month, with January at index "0" and December at "11".
  20. */
  21. var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
  22. /**
  23. * String formatting for each day, with Sunday at index "0" and Saturday at index "6"
  24. */
  25. days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
  26. /**
  27. * The number of days in each month.
  28. */
  29. counts = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
  30. /**
  31. * English ordinal suffix for corresponding days of the week.
  32. */
  33. suffix = [null, 'st', 'nd', 'rd'],
  34. /**
  35. * Define the object which will hold reference to the actual formatting functions. By not directly prototyping these
  36. * into the date function, we vastly reduce the amount of bloat adding these options causes.
  37. */
  38. _;
  39. //------------------------------
  40. //
  41. // Internal Methods
  42. //
  43. //------------------------------
  44. /**
  45. * Left-pad the string with the provided string up to the provided length.
  46. *
  47. * @param format The string to pad.
  48. *
  49. * @param string The string to pad with.
  50. *
  51. * @param length The length to make the string (default is "0" if undefined).
  52. *
  53. * @return The padded string.
  54. */
  55. function pad(format, string, length)
  56. {
  57. format = format + '';
  58. length = length || 2;
  59. return format.length < length ? new Array(1 + length - format.length).join(string) + format : format;
  60. }
  61. /**
  62. * Right-pad the string with the provided string up to the provided length.
  63. *
  64. * @param format The string to pad.
  65. *
  66. * @param string The string to pad with.
  67. *
  68. * @param length The length to make the string (default is "0" if undefined).
  69. *
  70. * @return The padded string.
  71. */
  72. function rpad(format, string, length)
  73. {
  74. format = format + '';
  75. length = length || 2;
  76. return format.length < length ? format + new Array(1 + length - format.length).join(string) : format;
  77. }
  78. /**
  79. * Perform a modulus calculation on a date object to extract the desired value.
  80. *
  81. * @param date The date object to perform the calculation on.
  82. *
  83. * @param mod1 The value to divide the date value seconds by.
  84. *
  85. * @param mod2 The modulus value.
  86. *
  87. * @return The computed value.
  88. */
  89. function modCalc(date, mod1, mod2)
  90. {
  91. return (Math.floor(Math.floor(date.valueOf() / 1e3) / mod1) % mod2);
  92. }
  93. /**
  94. * Given a string, return a properly formatted date string.
  95. *
  96. * @param date The date object being formatted.
  97. *
  98. * @param format The formatting string.
  99. *
  100. * @return The formatted date string
  101. */
  102. function formatDate(date, format)
  103. {
  104. format = format.split('');
  105. var output = '',
  106. /**
  107. * The characters '{' and '}' are the start and end characters of an escape. Anything between these
  108. * characters will not be treated as a formatting commands, and will merely be appended to the output
  109. * string. When the buffering property here is true, we are in the midst of appending escaped characters
  110. * to the output, and the formatting check should therefore be skipped.
  111. */
  112. buffering = false,
  113. char = '',
  114. index = 0;
  115. for (; index < format.length; index++)
  116. {
  117. char = format[index] + '';
  118. switch (char)
  119. {
  120. case ' ':
  121. output += char;
  122. break;
  123. case '{':
  124. case '}':
  125. buffering = char === '{';
  126. break;
  127. default:
  128. if (!buffering && _[char])
  129. {
  130. output += _[char].apply(date);
  131. }
  132. else
  133. {
  134. output += char;
  135. }
  136. break;
  137. }
  138. }
  139. return output;
  140. }
  141. //------------------------------
  142. //
  143. // Class Definition
  144. //
  145. //------------------------------
  146. /**
  147. * The formatting object holds all the actual formatting commands which should be accessible
  148. * for date formatting.
  149. *
  150. * Each method should reference the date function via its "this" context, which will be set
  151. * by the formatter.
  152. *
  153. * This function makes heavy use of the exponent notation for large numbers, to save space. In
  154. * javascript, any number with a set of trailing zeros can be expressed in exponent notation.
  155. *
  156. * Ex. 15,000,000,000 === 15e9, where the number after "e" represents the number of zeros.
  157. */
  158. _ =
  159. {
  160. //------------------------------
  161. // Timer Formatting
  162. //------------------------------
  163. /**
  164. * This is intended to be used for delta computation when subtracting one date object from another.
  165. *
  166. * @return The number of days since the epoch.
  167. */
  168. V: function ()
  169. {
  170. return modCalc(this, 864e2, 1e5);
  171. },
  172. /**
  173. * This is intended to be used for delta computation when subtracting one date object from another.
  174. *
  175. * @return The number of days since the epoch, padded to 2 digits.
  176. */
  177. v: function ()
  178. {
  179. return pad(_.V.apply(this), 0);
  180. },
  181. /**
  182. * This is intended to be used for delta computation when subtracting one date object from another.
  183. *
  184. * @return The number of days since the epoch, offset for years.
  185. */
  186. K: function ()
  187. {
  188. return _.V.apply(this) % 365;
  189. },
  190. /**
  191. * This is intended to be used for delta computation when subtracting one date object from another.
  192. *
  193. * @return The number of days since the epoch, offset for years, padded to 2 digits.
  194. */
  195. k: function ()
  196. {
  197. return pad(_.K.apply(this), 0);
  198. },
  199. /**
  200. * This is intended to be used for delta computation when subtracting one date object from another.
  201. *
  202. * @return The number of hours since the epoch.
  203. */
  204. X: function ()
  205. {
  206. return modCalc(this, 36e2, 24);
  207. },
  208. /**
  209. * This is intended to be used for delta computation when subtracting one date object from another.
  210. *
  211. * @return The number of hours since the epoch, padded to two digits.
  212. */
  213. x: function ()
  214. {
  215. return pad(_.X.apply(this), 0);
  216. },
  217. /**
  218. * This is intended to be used for delta computation when subtracting one date object from another.
  219. *
  220. * @return The number of minutes since the epoch.
  221. */
  222. p: function ()
  223. {
  224. return modCalc(this, 60, 60);
  225. },
  226. /**
  227. * This is intended to be used for delta computation when subtracting one date object from another.
  228. *
  229. * @return The number of minutes since the epoch, padded to two digits.
  230. */
  231. C: function ()
  232. {
  233. return pad(_.p.apply(this), 0);
  234. },
  235. /**
  236. * This is intended to be used for delta computation when subtracting one date object from another.
  237. *
  238. * @return The number of minutes since the epoch, uncapped. (1min 30seconds would be 90s)
  239. */
  240. E: function ()
  241. {
  242. return (_.X.apply(this) * 60) + _.p.apply(this);
  243. },
  244. /**
  245. * This is intended to be used for delta computation when subtracting one date object from another.
  246. *
  247. * @return The number of minutes since the epoch, uncapped and padded to two digits. (1min 30seconds would be 90s)
  248. */
  249. e: function ()
  250. {
  251. return pad(_.e.apply(this), 0);
  252. },
  253. //------------------------------
  254. // Day Formatting
  255. //------------------------------
  256. /**
  257. * @return The day of the month, padded to two digits.
  258. */
  259. d: function ()
  260. {
  261. return pad(this.getDate(), 0);
  262. },
  263. /**
  264. * @return A textual representation of the day, three letters.
  265. */
  266. D: function ()
  267. {
  268. return days[this.getDay()].substring(0, 3);
  269. },
  270. /**
  271. * @return Day of the month without leading zeros.
  272. */
  273. j: function ()
  274. {
  275. return this.getDate();
  276. },
  277. /**
  278. * @return A full textual representation of the day of the week.
  279. */
  280. l: function ()
  281. {
  282. return days[this.getDay()];
  283. },
  284. /**
  285. * @return ISO-8601 numeric representation of the day of the week.
  286. */
  287. N: function ()
  288. {
  289. return this.getDay() + 1;
  290. },
  291. /**
  292. * @return English ordinal suffix for the day of the month, two characters.
  293. */
  294. S: function ()
  295. {
  296. return suffix[this.getDate()] || 'th';
  297. },
  298. /**
  299. * @return Numeric representation of the day of the week.
  300. */
  301. w: function ()
  302. {
  303. return this.getDay();
  304. },
  305. /**
  306. * @return The day of the year (starting from 0).
  307. */
  308. z: function ()
  309. {
  310. return Math.round((this - _.f.apply(this)) / 864e5);
  311. },
  312. //------------------------------
  313. // Week
  314. //------------------------------
  315. /**
  316. * @return ISO-8601 week number of year, weeks starting on Monday
  317. */
  318. W: function ()
  319. {
  320. return Math.ceil(((((this - _.f.apply(this)) / 864e5) + _.w.apply(_.f.apply(this))) / 7));
  321. },
  322. //------------------------------
  323. // Month
  324. //------------------------------
  325. /**
  326. * @return A full textual representation of a month, such as January.
  327. */
  328. F: function ()
  329. {
  330. return months[this.getMonth()];
  331. },
  332. /**
  333. * @return Numeric representation of a month, padded to two digits.
  334. */
  335. m: function ()
  336. {
  337. return pad((this.getMonth() + 1), 0);
  338. },
  339. /**
  340. * @return A short textual representation of a month, three letters.
  341. */
  342. M: function ()
  343. {
  344. return months[this.getMonth()].substring(0, 3);
  345. },
  346. /**
  347. * @return Numeric representation of a month, without leading zeros.
  348. */
  349. n: function ()
  350. {
  351. return this.getMonth() + 1;
  352. },
  353. /**
  354. * @return Number of days in the given month.
  355. */
  356. t: function ()
  357. {
  358. // For February on leap years, we must return 29.
  359. if (this.getMonth() === 1 && _.L.apply(this) === 1)
  360. {
  361. return 29;
  362. }
  363. return counts[this.getMonth()];
  364. },
  365. //------------------------------
  366. // Year
  367. //------------------------------
  368. /**
  369. * @return Whether it's a leap year. 1 if it is a leap year, 0 otherwise.
  370. */
  371. L: function ()
  372. {
  373. var Y = _.Y.apply(this);
  374. return Y % 4 ? 0 : Y % 100 ? 1 : Y % 400 ? 0 : 1;
  375. },
  376. /**
  377. * @return A Date object representing the first day of the current year.
  378. */
  379. f: function ()
  380. {
  381. return new Date(this.getFullYear(), 0, 1);
  382. },
  383. /**
  384. * @return A full numeric representation of the year, 4 digits.
  385. */
  386. Y: function ()
  387. {
  388. return this.getFullYear();
  389. },
  390. /**
  391. * @return A two digit representation of the year.
  392. */
  393. y: function ()
  394. {
  395. return ('' + this.getFullYear()).substr(2);
  396. },
  397. //------------------------------
  398. // Time
  399. //------------------------------
  400. /**
  401. * @return Lowercase Ante/Post Meridiem values.
  402. */
  403. a: function ()
  404. {
  405. return this.getHours() < 12 ? 'am' : 'pm';
  406. },
  407. /**
  408. * @return Uppercase Ante/Post Meridiem values.
  409. */
  410. A: function ()
  411. {
  412. return _.a.apply(this).toUpperCase();
  413. },
  414. /**
  415. * If you ever use this for anything, email <eric@knewton.com>, cause he'd like to know how you found this nonsense useful.
  416. *
  417. * @return Swatch internet time.
  418. */
  419. B: function ()
  420. {
  421. return pad(Math.floor((((this.getHours()) * 36e5) + (this.getMinutes() * 6e4) + (this.getSeconds() * 1e3)) / 864e2), 0, 3);
  422. },
  423. /**
  424. * @return 12-hour format of an hour.
  425. */
  426. g: function ()
  427. {
  428. return this.getHours() % 12 || 12;
  429. },
  430. /**
  431. * @return 24-hour format of an hour.
  432. */
  433. G: function ()
  434. {
  435. return this.getHours();
  436. },
  437. /**
  438. * @return 12-hour format of an hour, padded to two digits.
  439. */
  440. h: function ()
  441. {
  442. return pad(_.g.apply(this), 0);
  443. },
  444. /**
  445. * @return 24-hour format of an hour, padded to two digits.
  446. */
  447. H: function ()
  448. {
  449. return pad(this.getHours(), 0);
  450. },
  451. /**
  452. * @return Minutes, padded to two digits.
  453. */
  454. i: function ()
  455. {
  456. return pad(this.getMinutes(), 0);
  457. },
  458. /**
  459. * @return Seconds, padded to two digits.
  460. */
  461. s: function ()
  462. {
  463. return pad(this.getSeconds(), 0);
  464. },
  465. /**
  466. * @return Microseconds
  467. */
  468. u: function ()
  469. {
  470. return this.getTime() % 1e3;
  471. },
  472. //------------------------------
  473. // Timezone
  474. //------------------------------
  475. /**
  476. * @return Difference to GMT in hours.
  477. */
  478. O: function ()
  479. {
  480. var t = this.getTimezoneOffset() / 60;
  481. return rpad(pad((t >= 0 ? '+' : '-') + Math.abs(t), 0), 0, 4);
  482. },
  483. /**
  484. * @return Difference to GMT in hours, with colon between hours and minutes
  485. */
  486. P: function ()
  487. {
  488. var t = _.O.apply(this);
  489. return t.subst(0, 3) + ':' + t.substr(3);
  490. },
  491. /**
  492. * @return Timezone offset in seconds.
  493. */
  494. Z: function ()
  495. {
  496. return this.getTimezoneOffset() * 60;
  497. },
  498. //------------------------------
  499. // Full Date/Time
  500. //------------------------------
  501. /**
  502. * @return ISO 8601 date
  503. */
  504. c: function ()
  505. {
  506. return _.Y.apply(this) + '-' + _.m.apply(this) + '-' + _.d.apply(this) + 'T' + _.H.apply(this) + ':' + _.i.apply(this) + ':' + _.s.apply(this) + _.P.apply(this);
  507. },
  508. /**
  509. * @return RFC 2822 formatted date
  510. */
  511. r: function ()
  512. {
  513. return this.toString();
  514. },
  515. /**
  516. * @return The number of seconds since the epoch.
  517. */
  518. U: function ()
  519. {
  520. return this.getTime() / 1e3;
  521. }
  522. };
  523. //------------------------------
  524. //
  525. // Native Prototype
  526. //
  527. //------------------------------
  528. $.extend(Date.prototype, {
  529. /**
  530. * Given a string of formatting commands, return the date object as a formatted string.
  531. *
  532. * @param format The formatting string.
  533. *
  534. * @return The formatted date string
  535. */
  536. format: function (format)
  537. {
  538. return formatDate(this, format);
  539. }
  540. });
  541. //------------------------------
  542. //
  543. // Expose to jQuery
  544. //
  545. //------------------------------
  546. $.dateformat =
  547. {
  548. /**
  549. * Get a reference to the formatting rules, or set custom rules.
  550. *
  551. * @param custom The custom rules to set for formatting.
  552. *
  553. * @return The formatting rules.
  554. */
  555. rules: function (custom)
  556. {
  557. if (custom !== undefined)
  558. {
  559. _ = $.extend(_, custom);
  560. }
  561. return _;
  562. },
  563. /**
  564. * Determine if the dateformat plugin has the requested formatting rule.
  565. *
  566. * @param rule The formatting rule to check.
  567. *
  568. * @return True if the rule exists, false otherwise.
  569. */
  570. hasRule: function (rule)
  571. {
  572. return _[rule] !== undefined;
  573. },
  574. /**
  575. * Get a formatting value for a given date.
  576. *
  577. * @param type The formatting character type to get the value of.
  578. *
  579. * @param date The date to extract the value from. Defaults to current.
  580. */
  581. get: function (type, date)
  582. {
  583. return _[type].apply(date || new Date());
  584. },
  585. /**
  586. * Given a string of formatting commands, return the date object as a formatted string.
  587. *
  588. * @param format The formatting string.
  589. *
  590. * @param date The date to extract the value from. Defaults to current.
  591. *
  592. * @return The formatted date string
  593. */
  594. format: function (format, date)
  595. {
  596. return formatDate(date || new Date(), format);
  597. },
  598. /**
  599. * @inheritDoc
  600. */
  601. pad: pad,
  602. /**
  603. * @inheritDoc
  604. */
  605. rpad: rpad
  606. };
  607. }(jQuery));