php-date-formatter.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. /*!
  2. * @copyright Copyright © Kartik Visweswaran, Krajee.com, 2014 - 2016
  3. * @version 1.3.4
  4. *
  5. * Date formatter utility library that allows formatting date/time variables or Date objects using PHP DateTime format.
  6. * @see http://php.net/manual/en/function.date.php
  7. *
  8. * For more JQuery plugins visit http://plugins.krajee.com
  9. * For more Yii related demos visit http://demos.krajee.com
  10. */
  11. var DateFormatter;
  12. (function () {
  13. "use strict";
  14. var _compare, _lpad, _extend, _indexOf, defaultSettings, DAY, HOUR;
  15. DAY = 1000 * 60 * 60 * 24;
  16. HOUR = 3600;
  17. _compare = function (str1, str2) {
  18. return typeof(str1) === 'string' && typeof(str2) === 'string' && str1.toLowerCase() === str2.toLowerCase();
  19. };
  20. _lpad = function (value, length, chr) {
  21. var val = value.toString();
  22. chr = chr || '0';
  23. return val.length < length ? _lpad(chr + val, length) : val;
  24. };
  25. _extend = function (out) {
  26. var i, obj;
  27. out = out || {};
  28. for (i = 1; i < arguments.length; i++) {
  29. obj = arguments[i];
  30. if (!obj) {
  31. continue;
  32. }
  33. for (var key in obj) {
  34. if (obj.hasOwnProperty(key)) {
  35. if (typeof obj[key] === 'object') {
  36. _extend(out[key], obj[key]);
  37. } else {
  38. out[key] = obj[key];
  39. }
  40. }
  41. }
  42. }
  43. return out;
  44. };
  45. _indexOf = function (val, arr) {
  46. for (var i = 0; i < arr.length; i++) {
  47. if (arr[i].toLowerCase() === val.toLowerCase()) {
  48. return i;
  49. }
  50. }
  51. return -1;
  52. };
  53. defaultSettings = {
  54. dateSettings: {
  55. days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
  56. daysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
  57. months: [
  58. 'January', 'February', 'March', 'April', 'May', 'June', 'July',
  59. 'August', 'September', 'October', 'November', 'December'
  60. ],
  61. monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
  62. meridiem: ['AM', 'PM'],
  63. ordinal: function (number) {
  64. var n = number % 10, suffixes = {1: 'st', 2: 'nd', 3: 'rd'};
  65. return Math.floor(number % 100 / 10) === 1 || !suffixes[n] ? 'th' : suffixes[n];
  66. }
  67. },
  68. separators: /[ \-+\/\.T:@]/g,
  69. validParts: /[dDjlNSwzWFmMntLoYyaABgGhHisueTIOPZcrU]/g,
  70. intParts: /[djwNzmnyYhHgGis]/g,
  71. tzParts: /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
  72. tzClip: /[^-+\dA-Z]/g
  73. };
  74. DateFormatter = function (options) {
  75. var self = this, config = _extend(defaultSettings, options);
  76. self.dateSettings = config.dateSettings;
  77. self.separators = config.separators;
  78. self.validParts = config.validParts;
  79. self.intParts = config.intParts;
  80. self.tzParts = config.tzParts;
  81. self.tzClip = config.tzClip;
  82. };
  83. DateFormatter.prototype = {
  84. constructor: DateFormatter,
  85. getMonth: function (val) {
  86. var self = this, i;
  87. i = _indexOf(val, self.dateSettings.monthsShort) + 1;
  88. if (i === 0) {
  89. i = _indexOf(val, self.dateSettings.months) + 1;
  90. }
  91. return i;
  92. },
  93. parseDate: function (vDate, vFormat) {
  94. var self = this, vFormatParts, vDateParts, i, vDateFlag = false, vTimeFlag = false, vDatePart, iDatePart,
  95. vSettings = self.dateSettings, vMonth, vMeriIndex, vMeriOffset, len, mer,
  96. out = {date: null, year: null, month: null, day: null, hour: 0, min: 0, sec: 0};
  97. if (!vDate) {
  98. return null;
  99. }
  100. if (vDate instanceof Date) {
  101. return vDate;
  102. }
  103. if (vFormat === 'U') {
  104. i = parseInt(vDate);
  105. return i ? new Date(i * 1000) : vDate;
  106. }
  107. switch (typeof vDate) {
  108. case 'number':
  109. return new Date(vDate);
  110. case 'string':
  111. break;
  112. default:
  113. return null;
  114. }
  115. vFormatParts = vFormat.match(self.validParts);
  116. if (!vFormatParts || vFormatParts.length === 0) {
  117. throw new Error("Invalid date format definition.");
  118. }
  119. vDateParts = vDate.replace(self.separators, '\0').split('\0');
  120. for (i = 0; i < vDateParts.length; i++) {
  121. vDatePart = vDateParts[i];
  122. iDatePart = parseInt(vDatePart);
  123. switch (vFormatParts[i]) {
  124. case 'y':
  125. case 'Y':
  126. if (iDatePart) {
  127. len = vDatePart.length;
  128. out.year = len === 2 ? parseInt((iDatePart < 70 ? '20' : '19') + vDatePart) : iDatePart;
  129. } else {
  130. return null;
  131. }
  132. vDateFlag = true;
  133. break;
  134. case 'm':
  135. case 'n':
  136. case 'M':
  137. case 'F':
  138. if (isNaN(iDatePart)) {
  139. vMonth = self.getMonth(vDatePart);
  140. if (vMonth > 0) {
  141. out.month = vMonth;
  142. } else {
  143. return null;
  144. }
  145. } else {
  146. if (iDatePart >= 1 && iDatePart <= 12) {
  147. out.month = iDatePart;
  148. } else {
  149. return null;
  150. }
  151. }
  152. vDateFlag = true;
  153. break;
  154. case 'd':
  155. case 'j':
  156. if (iDatePart >= 1 && iDatePart <= 31) {
  157. out.day = iDatePart;
  158. } else {
  159. return null;
  160. }
  161. vDateFlag = true;
  162. break;
  163. case 'g':
  164. case 'h':
  165. vMeriIndex = (vFormatParts.indexOf('a') > -1) ? vFormatParts.indexOf('a') :
  166. (vFormatParts.indexOf('A') > -1) ? vFormatParts.indexOf('A') : -1;
  167. mer = vDateParts[vMeriIndex];
  168. if (vMeriIndex !== -1) {
  169. vMeriOffset = _compare(mer, vSettings.meridiem[0]) ? 0 :
  170. (_compare(mer, vSettings.meridiem[1]) ? 12 : -1);
  171. if (iDatePart >= 1 && iDatePart <= 12 && vMeriOffset !== -1) {
  172. out.hour = iDatePart % 12 === 0 ? vMeriOffset : iDatePart + vMeriOffset;
  173. } else {
  174. if (iDatePart >= 0 && iDatePart <= 23) {
  175. out.hour = iDatePart;
  176. }
  177. }
  178. } else {
  179. if (iDatePart >= 0 && iDatePart <= 23) {
  180. out.hour = iDatePart;
  181. } else {
  182. return null;
  183. }
  184. }
  185. vTimeFlag = true;
  186. break;
  187. case 'G':
  188. case 'H':
  189. if (iDatePart >= 0 && iDatePart <= 23) {
  190. out.hour = iDatePart;
  191. } else {
  192. return null;
  193. }
  194. vTimeFlag = true;
  195. break;
  196. case 'i':
  197. if (iDatePart >= 0 && iDatePart <= 59) {
  198. out.min = iDatePart;
  199. } else {
  200. return null;
  201. }
  202. vTimeFlag = true;
  203. break;
  204. case 's':
  205. if (iDatePart >= 0 && iDatePart <= 59) {
  206. out.sec = iDatePart;
  207. } else {
  208. return null;
  209. }
  210. vTimeFlag = true;
  211. break;
  212. }
  213. }
  214. if (vDateFlag === true && out.year && out.month && out.day) {
  215. out.date = new Date(out.year, out.month - 1, out.day, out.hour, out.min, out.sec, 0);
  216. } else {
  217. if (vTimeFlag !== true) {
  218. return null;
  219. }
  220. out.date = new Date(0, 0, 0, out.hour, out.min, out.sec, 0);
  221. }
  222. return out.date;
  223. },
  224. guessDate: function (vDateStr, vFormat) {
  225. if (typeof vDateStr !== 'string') {
  226. return vDateStr;
  227. }
  228. var self = this, vParts = vDateStr.replace(self.separators, '\0').split('\0'), vPattern = /^[djmn]/g, len,
  229. vFormatParts = vFormat.match(self.validParts), vDate = new Date(), vDigit = 0, vYear, i, n, iPart, iSec;
  230. if (!vPattern.test(vFormatParts[0])) {
  231. return vDateStr;
  232. }
  233. for (i = 0; i < vParts.length; i++) {
  234. vDigit = 2;
  235. iPart = vParts[i];
  236. iSec = parseInt(iPart.substr(0, 2));
  237. if (isNaN(iSec)) {
  238. return null;
  239. }
  240. switch (i) {
  241. case 0:
  242. if (vFormatParts[0] === 'm' || vFormatParts[0] === 'n') {
  243. vDate.setMonth(iSec - 1);
  244. } else {
  245. vDate.setDate(iSec);
  246. }
  247. break;
  248. case 1:
  249. if (vFormatParts[0] === 'm' || vFormatParts[0] === 'n') {
  250. vDate.setDate(iSec);
  251. } else {
  252. vDate.setMonth(iSec - 1);
  253. }
  254. break;
  255. case 2:
  256. vYear = vDate.getFullYear();
  257. len = iPart.length;
  258. vDigit = len < 4 ? len : 4;
  259. vYear = parseInt(len < 4 ? vYear.toString().substr(0, 4 - len) + iPart : iPart.substr(0, 4));
  260. if (!vYear) {
  261. return null;
  262. }
  263. vDate.setFullYear(vYear);
  264. break;
  265. case 3:
  266. vDate.setHours(iSec);
  267. break;
  268. case 4:
  269. vDate.setMinutes(iSec);
  270. break;
  271. case 5:
  272. vDate.setSeconds(iSec);
  273. break;
  274. }
  275. n = iPart.substr(vDigit);
  276. if (n.length > 0) {
  277. vParts.splice(i + 1, 0, n);
  278. }
  279. }
  280. return vDate;
  281. },
  282. parseFormat: function (vChar, vDate) {
  283. var self = this, vSettings = self.dateSettings, fmt, backslash = /\\?(.?)/gi, doFormat = function (t, s) {
  284. return fmt[t] ? fmt[t]() : s;
  285. };
  286. fmt = {
  287. /////////
  288. // DAY //
  289. /////////
  290. /**
  291. * Day of month with leading 0: `01..31`
  292. * @return {string}
  293. */
  294. d: function () {
  295. return _lpad(fmt.j(), 2);
  296. },
  297. /**
  298. * Shorthand day name: `Mon...Sun`
  299. * @return {string}
  300. */
  301. D: function () {
  302. return vSettings.daysShort[fmt.w()];
  303. },
  304. /**
  305. * Day of month: `1..31`
  306. * @return {number}
  307. */
  308. j: function () {
  309. return vDate.getDate();
  310. },
  311. /**
  312. * Full day name: `Monday...Sunday`
  313. * @return {number}
  314. */
  315. l: function () {
  316. return vSettings.days[fmt.w()];
  317. },
  318. /**
  319. * ISO-8601 day of week: `1[Mon]..7[Sun]`
  320. * @return {number}
  321. */
  322. N: function () {
  323. return fmt.w() || 7;
  324. },
  325. /**
  326. * Day of week: `0[Sun]..6[Sat]`
  327. * @return {number}
  328. */
  329. w: function () {
  330. return vDate.getDay();
  331. },
  332. /**
  333. * Day of year: `0..365`
  334. * @return {number}
  335. */
  336. z: function () {
  337. var a = new Date(fmt.Y(), fmt.n() - 1, fmt.j()), b = new Date(fmt.Y(), 0, 1);
  338. return Math.round((a - b) / DAY);
  339. },
  340. //////////
  341. // WEEK //
  342. //////////
  343. /**
  344. * ISO-8601 week number
  345. * @return {number}
  346. */
  347. W: function () {
  348. var a = new Date(fmt.Y(), fmt.n() - 1, fmt.j() - fmt.N() + 3), b = new Date(a.getFullYear(), 0, 4);
  349. return _lpad(1 + Math.round((a - b) / DAY / 7), 2);
  350. },
  351. ///////////
  352. // MONTH //
  353. ///////////
  354. /**
  355. * Full month name: `January...December`
  356. * @return {string}
  357. */
  358. F: function () {
  359. return vSettings.months[vDate.getMonth()];
  360. },
  361. /**
  362. * Month w/leading 0: `01..12`
  363. * @return {string}
  364. */
  365. m: function () {
  366. return _lpad(fmt.n(), 2);
  367. },
  368. /**
  369. * Shorthand month name; `Jan...Dec`
  370. * @return {string}
  371. */
  372. M: function () {
  373. return vSettings.monthsShort[vDate.getMonth()];
  374. },
  375. /**
  376. * Month: `1...12`
  377. * @return {number}
  378. */
  379. n: function () {
  380. return vDate.getMonth() + 1;
  381. },
  382. /**
  383. * Days in month: `28...31`
  384. * @return {number}
  385. */
  386. t: function () {
  387. return (new Date(fmt.Y(), fmt.n(), 0)).getDate();
  388. },
  389. //////////
  390. // YEAR //
  391. //////////
  392. /**
  393. * Is leap year? `0 or 1`
  394. * @return {number}
  395. */
  396. L: function () {
  397. var Y = fmt.Y();
  398. return (Y % 4 === 0 && Y % 100 !== 0 || Y % 400 === 0) ? 1 : 0;
  399. },
  400. /**
  401. * ISO-8601 year
  402. * @return {number}
  403. */
  404. o: function () {
  405. var n = fmt.n(), W = fmt.W(), Y = fmt.Y();
  406. return Y + (n === 12 && W < 9 ? 1 : n === 1 && W > 9 ? -1 : 0);
  407. },
  408. /**
  409. * Full year: `e.g. 1980...2010`
  410. * @return {number}
  411. */
  412. Y: function () {
  413. return vDate.getFullYear();
  414. },
  415. /**
  416. * Last two digits of year: `00...99`
  417. * @return {string}
  418. */
  419. y: function () {
  420. return fmt.Y().toString().slice(-2);
  421. },
  422. //////////
  423. // TIME //
  424. //////////
  425. /**
  426. * Meridian lower: `am or pm`
  427. * @return {string}
  428. */
  429. a: function () {
  430. return fmt.A().toLowerCase();
  431. },
  432. /**
  433. * Meridian upper: `AM or PM`
  434. * @return {string}
  435. */
  436. A: function () {
  437. var n = fmt.G() < 12 ? 0 : 1;
  438. return vSettings.meridiem[n];
  439. },
  440. /**
  441. * Swatch Internet time: `000..999`
  442. * @return {string}
  443. */
  444. B: function () {
  445. var H = vDate.getUTCHours() * HOUR, i = vDate.getUTCMinutes() * 60, s = vDate.getUTCSeconds();
  446. return _lpad(Math.floor((H + i + s + HOUR) / 86.4) % 1000, 3);
  447. },
  448. /**
  449. * 12-Hours: `1..12`
  450. * @return {number}
  451. */
  452. g: function () {
  453. return fmt.G() % 12 || 12;
  454. },
  455. /**
  456. * 24-Hours: `0..23`
  457. * @return {number}
  458. */
  459. G: function () {
  460. return vDate.getHours();
  461. },
  462. /**
  463. * 12-Hours with leading 0: `01..12`
  464. * @return {string}
  465. */
  466. h: function () {
  467. return _lpad(fmt.g(), 2);
  468. },
  469. /**
  470. * 24-Hours w/leading 0: `00..23`
  471. * @return {string}
  472. */
  473. H: function () {
  474. return _lpad(fmt.G(), 2);
  475. },
  476. /**
  477. * Minutes w/leading 0: `00..59`
  478. * @return {string}
  479. */
  480. i: function () {
  481. return _lpad(vDate.getMinutes(), 2);
  482. },
  483. /**
  484. * Seconds w/leading 0: `00..59`
  485. * @return {string}
  486. */
  487. s: function () {
  488. return _lpad(vDate.getSeconds(), 2);
  489. },
  490. /**
  491. * Microseconds: `000000-999000`
  492. * @return {string}
  493. */
  494. u: function () {
  495. return _lpad(vDate.getMilliseconds() * 1000, 6);
  496. },
  497. //////////////
  498. // TIMEZONE //
  499. //////////////
  500. /**
  501. * Timezone identifier: `e.g. Atlantic/Azores, ...`
  502. * @return {string}
  503. */
  504. e: function () {
  505. var str = /\((.*)\)/.exec(String(vDate))[1];
  506. return str || 'Coordinated Universal Time';
  507. },
  508. /**
  509. * DST observed? `0 or 1`
  510. * @return {number}
  511. */
  512. I: function () {
  513. var a = new Date(fmt.Y(), 0), c = Date.UTC(fmt.Y(), 0),
  514. b = new Date(fmt.Y(), 6), d = Date.UTC(fmt.Y(), 6);
  515. return ((a - c) !== (b - d)) ? 1 : 0;
  516. },
  517. /**
  518. * Difference to GMT in hour format: `e.g. +0200`
  519. * @return {string}
  520. */
  521. O: function () {
  522. var tzo = vDate.getTimezoneOffset(), a = Math.abs(tzo);
  523. return (tzo > 0 ? '-' : '+') + _lpad(Math.floor(a / 60) * 100 + a % 60, 4);
  524. },
  525. /**
  526. * Difference to GMT with colon: `e.g. +02:00`
  527. * @return {string}
  528. */
  529. P: function () {
  530. var O = fmt.O();
  531. return (O.substr(0, 3) + ':' + O.substr(3, 2));
  532. },
  533. /**
  534. * Timezone abbreviation: `e.g. EST, MDT, ...`
  535. * @return {string}
  536. */
  537. T: function () {
  538. var str = (String(vDate).match(self.tzParts) || [""]).pop().replace(self.tzClip, "");
  539. return str || 'UTC';
  540. },
  541. /**
  542. * Timezone offset in seconds: `-43200...50400`
  543. * @return {number}
  544. */
  545. Z: function () {
  546. return -vDate.getTimezoneOffset() * 60;
  547. },
  548. ////////////////////
  549. // FULL DATE TIME //
  550. ////////////////////
  551. /**
  552. * ISO-8601 date
  553. * @return {string}
  554. */
  555. c: function () {
  556. return 'Y-m-d\\TH:i:sP'.replace(backslash, doFormat);
  557. },
  558. /**
  559. * RFC 2822 date
  560. * @return {string}
  561. */
  562. r: function () {
  563. return 'D, d M Y H:i:s O'.replace(backslash, doFormat);
  564. },
  565. /**
  566. * Seconds since UNIX epoch
  567. * @return {number}
  568. */
  569. U: function () {
  570. return vDate.getTime() / 1000 || 0;
  571. }
  572. };
  573. return doFormat(vChar, vChar);
  574. },
  575. formatDate: function (vDate, vFormat) {
  576. var self = this, i, n, len, str, vChar, vDateStr = '', BACKSLASH = '\\';
  577. if (typeof vDate === 'string') {
  578. vDate = self.parseDate(vDate, vFormat);
  579. if (!vDate) {
  580. return null;
  581. }
  582. }
  583. if (vDate instanceof Date) {
  584. len = vFormat.length;
  585. for (i = 0; i < len; i++) {
  586. vChar = vFormat.charAt(i);
  587. if (vChar === 'S' || vChar === BACKSLASH) {
  588. continue;
  589. }
  590. if (i > 0 && vFormat.charAt(i - 1) === BACKSLASH) {
  591. vDateStr += vChar;
  592. continue;
  593. }
  594. str = self.parseFormat(vChar, vDate);
  595. if (i !== (len - 1) && self.intParts.test(vChar) && vFormat.charAt(i + 1) === 'S') {
  596. n = parseInt(str) || 0;
  597. str += self.dateSettings.ordinal(n);
  598. }
  599. vDateStr += str;
  600. }
  601. return vDateStr;
  602. }
  603. return '';
  604. }
  605. };
  606. })();