Temporal Книга рецептов¶
Практическая книга рецептов по JavaScript Temporal: даты, время, часовые пояса, календари и типовые операции с примерами кода.
Обзор¶
Temporal — современный API JavaScript для работы с датами, временем, часовыми поясами и календарями. Он помогает безопасно выполнять вычисления и преобразования, избегая неоднозначностей и ошибок старого объекта Date.
Часто задаваемые вопросы¶
Это некоторые из наиболее распространенных задач, о которых люди задают вопросы в StackOverflow с устаревшим Date. Вот как они будут выглядеть при использовании Temporal.
Текущая дата и время¶
Как получить текущую дату и время в местном часовом поясе?
Обратите внимание: если вам нужна только дата, а не время, вам следует использовать Temporal.PlainDate. Если вам нужно и то, и другое, используйте Temporal.PlainDateTime.
Временная метка Unix¶
Как получить временную метку Unix?
Преобразование между типами Temporal и устаревшим Date¶
Устаревший Date => Temporal.Instant и/или Temporal.ZonedDateTime¶
Вот как можно преобразовать устаревший ECMAScript Date в экземпляр Temporal.Instant или Temporal.ZonedDateTime, соответствующий тому же моменту в точное время.
Значения только для Date: устаревший Date => Temporal.PlainDate¶
Распространенная ошибка возникает из-за простого вопроса: какая дата (год, месяц и день) представлена этим Date? Проблема: ответ зависит от часового пояса. Тот же Date может быть 31 декабря в Сан-Франциско, но 1 января в Лондоне или Токио.
Поэтому очень важно интерпретировать Date в контексте правильного часового пояса прежде пытаться извлечь год, месяц или день или перед выполнением вычислений типа «это произошло вчера?» с участием единиц даты. По этой причине Temporal.Instant (который является эквивалентом Temporal Date) не имеет свойств year, month, day. Чтобы получить доступ к единицам даты или времени в Temporal, необходимо указать часовой пояс, как описано в примере кода выше.
Другой случай, подверженный ошибкам, — это когда Date (ab) используется для хранения значения только даты, например даты рождения пользователя. В Date эти значения обычно сохраняются с указанием времени полуночи, но для правильного считывания даты необходимо знать, полночь какого часового пояса использовалась для создания Date. Например, new Date(2000, 0, 1) использует часовой пояс вызывающего абонента, а new Date('2000-01-01') использует UTC.
Чтобы правильно преобразовать Date только по дате в Temporal.PlainDate, не будучи уязвимым для ошибок с отклонением на один день, вы должны определить, полночь какого часового пояса использовалась для создания Date, а затем использовать тот же часовой пояс при преобразовании из Temporal.Instant в Temporal.PlainDate.
Типы Temporal => устаревший Date¶
Устаревший Date представляет точное время, поэтому легко преобразовать экземпляр Temporal.Instant или Temporal.ZonedDateTime в соответствующий ему устаревший экземпляр Date.
Создание¶
Элемент ввода календаря¶
Вы можете использовать объекты Temporal для установки свойств элемента управления «Календарь». Вот пример использования HTML-элемента <input type="date">, в котором любой день, кроме «сегодня», отключен и недоступен для выбора.
(Чтобы вернуть объект Temporal из элемента управления «Календарь», см. пример «Сколько дней до будущей даты».)
Преобразование между типами¶
Полдень определенного дня¶
Пример объединения календарной даты (Temporal.PlainDate) и времени настенных часов (Temporal.PlainTime) в Temporal.PlainDateTime.
День рождения в 2030 году¶
Пример объединения дня календаря (Temporal.PlainMonthDay) и года в Temporal.PlainDate.
Сериализация¶
Мгновенное зонирование по мгновенному времени и часовому поясу¶
Чтобы сериализовать Temporal.Instant точного времени в строку, используйте toString(). Без каких-либо аргументов вы получите строку во времени UTC.
Если вам нужно, чтобы ваша строка включала смещение UTC, используйте опцию timeZone Temporal.Instant.prototype.toString(), которая вернет сериализацию строки времени настенных часов в этом часовом поясе, соответствующую точному времени.
При этом теряется информация о том, в каком часовом поясе находилась строка, поскольку сохраняется только смещение UTC от часового пояса в это конкретное время. Если вам нужно, чтобы ваша строка включала имя часового пояса, вместо этого используйте Temporal.ZonedDateTime, который сохранит эту информацию.
Сортировка¶
Каждый тип Temporal имеет статический метод compare(), который можно передать в Array.prototype.sort() в качестве функции сравнения для сортировки массива типов Temporal.
Сортировка значений PlainDateTime¶
Отсортируйте список Temporal.PlainDateTime, например, чтобы расположить расписание конференций в правильном порядке. Сортировка других типов Temporal будет работать точно так же.
Сортировка строк даты/времени ISO¶
Сортируйте список строк даты и времени ISO 8601 или RFC 9557, например, чтобы упорядочить записи журнала.
Округление¶
Округляем время до целых часов¶
Используйте метод round() каждого типа Temporal, если вы хотите округлить поля времени. Вот пример округления времени вниз до предыдущего целого часа:
Округляем дату до ближайшего начала месяца¶
Округление определено только для полей времени. Округление поля даты может быть неоднозначным, поэтому типы, содержащие только дату, такие как Temporal.PlainDate, не имеют метода round(). Например, если вам нужно округлить дату до ближайшего месяца, вы должны явно указать, какой тип округления вы хотите. Вот пример округления до ближайшего начала месяца, округления в большую сторону в случае ничьей:
См. также раздел «Отодвинуть дату запуска», чтобы узнать более простой способ безусловного округления до следующего начала месяца.
Преобразование часового пояса¶
Сохранение местного времени¶
Сопоставьте дату и время дня без зоны с экземпляром Temporal.Instant, в котором локальная дата и время суток в указанном часовом поясе соответствуют им. Это легко сделать с помощью dateTime.toZonedDateTime(timeZone).toInstant(), но вот пример реализации поведения устранения неоднозначности, отличного от 'compatible', 'earlier', 'later' и 'reject', встроенных в Temporal.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | |
Сохранение точного времени¶
Сопоставьте зональную дату и время суток с другой зональной датой и временем суток в целевом часовом поясе в соответствующее точное время. Это можно использовать при преобразовании вводимых пользователем значений даты и времени между часовыми поясами.
Вот еще один пример, аналогичный предыдущему, с использованием часового пояса для будущих событий. Время и место серии будущих встреч хранятся в виде пары строк: одна для календарной даты и времени настенных часов, а другая для часового пояса. Они не могут быть сохранены как точное время, потому что между настоящим моментом и временем, когда произойдет событие, правила часового пояса для перехода на летнее время могут измениться — например, Бразилия отменила летнее время в 2019 году — но собрание все равно будет проводиться в то же время на настенных часах в этот день. Поэтому, если правила часового пояса изменятся, точное время мероприятия изменится.
В этом примере рассчитывается время начала всех собраний Ecma TC39 в 2019 году по местному времени в Токио.
Ежедневное событие по местному времени¶
Аналогично предыдущему рецепту рассчитайте точное время ежедневных событий, происходящих в определенное местное время в определенном часовом поясе.
Смещение UTC для зонального события в виде строки¶
Используйте Temporal.Instant.toZonedDateTimeISO() и Temporal.ZonedDateTime.offset, чтобы сопоставить экземпляр Temporal.Instant и часовой пояс со смещением UTC в точное время в этом часовом поясе в виде строки.
UTC смещение для зонального события в секундах¶
Аналогичным образом используйте Temporal.Instant.toZonedDateTimeISO() и Temporal.ZonedDateTime.offsetNanoseconds, чтобы сделать то же самое для смещения в секундах. (Не забудьте разделить на 109, чтобы преобразовать наносекунды в секунды.)
Смещение между двумя часовыми поясами в точное время¶
Также, используя Temporal.Instant.toZonedDateTimeISO() и Temporal.ZonedDateTime.offsetNanoseconds, мы можем сопоставить экземпляр Temporal.Instant и два часовых пояса со знаком разницы смещений UTC между этими часовыми поясами в это точное время, выраженное в секундах.
Работа с датами и временем в фиксированном месте¶
Вот пример использования Temporal на графике, показывающий фиктивную активность резервуара-хранилища в фиксированном месте (Стокгольм, Швеция). График всегда начинается в полночь в том месте, где находится резервуар, но метки графика находятся в часовом поясе зрителя.
Забронируйте встречу в разных часовых поясах¶
В Интернете существует несколько инструментов для поиска времени встречи, подходящего для часовых поясов всех участников, например World Time Buddy, World Clock Meeting Planner, которые встроены в различные календарные программы.
Арифметика¶
Сколько дней до будущей даты¶
Пример HTML-формы, вдохновленный Days Calculator на timeanddate.com:
Продолжительность между настоящим и прошлым/будущим зональным событием ограничена единицей¶
Возьмите разницу между двумя экземплярами Temporal.Instant как экземпляр Temporal.Duration (положительный или отрицательный), представляющий продолжительность между двумя моментами без использования единиц измерения, более грубых, чем указано (например, для представления значимого обратного отсчета с использованием месяцев или дней без использования).
Следующий переход смещения в часовом поясе¶
Сопоставьте экземпляр Temporal.ZonedDateTime с другим экземпляром Temporal.ZonedDateTime, представляющим ближайшее следующее точное время, в которое происходит сдвиг смещения в часовом поясе (например, для установки напоминаний).
Сравнение точного времени с часами работы¶
В этом примере берется список времени открытия и закрытия настенных часов для компании, а точное время сопоставляется с индикатором состояния, чувствительным ко времени («скоро открытие», «открытие», «скоро закрытие», «закрыто»).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | |
Прибытие/вылет/продолжительность рейса¶
Сопоставьте время отправления и прибытия локализованной поездки с продолжительностью поездки в единицах, не превышающих часов. (По умолчанию различия между экземплярами ZonedDateTime представляют собой точные различия в единицах времени.)
Учитывая время отправления с часовым поясом и продолжительность полета, получите время прибытия в часовом поясе пункта назначения, используя математические вычисления с учетом часового пояса.
Отодвинуть дату запуска¶
Добавьте количество дней, которое потребовалось для получения одобрения, и перейдите к началу следующего месяца.
Запланируйте напоминание перед достижением рекордной продолжительности¶
Рассматривая рекорд (например, личное лучшее время в спорте), вы можете захотеть получить предупреждение непосредственно перед тем, как рекорд вот-вот будет побит. В этом примере используется запись как Temporal.Duration, точное время начала текущей попытки как Temporal.Instant и еще один Temporal.Duration, указывающий, сколько времени осталось до потенциально рекордного точного времени, когда вы хотели бы получить предупреждение. Он возвращает точное время, когда может быть отправлено уведомление, например: «Продолжайте! Еще 5 минут, и это будет ваш личный рекорд!»
Это можно использовать для отслеживания тренировок, гонок (включая гонки на длинные дистанции и, возможно, с пересечением часовых поясов, такие как Bullrun Rally, Iditarod, Self-Transcendence 3100 и Clipper Round The World) или даже для открытых аналогов, таких как ежедневные «полосы» событий.
N-й день недели месяца¶
Пример получения Temporal.PlainDate, представляющего первый вторник данного Temporal.PlainYearMonth, который можно адаптировать к другим дням недели.
Учитывая экземпляр Temporal.PlainYearMonth и порядковый номер календарного дня недели ISO 8601 в диапазоне от 1 (понедельник) до 7 (воскресенье), верните хронологически упорядоченный массив экземпляров Temporal.PlainDate, соответствующих каждому дню месяца, который является указанным днем недели (которых всегда будет четыре или пять).
Учитывая экземпляр Temporal.PlainDate, верните количество предыдущих дней в этом месяце, которые совпадают с его днем недели.
Управление днем месяца¶
Вот несколько примеров использования существующей даты и настройки дня месяца.
Тот же день в другом месяце¶
Аналогично, вот несколько примеров использования существующей даты и корректировки месяца, но с сохранением дня и года.
В зависимости от желаемого поведения вам нужно будет выбрать правильный параметр overflow, но значение по умолчанию 'constrain' должно быть правильным в большинстве случаев.
Следующее событие недели¶
Из экземпляра Temporal.ZonedDateTime получите Temporal.ZonedDateTime, представляющий следующее возникновение еженедельного события, запланированного на определенный день недели и время в определенном часовом поясе. (Например, «еженедельно по четвергам в 08:45 по калифорнийскому времени»).
День недели ежегодного события¶
В некоторых странах, когда государственный праздник приходится на вторник или четверг, в понедельник или пятницу отмечается дополнительный «мостовой» государственный праздник, чтобы дать работникам длинные выходные. В следующем примере это вычисляется.
Расширенные варианты использования¶
Ожидается, что они не будут частью обычного использования Temporal, но демонстрируют некоторые необычные вещи, которые можно сделать с помощью Temporal. Поскольку они обычно больше, чем рецепты кулинарной книги, они находятся на отдельных страницах.
Дополнительные годы¶
Расширьте Temporal для поддержки лет произвольного размера (например, +635427810-02-02) для астрономических целей.
Пример расширенного года
Это пример подхода к расширению Temporal для поддержки лет произвольного размера (например, +635427810-02-02) для астрономических целей.
Код ниже — это всего лишь пример, показывающий, как это можно сделать. Чтобы сделать это полностью, потребуется добавить поддержку Temporal.Instant и Temporal.ZonedDateTime и переопределить больше методов.
Например, в этом примере арифметика не будет работать правильно.
ПРИМЕЧАНИЕ: Это очень специализированное использование Temporal, и вам обычно не придется это делать. Специальная сторонняя библиотека может быть лучшим решением этой проблемы.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | |
Регулируемый календарь Хиджры¶
Расширьте Temporal для поддержки корректирующих дней для календарей Хиджры, которые иногда требуются, когда начало месяца основано на астрономических наблюдениях.
Изменения в дни Хиджры
В этом примере демонстрируется подход к настройке отображения дат хиджры в Temporal путем реализации класса AdjustableHijriTemporal. Этот класс позволяет сдвигать даты хиджры вперед или назад на указанное количество дней.
Код ниже демонстрирует, как:
- Синхронизируйте отображаемые даты хиджры с местными календарями хиджры.
- Содействовать использованию альтернативных календарных эпох Хиджры.
Ключевые особенности этой реализации:
- Настраивает отображение дат Хиджры без изменения базовой календарной системы.
- Применяет простую дневную смену без изменения длины месяца или других календарных правил.
- Обеспечивает визуальное выравнивание для различных вариантов календаря Хиджры.
ПРИМЕЧАНИЕ. Этот пример предназначен для базовой корректировки даты Хиджры и визуального выравнивания. Он не реализует комплексную настройку календаря или подробные варианты календаря Хиджры. Для более сложных корректировок или вариантов календаря Хиджры потребуется более сложная реализация.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | |
Непальский календарь¶
Реализация непальского календаря в пользовательском пространстве. Этот календарь в настоящее время не встроен в среду JS. Это служит примером того, как создать поддержку календарей, которые не получили широкого распространения в браузерах.
Поддержка непальского календаря в настоящее время не встроена в среды JS. В этом примере показано, как реализовать собственный календарь с помощью Temporal, создав для этого календаря класс даты, который работает как PlainDate и может использоваться как пакет свойств PlainDate.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 | |
Источник: https://tc39.es/proposal-temporal/docs/cookbook.html