time.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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.97
  5. */
  6. import { isValidNumber } from "./number";
  7. import { getSupportedLocale, getSupportedNumberingSystem } from "./locale";
  8. export const maxTenthForMinuteAndSecond = 5;
  9. function createLocaleDateTimeFormatter(locale, numberingSystem, includeSeconds = true) {
  10. try {
  11. const options = {
  12. hour: "2-digit",
  13. minute: "2-digit",
  14. timeZone: "UTC",
  15. numberingSystem: getSupportedNumberingSystem(numberingSystem)
  16. };
  17. if (includeSeconds) {
  18. options.second = "2-digit";
  19. }
  20. return new Intl.DateTimeFormat(getSupportedLocale(locale), options);
  21. }
  22. catch (error) {
  23. throw new Error(`Invalid locale supplied while attempting to create a DateTime formatter: ${locale}`);
  24. }
  25. }
  26. export function formatTimePart(number) {
  27. const numberAsString = number.toString();
  28. return number >= 0 && number <= 9 ? numberAsString.padStart(2, "0") : numberAsString;
  29. }
  30. export function formatTimeString(value) {
  31. if (!isValidTime(value)) {
  32. return null;
  33. }
  34. const [hourString, minuteString, secondString] = value.split(":");
  35. const hour = formatTimePart(parseInt(hourString));
  36. const minute = formatTimePart(parseInt(minuteString));
  37. if (secondString) {
  38. const second = formatTimePart(parseInt(secondString));
  39. return `${hour}:${minute}:${second}`;
  40. }
  41. return `${hour}:${minute}`;
  42. }
  43. export function getLocaleHourCycle(locale, numberingSystem) {
  44. const formatter = createLocaleDateTimeFormatter(locale, numberingSystem);
  45. const parts = formatter.formatToParts(new Date(Date.UTC(0, 0, 0, 0, 0, 0)));
  46. return getLocalizedTimePart("meridiem", parts) ? "12" : "24";
  47. }
  48. function getLocalizedTimePart(part, parts) {
  49. var _a, _b, _c, _d;
  50. if (!part || !parts) {
  51. return null;
  52. }
  53. if (part === "hourSuffix") {
  54. const hourIndex = parts.indexOf(parts.find(({ type }) => type === "hour"));
  55. const minuteIndex = parts.indexOf(parts.find(({ type }) => type === "minute"));
  56. const hourSuffix = parts[hourIndex + 1];
  57. return hourSuffix && hourSuffix.type === "literal" && minuteIndex - hourIndex === 2
  58. ? ((_a = hourSuffix.value) === null || _a === void 0 ? void 0 : _a.trim()) || null
  59. : null;
  60. }
  61. if (part === "minuteSuffix") {
  62. const minuteIndex = parts.indexOf(parts.find(({ type }) => type === "minute"));
  63. const secondIndex = parts.indexOf(parts.find(({ type }) => type === "second"));
  64. const minuteSuffix = parts[minuteIndex + 1];
  65. return minuteSuffix && minuteSuffix.type === "literal" && secondIndex - minuteIndex === 2
  66. ? ((_b = minuteSuffix.value) === null || _b === void 0 ? void 0 : _b.trim()) || null
  67. : null;
  68. }
  69. if (part === "secondSuffix") {
  70. const secondIndex = parts.indexOf(parts.find(({ type }) => type === "second"));
  71. const secondSuffix = parts[secondIndex + 1];
  72. return secondSuffix && secondSuffix.type === "literal" ? ((_c = secondSuffix.value) === null || _c === void 0 ? void 0 : _c.trim()) || null : null;
  73. }
  74. return ((_d = parts.find(({ type }) => (part == "meridiem" ? type === "dayPeriod" : type === part))) === null || _d === void 0 ? void 0 : _d.value) || null;
  75. }
  76. export function getMeridiem(hour) {
  77. if (!isValidNumber(hour)) {
  78. return null;
  79. }
  80. const hourAsNumber = parseInt(hour);
  81. return hourAsNumber >= 0 && hourAsNumber <= 11 ? "AM" : "PM";
  82. }
  83. export function isValidTime(value) {
  84. if (!value || value.startsWith(":") || value.endsWith(":")) {
  85. return false;
  86. }
  87. const splitValue = value.split(":");
  88. const validLength = splitValue.length > 1 && splitValue.length < 4;
  89. if (!validLength) {
  90. return false;
  91. }
  92. const [hour, minute, second] = splitValue;
  93. const hourAsNumber = parseInt(splitValue[0]);
  94. const minuteAsNumber = parseInt(splitValue[1]);
  95. const secondAsNumber = parseInt(splitValue[2]);
  96. const hourValid = isValidNumber(hour) && hourAsNumber >= 0 && hourAsNumber < 24;
  97. const minuteValid = isValidNumber(minute) && minuteAsNumber >= 0 && minuteAsNumber < 60;
  98. const secondValid = isValidNumber(second) && secondAsNumber >= 0 && secondAsNumber < 60;
  99. if ((hourValid && minuteValid && !second) || (hourValid && minuteValid && secondValid)) {
  100. return true;
  101. }
  102. }
  103. function isValidTimePart(value, part) {
  104. if (part === "meridiem") {
  105. return value === "AM" || value === "PM";
  106. }
  107. if (!isValidNumber(value)) {
  108. return false;
  109. }
  110. const valueAsNumber = Number(value);
  111. return part === "hour" ? valueAsNumber >= 0 && valueAsNumber < 24 : valueAsNumber >= 0 && valueAsNumber < 60;
  112. }
  113. export function localizeTimePart({ value, part, locale, numberingSystem }) {
  114. if (!isValidTimePart(value, part)) {
  115. return;
  116. }
  117. const valueAsNumber = parseInt(value);
  118. const date = new Date(Date.UTC(0, 0, 0, part === "hour" ? valueAsNumber : part === "meridiem" ? (value === "AM" ? 0 : 12) : 0, part === "minute" ? valueAsNumber : 0, part === "second" ? valueAsNumber : 0));
  119. if (!date) {
  120. return;
  121. }
  122. const formatter = createLocaleDateTimeFormatter(locale, numberingSystem);
  123. const parts = formatter.formatToParts(date);
  124. return getLocalizedTimePart(part, parts);
  125. }
  126. export function localizeTimeString({ value, locale, numberingSystem, includeSeconds = true }) {
  127. if (!isValidTime(value)) {
  128. return null;
  129. }
  130. const { hour, minute, second = "0" } = parseTimeString(value);
  131. const dateFromTimeString = new Date(Date.UTC(0, 0, 0, parseInt(hour), parseInt(minute), parseInt(second)));
  132. const formatter = createLocaleDateTimeFormatter(locale, numberingSystem, includeSeconds);
  133. return (formatter === null || formatter === void 0 ? void 0 : formatter.format(dateFromTimeString)) || null;
  134. }
  135. export function localizeTimeStringToParts({ value, locale, numberingSystem }) {
  136. if (!isValidTime(value)) {
  137. return null;
  138. }
  139. const { hour, minute, second = "0" } = parseTimeString(value);
  140. const dateFromTimeString = new Date(Date.UTC(0, 0, 0, parseInt(hour), parseInt(minute), parseInt(second)));
  141. if (dateFromTimeString) {
  142. const formatter = createLocaleDateTimeFormatter(locale, numberingSystem);
  143. const parts = formatter.formatToParts(dateFromTimeString);
  144. return {
  145. localizedHour: getLocalizedTimePart("hour", parts),
  146. localizedHourSuffix: getLocalizedTimePart("hourSuffix", parts),
  147. localizedMinute: getLocalizedTimePart("minute", parts),
  148. localizedMinuteSuffix: getLocalizedTimePart("minuteSuffix", parts),
  149. localizedSecond: getLocalizedTimePart("second", parts),
  150. localizedSecondSuffix: getLocalizedTimePart("secondSuffix", parts),
  151. localizedMeridiem: getLocalizedTimePart("meridiem", parts)
  152. };
  153. }
  154. return null;
  155. }
  156. export function getTimeParts({ value, locale, numberingSystem }) {
  157. if (!isValidTime(value)) {
  158. return null;
  159. }
  160. const { hour, minute, second = "0" } = parseTimeString(value);
  161. const dateFromTimeString = new Date(Date.UTC(0, 0, 0, parseInt(hour), parseInt(minute), parseInt(second)));
  162. if (dateFromTimeString) {
  163. const formatter = createLocaleDateTimeFormatter(locale, numberingSystem);
  164. const parts = formatter.formatToParts(dateFromTimeString);
  165. return parts;
  166. }
  167. return null;
  168. }
  169. export function parseTimeString(value) {
  170. if (isValidTime(value)) {
  171. const [hour, minute, second] = value.split(":");
  172. return {
  173. hour,
  174. minute,
  175. second
  176. };
  177. }
  178. return {
  179. hour: null,
  180. minute: null,
  181. second: null
  182. };
  183. }