parseIso.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. var some = require('../array/some');
  2. var datePatterns = [
  3. /^([0-9]{4})$/, // YYYY
  4. /^([0-9]{4})-([0-9]{2})$/, // YYYY-MM (YYYYMM not allowed)
  5. /^([0-9]{4})-?([0-9]{2})-?([0-9]{2})$/ // YYYY-MM-DD or YYYYMMDD
  6. ];
  7. var ORD_DATE = /^([0-9]{4})-?([0-9]{3})$/; // YYYY-DDD
  8. var timePatterns = [
  9. /^([0-9]{2}(?:\.[0-9]*)?)$/, // HH.hh
  10. /^([0-9]{2}):?([0-9]{2}(?:\.[0-9]*)?)$/, // HH:MM.mm
  11. /^([0-9]{2}):?([0-9]{2}):?([0-9]{2}(\.[0-9]*)?)$/ // HH:MM:SS.ss
  12. ];
  13. var DATE_TIME = /^(.+)T(.+)$/;
  14. var TIME_ZONE = /^(.+)([+\-])([0-9]{2}):?([0-9]{2})$/;
  15. function matchAll(str, patterns) {
  16. var match;
  17. var found = some(patterns, function(pattern) {
  18. return !!(match = pattern.exec(str));
  19. });
  20. return found ? match : null;
  21. }
  22. function getDate(year, month, day) {
  23. var date = new Date(Date.UTC(year, month, day));
  24. // Explicitly set year to avoid Date.UTC making dates < 100 relative to
  25. // 1900
  26. date.setUTCFullYear(year);
  27. var valid =
  28. date.getUTCFullYear() === year &&
  29. date.getUTCMonth() === month &&
  30. date.getUTCDate() === day;
  31. return valid ? +date : NaN;
  32. }
  33. function parseOrdinalDate(str) {
  34. var match = ORD_DATE.exec(str);
  35. if (match ) {
  36. var year = +match[1],
  37. day = +match[2],
  38. date = new Date(Date.UTC(year, 0, day));
  39. if (date.getUTCFullYear() === year) {
  40. return +date;
  41. }
  42. }
  43. return NaN;
  44. }
  45. function parseDate(str) {
  46. var match, year, month, day;
  47. match = matchAll(str, datePatterns);
  48. if (match === null) {
  49. // Ordinal dates are verified differently.
  50. return parseOrdinalDate(str);
  51. }
  52. year = (match[1] === void 0) ? 0 : +match[1];
  53. month = (match[2] === void 0) ? 0 : +match[2] - 1;
  54. day = (match[3] === void 0) ? 1 : +match[3];
  55. return getDate(year, month, day);
  56. }
  57. function getTime(hr, min, sec) {
  58. var valid =
  59. (hr < 24 && hr >= 0 &&
  60. min < 60 && min >= 0 &&
  61. sec < 60 && min >= 0) ||
  62. (hr === 24 && min === 0 && sec === 0);
  63. if (!valid) {
  64. return NaN;
  65. }
  66. return ((hr * 60 + min) * 60 + sec) * 1000;
  67. }
  68. function parseOffset(str) {
  69. var match;
  70. if (str.charAt(str.length - 1) === 'Z') {
  71. str = str.substring(0, str.length - 1);
  72. } else {
  73. match = TIME_ZONE.exec(str);
  74. if (match) {
  75. var hours = +match[3],
  76. minutes = (match[4] === void 0) ? 0 : +match[4],
  77. offset = getTime(hours, minutes, 0);
  78. if (match[2] === '-') {
  79. offset *= -1;
  80. }
  81. return { offset: offset, time: match[1] };
  82. }
  83. }
  84. // No time zone specified, assume UTC
  85. return { offset: 0, time: str };
  86. }
  87. function parseTime(str) {
  88. var match;
  89. var offset = parseOffset(str);
  90. str = offset.time;
  91. offset = offset.offset;
  92. if (isNaN(offset)) {
  93. return NaN;
  94. }
  95. match = matchAll(str, timePatterns);
  96. if (match === null) {
  97. return NaN;
  98. }
  99. var hours = (match[1] === void 0) ? 0 : +match[1],
  100. minutes = (match[2] === void 0) ? 0 : +match[2],
  101. seconds = (match[3] === void 0) ? 0 : +match[3];
  102. return getTime(hours, minutes, seconds) - offset;
  103. }
  104. /**
  105. * Parse an ISO8601 formatted date string, and return a Date object.
  106. */
  107. function parseISO8601(str){
  108. var match = DATE_TIME.exec(str);
  109. if (!match) {
  110. // No time specified
  111. return parseDate(str);
  112. }
  113. return parseDate(match[1]) + parseTime(match[2]);
  114. }
  115. module.exports = parseISO8601;