php-date-formatter.js 23 KB

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