PageRenderTime 24ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/node_modules/twig/node_modules/phpjs/functions/datetime/strptime.js

https://gitlab.com/rickoverman/doo-cli
JavaScript | 365 lines | 256 code | 19 blank | 90 comment | 22 complexity | cb64c6e47c945c62fb36861e0dd6ed4c MD5 | raw file
  1. function strptime(dateStr, format) {
  2. // discuss at: http://phpjs.org/functions/strptime/
  3. // original by: Brett Zamir (http://brett-zamir.me)
  4. // original by: strftime
  5. // depends on: setlocale
  6. // depends on: array_map
  7. // test: skip
  8. // example 1: strptime('20091112222135', '%Y%m%d%H%M%S'); // Return value will depend on date and locale
  9. // example 1: strptime('2009extra', '%Y');
  10. // returns 1: {tm_sec: 35, tm_min: 21, tm_hour: 22, tm_mday: 12, tm_mon: 10, tm_year: 109, tm_wday: 4, tm_yday: 315, unparsed: ''}
  11. // returns 1: {tm_sec:0, tm_min:0, tm_hour:0, tm_mday:0, tm_mon:0, tm_year:109, tm_wday:3, tm_yday: -1, unparsed: 'extra'}
  12. // tm_isdst is in other docs; why not PHP?
  13. // Needs more thorough testing and examples
  14. var retObj = {
  15. tm_sec: 0,
  16. tm_min: 0,
  17. tm_hour: 0,
  18. tm_mday: 0,
  19. tm_mon: 0,
  20. tm_year: 0,
  21. tm_wday: 0,
  22. tm_yday: 0,
  23. unparsed: ''
  24. },
  25. i = 0,
  26. that = this,
  27. amPmOffset = 0,
  28. prevHour = false,
  29. _reset = function(dateObj, realMday) {
  30. // realMday is to allow for a value of 0 in return results (but without
  31. // messing up the Date() object)
  32. var jan1,
  33. o = retObj,
  34. d = dateObj;
  35. o.tm_sec = d.getUTCSeconds();
  36. o.tm_min = d.getUTCMinutes();
  37. o.tm_hour = d.getUTCHours();
  38. o.tm_mday = realMday === 0 ? realMday : d.getUTCDate();
  39. o.tm_mon = d.getUTCMonth();
  40. o.tm_year = d.getUTCFullYear() - 1900;
  41. o.tm_wday = realMday === 0 ? (d.getUTCDay() > 0 ? d.getUTCDay() - 1 : 6) : d.getUTCDay();
  42. jan1 = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
  43. o.tm_yday = Math.ceil((d - jan1) / (1000 * 60 * 60 * 24));
  44. },
  45. _date = function() {
  46. var o = retObj;
  47. // We set date to at least 1 to ensure year or month doesn't go backwards
  48. return _reset(new Date(Date.UTC(o.tm_year + 1900, o.tm_mon, o.tm_mday || 1, o.tm_hour, o.tm_min, o.tm_sec)),
  49. o.tm_mday);
  50. };
  51. // BEGIN STATIC
  52. var _NWS = /\S/,
  53. _WS = /\s/;
  54. var _aggregates = {
  55. c: 'locale',
  56. D: '%m/%d/%y',
  57. F: '%y-%m-%d',
  58. r: 'locale',
  59. R: '%H:%M',
  60. T: '%H:%M:%S',
  61. x: 'locale',
  62. X: 'locale'
  63. };
  64. /* Fix: Locale alternatives are supported though not documented in PHP; see http://linux.die.net/man/3/strptime
  65. Ec
  66. EC
  67. Ex
  68. EX
  69. Ey
  70. EY
  71. Od or Oe
  72. OH
  73. OI
  74. Om
  75. OM
  76. OS
  77. OU
  78. Ow
  79. OW
  80. Oy
  81. */
  82. var _preg_quote = function(str) {
  83. return (str + '')
  84. .replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!<>\|\:])/g, '\\$1');
  85. };
  86. // END STATIC
  87. // BEGIN REDUNDANT
  88. this.php_js = this.php_js || {};
  89. this.setlocale('LC_ALL', 0); // ensure setup of localization variables takes place
  90. // END REDUNDANT
  91. var phpjs = this.php_js;
  92. var locale = phpjs.localeCategories.LC_TIME;
  93. var locales = phpjs.locales;
  94. var lc_time = locales[locale].LC_TIME;
  95. // First replace aggregates (run in a loop because an agg may be made up of other aggs)
  96. while (format.match(/%[cDFhnrRtTxX]/)) {
  97. format = format.replace(/%([cDFhnrRtTxX])/g, function(m0, m1) {
  98. var f = _aggregates[m1];
  99. return (f === 'locale' ? lc_time[m1] : f);
  100. });
  101. }
  102. var _addNext = function(j, regex, cb) {
  103. if (typeof regex === 'string') {
  104. regex = new RegExp('^' + regex, 'i');
  105. }
  106. var check = dateStr.slice(j);
  107. var match = regex.exec(check);
  108. // Even if the callback returns null after assigning to the return object, the object won't be saved anyways
  109. var testNull = match ? cb.apply(null, match) : null;
  110. if (testNull === null) {
  111. throw 'No match in string';
  112. }
  113. return j + match[0].length;
  114. };
  115. var _addLocalized = function(j, formatChar, category) {
  116. return _addNext(j, that.array_map(
  117. _preg_quote, lc_time[formatChar])
  118. .join('|'), // Could make each parenthesized instead and pass index to callback
  119. function(m) {
  120. var match = lc_time[formatChar].search(new RegExp('^' + _preg_quote(m) + '$', 'i'));
  121. if (match) {
  122. retObj[category] = match[0];
  123. }
  124. });
  125. };
  126. // BEGIN PROCESSING CHARACTERS
  127. for (i = 0, j = 0; i < format.length; i++) {
  128. if (format.charAt(i) === '%') {
  129. var literalPos = ['%', 'n', 't'].indexOf(format.charAt(i + 1));
  130. if (literalPos !== -1) {
  131. if (['%', '\n', '\t'].indexOf(dateStr.charAt(j)) === literalPos) { // a matched literal
  132. ++i;
  133. ++j; // skip beyond
  134. continue;
  135. }
  136. // Format indicated a percent literal, but not actually present
  137. return false;
  138. }
  139. var formatChar = format.charAt(i + 1);
  140. try {
  141. switch (formatChar) {
  142. case 'a':
  143. // Fall-through // Sun-Sat
  144. case 'A':
  145. // Sunday-Saturday
  146. j = _addLocalized(j, formatChar, 'tm_wday'); // Changes nothing else
  147. break;
  148. case 'h':
  149. // Fall-through (alias of 'b');
  150. case 'b':
  151. // Jan-Dec
  152. j = _addLocalized(j, 'b', 'tm_mon');
  153. _date(); // Also changes wday, yday
  154. break;
  155. case 'B':
  156. // January-December
  157. j = _addLocalized(j, formatChar, 'tm_mon');
  158. _date(); // Also changes wday, yday
  159. break;
  160. case 'C':
  161. // 0+; century (19 for 20th)
  162. j = _addNext(j, /^\d?\d/, // PHP docs say two-digit, but accepts one-digit (two-digit max)
  163. function(d) {
  164. var year = (parseInt(d, 10) - 19) * 100;
  165. retObj.tm_year = year;
  166. _date();
  167. if (!retObj.tm_yday) {
  168. retObj.tm_yday = -1;
  169. }
  170. // Also changes wday; and sets yday to -1 (always?)
  171. });
  172. break;
  173. case 'd':
  174. // Fall-through 01-31 day
  175. case 'e':
  176. // 1-31 day
  177. j = _addNext(j, formatChar === 'd' ? /^(0[1-9]|[1-2]\d|3[0-1])/ : /^([1-2]\d|3[0-1]|[1-9])/,
  178. function(d) {
  179. var dayMonth = parseInt(d, 10);
  180. retObj.tm_mday = dayMonth;
  181. _date(); // Also changes w_day, y_day
  182. });
  183. break;
  184. case 'g':
  185. // No apparent effect; 2-digit year (see 'V')
  186. break;
  187. case 'G':
  188. // No apparent effect; 4-digit year (see 'V')'
  189. break;
  190. case 'H':
  191. // 00-23 hours
  192. j = _addNext(j, /^([0-1]\d|2[0-3])/, function(d) {
  193. var hour = parseInt(d, 10);
  194. retObj.tm_hour = hour;
  195. // Changes nothing else
  196. });
  197. break;
  198. case 'l':
  199. // Fall-through of lower-case 'L'; 1-12 hours
  200. case 'I':
  201. // 01-12 hours
  202. j = _addNext(j, formatChar === 'l' ? /^([1-9]|1[0-2])/ : /^(0[1-9]|1[0-2])/, function(d) {
  203. var hour = parseInt(d, 10) - 1 + amPmOffset;
  204. retObj.tm_hour = hour;
  205. prevHour = true; // Used for coordinating with am-pm
  206. // Changes nothing else, but affected by prior 'p/P'
  207. });
  208. break;
  209. case 'j':
  210. // 001-366 day of year
  211. j = _addNext(j, /^(00[1-9]|0[1-9]\d|[1-2]\d\d|3[0-6][0-6])/, function(d) {
  212. var dayYear = parseInt(d, 10) - 1;
  213. retObj.tm_yday = dayYear;
  214. // Changes nothing else (oddly, since if original by a given year, could calculate other fields)
  215. });
  216. break;
  217. case 'm':
  218. // 01-12 month
  219. j = _addNext(j, /^(0[1-9]|1[0-2])/, function(d) {
  220. var month = parseInt(d, 10) - 1;
  221. retObj.tm_mon = month;
  222. _date(); // Also sets wday and yday
  223. });
  224. break;
  225. case 'M':
  226. // 00-59 minutes
  227. j = _addNext(j, /^[0-5]\d/, function(d) {
  228. var minute = parseInt(d, 10);
  229. retObj.tm_min = minute;
  230. // Changes nothing else
  231. });
  232. break;
  233. case 'P':
  234. // Seems not to work; AM-PM
  235. return false; // Could make fall-through instead since supposed to be a synonym despite PHP docs
  236. case 'p':
  237. // am-pm
  238. j = _addNext(j, /^(am|pm)/i, function(d) {
  239. // No effect on 'H' since already 24 hours but
  240. // works before or after setting of l/I hour
  241. amPmOffset = (/a/)
  242. .test(d) ? 0 : 12;
  243. if (prevHour) {
  244. retObj.tm_hour += amPmOffset;
  245. }
  246. });
  247. break;
  248. case 's':
  249. // Unix timestamp (in seconds)
  250. j = _addNext(j, /^\d+/, function(d) {
  251. var timestamp = parseInt(d, 10);
  252. var date = new Date(Date.UTC(timestamp * 1000));
  253. _reset(date);
  254. // Affects all fields, but can't be negative (and initial + not allowed)
  255. });
  256. break;
  257. case 'S':
  258. // 00-59 seconds
  259. j = _addNext(j, /^[0-5]\d/, // strptime also accepts 60-61 for some reason
  260. function(d) {
  261. var second = parseInt(d, 10);
  262. retObj.tm_sec = second;
  263. // Changes nothing else
  264. });
  265. break;
  266. case 'u':
  267. // Fall-through; 1 (Monday)-7(Sunday)
  268. case 'w':
  269. // 0 (Sunday)-6(Saturday)
  270. j = _addNext(j, /^\d/, function(d) {
  271. retObj.tm_wday = d - (formatChar === 'u');
  272. // Changes nothing else apparently
  273. });
  274. break;
  275. case 'U':
  276. // Fall-through (week of year, from 1st Sunday)
  277. case 'V':
  278. // Fall-through (ISO-8601:1988 week number; from first 4-weekday week, starting with Monday)
  279. case 'W':
  280. // Apparently ignored (week of year, from 1st Monday)
  281. break;
  282. case 'y':
  283. // 69 (or higher) for 1969+, 68 (or lower) for 2068-
  284. j = _addNext(j, /^\d?\d/, // PHP docs say two-digit, but accepts one-digit (two-digit max)
  285. function(d) {
  286. d = parseInt(d, 10);
  287. var year = d >= 69 ? d : d + 100;
  288. retObj.tm_year = year;
  289. _date();
  290. if (!retObj.tm_yday) {
  291. retObj.tm_yday = -1;
  292. }
  293. // Also changes wday; and sets yday to -1 (always?)
  294. });
  295. break;
  296. case 'Y':
  297. // 2010 (4-digit year)
  298. j = _addNext(j, /^\d{1,4}/, // PHP docs say four-digit, but accepts one-digit (four-digit max)
  299. function(d) {
  300. var year = (parseInt(d, 10)) - 1900;
  301. retObj.tm_year = year;
  302. _date();
  303. if (!retObj.tm_yday) {
  304. retObj.tm_yday = -1;
  305. }
  306. // Also changes wday; and sets yday to -1 (always?)
  307. });
  308. break;
  309. case 'z':
  310. // Timezone; on my system, strftime gives -0800, but strptime seems not to alter hour setting
  311. break;
  312. case 'Z':
  313. // Timezone; on my system, strftime gives PST, but strptime treats text as unparsed
  314. break;
  315. default:
  316. throw 'Unrecognized formatting character in strptime()';
  317. }
  318. } catch (e) {
  319. if (e === 'No match in string') { // Allow us to exit
  320. return false; // There was supposed to be a matching format but there wasn't
  321. }
  322. }++i; // Calculate skipping beyond initial percent too
  323. } else if (format.charAt(i) !== dateStr.charAt(j)) {
  324. // If extra whitespace at beginning or end of either, or between formats, no problem
  325. // (just a problem when between % and format specifier)
  326. // If the string has white-space, it is ok to ignore
  327. if (dateStr.charAt(j)
  328. .search(_WS) !== -1) {
  329. j++;
  330. i--; // Let the next iteration try again with the same format character
  331. } else if (format.charAt(i)
  332. .search(_NWS) !== -1) { // Any extra formatting characters besides white-space causes
  333. // problems (do check after WS though, as may just be WS in string before next character)
  334. return false;
  335. }
  336. // Extra WS in format
  337. // Adjust strings when encounter non-matching whitespace, so they align in future checks above
  338. // Will check on next iteration (against same (non-WS) string character)
  339. } else {
  340. j++;
  341. }
  342. }
  343. // POST-PROCESSING
  344. retObj.unparsed = dateStr.slice(j); // Will also get extra whitespace; empty string if none
  345. return retObj;
  346. }