date.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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. export 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. export 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. export 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. export 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. export 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. export 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. export 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. export 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. export 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. export 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. export 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. export 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. export function getDaysDiff(date1, date2) {
  155. const ts1 = date1.getTime();
  156. const ts2 = date2.getTime();
  157. return (ts1 - ts2) / (1000 * 3600 * 24);
  158. }