date.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /*!
  2. * All material copyright ESRI, All Rights Reserved, unless otherwise specified.
  3. * See https://github.com/Esri/calcite-components/blob/master/LICENSE.md for details.
  4. * v1.0.0-beta.82
  5. */
  6. /**
  7. * Check if date is within a min and max
  8. */
  9. function inRange(date, min, max) {
  10. const time = date.getTime();
  11. const afterMin = !(min instanceof Date) || time >= min.getTime();
  12. const beforeMax = !(max instanceof Date) || time <= max.getTime();
  13. return afterMin && beforeMax;
  14. }
  15. /**
  16. * Ensures date is within range,
  17. * returns min or max if out of bounds
  18. */
  19. function dateFromRange(date, min, max) {
  20. if (!(date instanceof Date)) {
  21. return null;
  22. }
  23. const time = date.getTime();
  24. const beforeMin = min instanceof Date && time < min.getTime();
  25. const afterMax = max instanceof Date && time > max.getTime();
  26. if (beforeMin) {
  27. return min;
  28. }
  29. if (afterMax) {
  30. return max;
  31. }
  32. return date;
  33. }
  34. /**
  35. * Parse an iso8601 string (YYYY-mm-dd) into a valid date.
  36. * TODO: handle time when time of day UI is added
  37. */
  38. function dateFromISO(iso8601) {
  39. if (iso8601 instanceof Date) {
  40. return iso8601;
  41. }
  42. if (!iso8601 || typeof iso8601 !== "string") {
  43. return null;
  44. }
  45. const d = iso8601.split(/[: T-]/).map(parseFloat);
  46. const date = new Date(d[0], (d[1] || 1) - 1, d[2] || 1);
  47. date.setFullYear(d[0]);
  48. if (isNaN(date.getTime())) {
  49. throw new Error(`Invalid ISO 8601 date: "${iso8601}"`);
  50. }
  51. return date;
  52. }
  53. /**
  54. * Return first portion of ISO string (YYYY-mm-dd)
  55. */
  56. function dateToISO(date) {
  57. if (typeof date === "string") {
  58. return date;
  59. }
  60. if (date instanceof Date) {
  61. return new Date(date.getTime() - date.getTimezoneOffset() * 60000).toISOString().split("T")[0];
  62. }
  63. return "";
  64. }
  65. /**
  66. * Check if two dates are the same day, month, year
  67. */
  68. function sameDate(d1, d2) {
  69. return (d1 instanceof Date &&
  70. d2 instanceof Date &&
  71. d1.getDate() === d2.getDate() &&
  72. d1.getMonth() === d2.getMonth() &&
  73. d1.getFullYear() === d2.getFullYear());
  74. }
  75. /**
  76. * Get a date one month in the past
  77. */
  78. function prevMonth(date) {
  79. const month = date.getMonth();
  80. const nextDate = new Date(date);
  81. nextDate.setMonth(month - 1);
  82. // date doesn't exist in new month, use last day
  83. if (month === nextDate.getMonth()) {
  84. return new Date(date.getFullYear(), month, 0);
  85. }
  86. return nextDate;
  87. }
  88. /**
  89. * Get a date one month in the future
  90. */
  91. function nextMonth(date) {
  92. const month = date.getMonth();
  93. const nextDate = new Date(date);
  94. nextDate.setMonth(month + 1);
  95. // date doesn't exist in new month, use last day
  96. if ((month + 2) % 7 === nextDate.getMonth() % 7) {
  97. return new Date(date.getFullYear(), month + 2, 0);
  98. }
  99. return nextDate;
  100. }
  101. /**
  102. * Translate a number into a given locals numeral system
  103. */
  104. function localizeNumber(num, localeData) {
  105. return String(num)
  106. .split("")
  107. .map((i) => localeData.numerals[i])
  108. .join("");
  109. }
  110. /**
  111. * Calculate actual number from localized string
  112. */
  113. function parseNumber(str, localeData) {
  114. const numerals = "0123456789";
  115. return parseInt(str
  116. .split("")
  117. .map((i) => numerals[localeData.numerals.indexOf(i)])
  118. .filter((num) => num)
  119. .join(""));
  120. }
  121. /**
  122. * Parse numeric units for day, month, and year from a localized string
  123. * month starts at 0 (can pass to date constructor)
  124. */
  125. function parseDateString(str, localeData) {
  126. const { separator, unitOrder } = localeData;
  127. const order = getOrder(unitOrder);
  128. const values = replaceArabicNumerals(str).split(separator);
  129. return {
  130. day: parseInt(values[order.indexOf("d")]),
  131. month: parseInt(values[order.indexOf("m")]) - 1,
  132. year: parseInt(values[order.indexOf("y")])
  133. };
  134. }
  135. /**
  136. * Convert eastern arbic numerals
  137. */
  138. function replaceArabicNumerals(str = "") {
  139. return str
  140. .replace(/[\u0660-\u0669]/g, (c) => (c.charCodeAt(0) - 0x0660))
  141. .replace(/[\u06f0-\u06f9]/g, (c) => (c.charCodeAt(0) - 0x06f0));
  142. }
  143. /**
  144. * Based on the unitOrder string, find order of month, day, and year for locale
  145. */
  146. function getOrder(unitOrder) {
  147. const signifiers = ["d", "m", "y"];
  148. const order = unitOrder.toLowerCase();
  149. return signifiers.sort((a, b) => order.indexOf(a) - order.indexOf(b));
  150. }
  151. /**
  152. * Get number of days between two dates
  153. */
  154. function getDaysDiff(date1, date2) {
  155. const ts1 = date1.getTime();
  156. const ts2 = date2.getTime();
  157. return (ts1 - ts2) / (1000 * 3600 * 24);
  158. }
  159. export { dateFromISO as a, dateFromRange as b, getOrder as c, dateToISO as d, parseNumber as e, parseDateString as f, getDaysDiff as g, inRange as i, localizeNumber as l, nextMonth as n, prevMonth as p, sameDate as s };