Какой часовой пояс лучше использовать когда компьютеры обмениваются данными через api

Обновлено: 06.07.2024

Когда включена поддержка часовых поясов, Django хранит информацию о дате и времени в формате UTC в базе данных, использует внутренние объекты datetime с учетом часовых поясов и переводит их в часовой пояс конечного пользователя в шаблонах и формах.

Это удобно, если ваши пользователи живут в нескольких часовых поясах и вы хотите отображать информацию о дате и времени в соответствии с настенными часами каждого пользователя.

Даже если ваш веб-сайт доступен только в одном часовом поясе, все равно рекомендуется хранить данные в формате UTC в вашей базе данных. Основная причина - переход на летнее время (DST). Во многих странах действует система летнего времени, при которой часы переводятся вперед весной и назад осенью. Если вы работаете по местному времени, вы, вероятно, будете сталкиваться с ошибками дважды в год, когда происходят переходы. (В документации pytz эти вопросы обсуждаются более подробно.) Это, вероятно, не имеет значения для вашего блога, но это проблема, если вы выставляете завышенные или заниженные счета своим клиентам на один час, два раза в год, каждый год. Решение этой проблемы - использовать UTC в коде и использовать местное время только при взаимодействии с конечными пользователями.

По умолчанию поддержка часовых поясов отключена. Чтобы включить его, установите в вашем файле настроек. По умолчанию для поддержки часовых поясов используется pytz , который устанавливается при установке Django; Django также поддерживает использование других реализаций часовых поясов, например, путем передачи объектов непосредственно функциям в . USE_TZ = True zoneinfo tzinfo django.utils.timezone

pytz Добавлена поддержка реализаций без часового пояса.

settings.py Файл по умолчанию, созданный для удобства, включает . django-admin startproject USE_TZ = True

Существует также независимый, но связанный USE_L10N параметр, который определяет, должен ли Django активировать локализацию формата. Подробнее см. Локализация формата .

Если вы боретесь с конкретной проблемой, начните с часто задаваемых вопросов о часовых поясах .

Концепции ¶

Наивные и осведомленные объекты datetime ¶

У datetime.datetime объектов Python есть tzinfo атрибут, который можно использовать для хранения информации о часовом поясе, представленной как экземпляр подкласса datetime.tzinfo . Когда этот атрибут установлен и описывает смещение, объект datetime осведомлен . В противном случае это наивно .

Вы можете использовать is_aware() и, is_naive() чтобы определить, насколько известно время даты или нет.

Когда поддержка часового пояса отключена, Django использует наивные объекты datetime по местному времени. Этого достаточно для многих случаев использования. В этом режиме, чтобы получить текущее время, вы должны написать:

Когда поддержка часового пояса включена ( USE_TZ=True ), Django использует объекты datetime, учитывающие часовой пояс. Если ваш код создает объекты datetime, они тоже должны знать об этом. В этом режиме приведенный выше пример выглядит следующим образом:

Работа с известными объектами datetime не всегда интуитивно понятна. Например, tzinfo аргумент стандартного конструктора datetime не работает надежно для часовых поясов с DST. Использование UTC в целом безопасно; если вы используете другие часовые пояса, вам следует внимательно изучить документацию pytz .

datetime.time Объекты Python также имеют tzinfo атрибут, а PostgreSQL имеет соответствующий тип. Однако, как сказано в документации PostgreSQL, этот тип «демонстрирует свойства, которые приводят к сомнительной полезности». time with time zone

Django поддерживает только наивные объекты времени и вызовет исключение, если вы попытаетесь сохранить известный объект времени, поскольку часовой пояс для времени без связанной даты не имеет смысла.

Интерпретация наивных объектов datetime ¶

Когда USE_TZ есть True , Django по-прежнему принимает наивные объекты datetime, чтобы сохранить обратную совместимость. Когда уровень базы данных получает его, он пытается уведомить его, интерпретируя его в часовом поясе по умолчанию, и выдает предупреждение.

К сожалению, во время перехода на летнее время некоторые даты не существуют или являются неоднозначными. В таких ситуациях pytz вызывает исключение. Вот почему вы всегда должны создавать осведомленные объекты datetime, когда включена поддержка часовых поясов.

На практике это редко бывает проблемой. Django предоставляет вам известные объекты datetime в моделях и формах, и чаще всего новые объекты datetime создаются из существующих с помощью timedelta арифметики. Единственное datetime, которое часто создается в коде приложения, - это текущее время, и оно timezone.now() автоматически работает правильно.

Часовой пояс по умолчанию и текущий часовой пояс ¶

Часовой пояс по умолчанию часовой пояс определяется TIME_ZONE настройкой.

Текущий часовой пояс часовой пояс , который используется для рендеринга.

Вы должны установить текущий часовой пояс на фактический часовой пояс конечного пользователя с помощью activate() . В противном случае используется часовой пояс по умолчанию.

Как объясняется в документации TIME_ZONE , Django устанавливает переменные среды так, чтобы его процесс выполнялся в часовом поясе по умолчанию. Это происходит независимо от значения USE_TZ и текущего часового пояса.

Когда USE_TZ есть True , это полезно для сохранения обратной совместимости с приложениями, которые все еще полагаются на местное время. Однако, как объяснялось выше , это не совсем надежно, и вы всегда должны работать с известными датами в формате UTC в своем собственном коде. Например, используйте fromtimestamp() и установите для tz параметра значение utc .

Выбор текущего часового пояса ¶

Большинство веб-сайтов, которые заботятся о часовых поясах, спрашивают пользователей, в каком часовом поясе они живут, и сохраняют эту информацию в профиле пользователя. Для анонимных пользователей они используют часовой пояс своей основной аудитории или UTC. pytz предоставляет помощники , такие как список часовых поясов для каждой страны, которые вы можете использовать для предварительного выбора наиболее вероятных вариантов.

Вот пример, в котором хранится текущий часовой пояс сеанса. (Для простоты он полностью пропускает обработку ошибок.)

Как вы уже наверняка знаете, в 11-й версии продукта вышла поддержка часовых поясов. Давайте рассмотрим подробнее, в чем заключается поддержка, и как можно использовать часовые пояса. Я расскажу как об использовании, так и о внутреннем устройстве (для понимания разработчиками).[spoiler]

Сначала о базовых принципах.

1) Мы полагаем, что PHP и база данных работают в одном часовом поясе. Чаще всего часовой пояс определяется настройками операционной системы, реже используются специальные настройки PHP и БД. На самом деле, PHP и БД должны работать в одном поясе.

2) Мы не ведем собственную базу часовых поясов. Мы полностью полагаемся на PHP в вопросах часовых поясов, перехода на летнее/зимнее время и прочее. Поддержка DateTime появилась в php 5.2.0 - на более старых версиях часовые пояса в продукте работать не будут. PHP использует ту же базу часовых поясов, что и многие сборки Unix. В этой базе идентификаторы зон имеют вид "Europe/Kaliningrad".

3) Все даты записываются и хранятся в БД в локальном времени сервера . Это наше наследие, которое нельзя легко изменить - никаким обновлением невозможно изменить значения во всех полях типа дата всех таблиц. Т.е. если сервер работает в московском часовом поясе, то "14:00:00", записанное в БД - это именно 14:00 по Москве.

4) При выборке из БД значения полей типа дата (в полном формате) переводятся в указанный в настройках часовой пояс (о настройках ниже). Если дата в коротком формате (без часов-минут-секунд), то арифметика часовых поясов не производится. Проще говоря, посетители видят время в своем локальном времени.

5) При записи в БД значения полей типа дата переводятся из указанного в настройках часового пояса в локальное время сервера (только для полного формата). Проще говоря, посетители во всех формах должны вводить время в своем локальном времени.

Теперь о настройках.

В настройках ядра появилась секция "Часовые пояса":


1) "Локальное время сервера" показывает, в каком поясе фактически работает сервер. Для корректной работы системы часовых поясов должна быть правильная комбинация времени и смещения от UTC (18:26:10 +0300). Из продукта время и пояс не настраиваются, они просто должны быть правильными . Если что-то не так, нужно настраивать ОС и/или PHP и БД.

:)

2) Флажок "Разрешить использование часовых поясов" включает или полностью отключает использование часовых поясов - на усмотрение администратора. При отключенной галочке запросы к БД будут немного короче.

4) "По умолчанию автоматически определять часовой пояс по браузеру". Javascript браузера знает, в каком часовом поясе работает пользователь на своем компьютере. Мы можем воспользоваться этой информацией, чтобы не задавать пользователю лишних вопросов, а определить его часовой пояс автоматически. Опция особенно полезна в корпоративном портале, где часовые пояса имеют большое значение.

В профиле пользователя появилась настройка "Часовые пояса":


Для каждого пользователя можно указать настройки "по умолчанию", "автоматически", "выбрать из списка". "По умолчанию" - настройки автоопределения берутся из настроек главного модуля. "Выбрать из списка" - можно выбрать конкретную зону. Настройки конкретного профиля имеют приоритет над настройками ядра.


Тогда в редактировании профиля будет доступен выбор часового пояса:


Аналогичные настройки есть в других перечисленных компонентах.

Как это выглядит.


При сохранении дата переводится в локальное время сервера:


Как видно, значение в БД на один час меньше - это как раз разница между Калининградом и Москвой.

Как это работает. (Информация для разработчиков)

Мы решили, что самым правильным будет применить арифметику часовых поясов на самом низком уровне - на уровне выборки из БД и записи в БД. В противном случае пришлось бы форматировать дату непосредственно при выводе. Например, в компоненте новостей написано:

Понятно, что таких мест в продукте очень много, каждое не исправишь. Поэтому GetList инфоблока возвращает уже модифицированную дату. На самом деле, конвертация происходит на еще более низком уровне, в функциях CDatabase:: DateToCharFunction() и CDatabase::CharToDateFunction(). Поэтому если API при выборке и записи использует эти функции, то все должно заработать "само".

Часто бывает, что вычисление даты делается кодом PHP, например:

В этом случае нам придется учесть часовой пояс самостоятельно:

В этом примере мы переводим текущее время сервера в часовой пояс пользователя. В таких операциях нужно запомнить одну простую формулу, которая поможет манипулировать со временем:

А что делать, если нам совершенно точно не потребуется конвертировать время при выборке из БД и при сохранении в БД? Нам поможет такой прием:

При разработке кода теперь необходимо учитывать следующие особенности:

1) Все агенты исполняются в локальном времени сервера.

3) В CPHPCache и CPageCache часовой пояс не учитывается . Если кешируемые данные зависят от пояса, то в ID кеша необходимо подмешивать результат выполнения CTimeZone::GetOffset();

4) В полях CEvent::Send() желательно передавать локальное время сервера - в общем случае мы не знаем, для кого предназначено письмо.

:)

Чтобы учесть все эти нюансы, нам пришлось буквально "проползти с фонариком" по всем модулям.

Надеюсь, что нововведения понравятся нашим пользователям и разработчикам!

Допустим, вы хотите написать приложение Windows Store, в котором выводятся часы для разных городов мира. Вероятно, версия для Windows 8 будет выглядеть примерно так:

Пример приложения, отслеживающего время в разных часовых поясах

Такая программа позволяет добавлять новые часы, задавать их местонахождение и часовой пояс, выбирать цвета и сохранять введенную информацию в конфигурации приложения. Для вычисления времени в различных часовых поясах и особенно для решения проблемы летнего времени, было бы очень удобно воспользоваться встроенной поддержкой Windows.

Разработчик с радостью обнаруживает класс TimeZoneInfo в пространстве имен System и замечает, что статический метод GetSystemTimeZones возвращает коллекцию объектов TimeZoneInfo для всех часовых поясов в мире. Однако при попытке использовать этот метод выясняется, что он недоступен для приложений Windows 8. В приложениях Windows 8 можно получить либо объект TimeZoneInfo для текущего часового пояса, либо тривиальный объект TimeZoneInfo для времени UTC (Universal Coordinated Time).

Однако приложениям Windows 8 доступны функции Win32, способные предоставить большую часть нужной информации. Функция Win32 EnumDynamicTimeZoneInformation перебирает все часовые пояса в мире в формате структур DYNAMIC_TIME_ZONE_INFORMATION:

Это расширенная версия структуры TIME_ZONE_INFORMATION:

Тип WCHAR представляет 16-разрядный символ Юникода, а массивы таких символов обычно представляют строки, завершаемые нуль-символом. Поле StandardName содержит строку вида «Eastern Standard Time», а поле DaylightName - строку вида «Eastern Daylight Time». Поле TimeZoneKeyName в структуре DYNAMIC_TIME_ZONE_INFORMATION содержит ключ реестра Windows. В Windows 8 эти записи реестра находятся в ветке HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Time Zones, а ключ реестра совпадает с StandardName.

Поле Bias содержит количество минут, вычитаемое из времени UTC для получения местного времени. Для восточного побережья США смещение составляет 300 минут. Поле StandardBias всегда равно нулю, тогда как DaylightBias содержит количество минут, вычитаемое из стандартного времени для перехода к летнему времени (обычно -60).

Поля DaylightDate и StandardDate определяют, когда должен происходить переход на летнее время и обратно; информация хранится в формате SYSTEMTIME:

Структура SYSTEMTIME в основном используется функциями Win32 GetLocalTime и GetSystemTime для получения текущего местного времени и времени UTC соответственно. Значения SYSTEMTIME в структуре TIME_ZONE_INFORMATlON специально закодированы для обозначения даты перехода: поля wHour и wMinute обозначают время перехода, поле wMonth обозначает месяц перехода (например, 3 - март), поле wDayOfWeek обозначает день недели перехода (например, 1 - воскресенье), а поле wDay - конкретное вхождение заданного дня недели в заданном месяце (например, 2 - второе воскресенье месяца, или 5 - последнее воскресенье).

Windows различает , которые переключаются между стандартным и летним временем в дни, обозначенные подобным образом, и теми, которые динамически переключают время каждый год. Говорят, что последние используют «динамическое летнее время», но информация по годам напрямую недоступна. Функция с именем GetTimeZoneInformationForYear получает год и указатель на структуру DYNAMIC_TIME_ZONE_INFORMATION, а возвращает указатель на структуру TIME_ZONE_INFORMATION с информацией для указанного года. Функция SystemTimeToTzSpecificLocalTime получает указатель на структуру TIME_ZONE_INFORMATION и указатель на структуру SYSTEMTIME (вероятно, полученный от функции GetSystemTime) и возвращает структуру SYSTEMTIME для местного времени в этом часовом поясе. Таким образом, программам не приходится самостоятельно выполнять преобразование времени.

Такая программа, как ClockRack, должна поддерживать возможность выбора часового пояса для конкретного локального контекста. В идеале она должна напоминать средства выбора часового пояса в Windows 8. Вызовите чудо-кнопки Windows 8, выберите кнопку "Параметры" и нажмите нижнюю кнопку "Изменение параметров компьютера". Кнопка запускает программу со списком настроек. Выберите категорию Общие; в верхней части приложения располагается поле со списком часовых поясов. Каждый часовой пояс определяется смещением от UTC; иногда приводится название часового пояса и во многих случаях - примеры городов.

Например, для «романского часового пояса» в списке отображается строка:

В разделе реестра Windows, содержащем список часовых поясов, метки хранятся под именем «Display», но эта информация не предоставляется функциями Win32. Ее придется извлекать из реестра, а для приложений Windows 8 недоступны функции Win32 для чтения данных из реестра.

Объект Dictionary является частью класса TimeZoneManager из проекта ClockRack. В этом классе я объединил всю логику P/Invoke. Код за пределами TimeZoneManager не обращается ни к каким функциям или структурам Win32.

Класс TimeZoneManager спроектирован так, чтобы он создавался в единственном экземпляре, используемом на протяжении всей работы приложения. Класс предоставляет данные часовых поясов остальному коду программы в виде коллекции значений:

Свойство Bias используется только для сортировки. Поле TimeZoneKey содержит ту же строку, что и поле TimeZoneKeyName в структуре DYNAMIC_TIME_Z0NE_INFORMATION, а свойство Display берется из словаря displayStrings.

Часть класса TimeZoneManager в основном файле TimeZoneManager.cs начинается с определения структур Win32 и объявления трех функций Win32, необходимых для работы класса:

Конструктор класса TimeZoneManager многократно вызывает EnumDynamicTimeZoneInformation до тех пор, пока не будет получено ненулевое значение - признак конца списка. Количество значений в списке зависит от версии Windows (101 в моей версии). Каждое значение преобразуется к типу TimeZoneDisplayInfo и добавляется в открытую коллекцию с именем DisplayInformation:

Как вы вскоре увидите, это свойство DisplayInformation используется как источник данных (ItemsSource) для ComboBox.

Последний метод TimeZoneManager преобразует время UTC в местное время по ключу часового пояса. Эта же строка используется в поле TimeZoneKeyName структуры DYNAMIC_TIME_ZONE_INFORMATION и в свойстве TimeZoneKey структуры TimeZoneDisplayInfo:

Не могу сказать, что я полностью доволен этим методом. Дело в том, что программа ClockRack отображает несколько часов и использует метод CompositionTarget.Rendering для получения обновленного значения DateTime.UtcNow, которое используется для всех часов. (Я решил, что такое решение будет эффективнее, чем вызывать из GetLocalTime функцию Win32 GetSystemTime с получением значения SYSTEMTIME для времени UTC по каждым часам.) Мне не нравится повторный вызов метода GetTimeZoneInformationForYear. В действительности его достаточно вызвать только один раз для каждого часового пояса, а в дальнейшем повторно использовать TIME_Z0NE_INFORMATION в последующих вызовах. Но если программа работает при переходе с 31 декабря к 1 января, потребуется повторный вызов. Я решил не загромождать класс подобной логикой.

Год, передаваемый GetTimeZoneInformationForYear, должен быть годом местного времени, а не годом UTC; это еще один момент, который обрабатывается не совсем корректно. Эти два года теоретически могут различаться только в 24-часовом периоде, включающем Новый год по UTC, и в такой программе это не должно играть роли, потому что переход между стандартным и летним временем происходит намного позднее.

Впрочем, если какой-то локальный контекст южного полушария вдруг решит, что переход на летнее время должен происходить в одном году, но не в следующем (или наоборот), то время при переходе между этими двумя годами будет вычисляться неверно. Но давайте двигаться дальше.

Большая часть кода вывода часов (класс, производный от UserControl, с именем TimeZoneClock) была позаимствована в программе AnalogClock из статьи "Создание стрелочных часов в WinRT", но я переработал его для использования модели представления через привязки данных. Также все координаты и размеры были уменьшены в 10 раз. Из-за того, что в очень малом пространстве (например, в режиме Snap View) может отображаться большое количество часов, программа должна быть способна изменять размеры часов в широком спектре.

Другое отличие заключается в том, что циферблат часов теперь располагается между двумя элементами TextBlock. В одном выводится географическое место, а в другом текущая дата и время. Без нижнего текста пользователь вряд ли сразу поймет, к какой половине суток относятся показания часов.

Каждый из двух элементов TextBlock имеет фиксированную высоту из настроек RowDefinition панели Grid, но каждый из них также находится в элементе Viewbox; слишком длинный текст автоматически сжимается по размерам. Каждые часы находятся в панели Grid из одной ячейки, свойству Background которой задается привязка данных. Панель занимает все доступное для нее место. В панели Grid находится элемент Viewbox, изменяющий размер своего содержимого - еще одной панели Grid с фиксированным размером 30 x 20, фактический размер которой определяется элементом Viewbox в зависимости от доступного места:

Оба элемента TextBlock и все элементы RotateTransform имеют привязки к свойствам модели представления. В начале файла TimeZoneClock.xaml видно, что модель представления также включает свойства типа Color с именами Foreground и Background. Файл фонового кода не содержит ничего, кроме вызова InitializeComponent.

Чтобы программа была относительно простой, я решил ограничить фоновый и основной цвета каждых часов 140 цветами, которым присвоены имена и которые, следовательно, соответствуют членам статического класса Colors. Как и следовало ожидать, модель представления класса TimeZoneClock определяет свойства Foreground и Background типа Color, но также она определяет свойства ForegroundName и BackgroundName; при изменении одного из этих свойство другое также изменяется при помощи логики отражения:

Эта модель представления также включает свойство DateTime, при каждом изменении которого также изменяются свойства HourAngle, MinuteAngle и SecondAngle, управляющие тремя объектами RotateTransform в TimeZoneClock.xaml.

Для вывода нескольких часов мне была нужна панель, которая бы позволяла вывести все часы в границах страницы, но с выделением оптимального места для каждого потомка. Панель UniformGrid, разработанная в статье "Пользовательские панели в WinRT", была достаточно близка к тому, что требовалось, но не совсем. Предположим, выводятся семь циферблатов, и UniformGrid определяет, что они должны выводиться в две строки по пять в каждой. UniformGrid поместит пять циферблатов часов в первую строку и два - во вторую. Приложение будет лучше смотреться, если панель распределит часы между двумя строками более равномерно - четыре в одной и три в другой.

Программа ClockRack содержит ссылку на библиотеку, в которой мы разработали элемент UniformGrid, но определяет производную от UniformGrid панель с именем DistributedUniformGrid. Логика этого нового класса выделяет приблизительно равное количество ячеек во всех строках. В пределах одной строки объекты равномерно распределяются по ширине:

Файл MainPage.xaml не содержит практически ничего, кроме определения DistributedUniformGrid для хранения элементов управления с часами:

Конструктор класса MainPage отвечает за заполнение панели DistributedUniformGrid по конфигурации приложения. Программа использует класс ApplicationData из пространства имен Windows.Storage для хранения четырех текстовых полей для каждых часов: название места (выбирается пользователем), ключ часового пояса, названия основного и фонового цветов. Для первых часов данные сохраняются с ключами «0Location», «0TimeZoneKey», «0Foreground» и «0Background»; у вторых часов ключи начинаются с цифры 1 и т.д. При выборке каждого набора параметров создаются и инициализируются объекты TimeZoneClock и TimeZoneClockViewModel:

Как обычно, настройки сохраняются во время обработки события Suspending. Конструктор завершается запуском события CompositionTarget.Rendering. Оно отвечает за использование экземпляра TimeZoneManager для получения местного времени на основании текущего времени UTC с ключом часового пояса для каждых часов:

Правое касание открывает контекстное меню с тремя командами добавления (Add), изменения (Edit) и удаления (Delete) часов. Команды Edit и Delete относятся к конкретным часам, поэтому переопределение OnRightTapped начинается с определения часов, к которым прикоснулся пользователь. Этот объект передается обработчикам трех команд. Даже для команды Add эта информация необходима, потому что логика программы вставляет новые часы после выбранных:

Команда Delete присутствует в меню только в том случае, если в приложении открыто более одних часов:

Для команды меню Add необходимо создать и вставить в коллекцию новый объект TimeZoneClock (с соответствующим объектом TimeZoneClockViewModel). Новые часы всегда вставляются после часов, к которым прикоснулся пользователь:

Конечно, команда Edit требует более сложной обработки. Скорее всего, вы вызовете ее сразу же после добавления новых часов (если только вас не устраивают часы с синим циферблатом на желтом фоне). Команда Edit создает экземпляр SettingsDialog (вскоре этот класс будет рассмотрен более подробно) как потомка объекта Popup. Так как SettingsDialog необходим доступ к экземпляру TimeZoneManager, объект TimeZoneManager передается в конструкторе SettingsDialog. Основная часть кода отвечает за позиционирование Popup, чтобы окно было визуально связано с выбранными часами и не выходило за край экрана:

На иллюстрации показано, как выглядит окно SettingsDialog. В первом поле EditBox просто вводится текстовое описание; три других поля используют поле со списком ComboBox для отображения текущего выделенного элемента. При получении фокуса ввода поле ComboBox открывает список вариантов:

Добавление меню для смены часовых поясов

Свойству DataContext объекта SettingsDialog задается значение свойства DataContext изменяемого объекта TimeZoneClock. Оно представляет собой объект TimeZoneClockViewModel, а в файле XAML содержатся привязки к свойствам Location.TimeZoneKey, ForegroundName и BackgroundName этого класса. Обратите внимание: у поля TextBox, привязанного к свойству Location, назначен обработчик события TextChanged; это позволяет файлу фонового кода «вручную» обновлять свойство Location объекта TimeZoneClockViewModel, что приводит к обновлению содержимого верхней части Popup.

Файл фонового кода (приведенный далее) поставляет коллекции для трех элементов управления ComboBox. Список часовых поясов заполняется из свойства DisplayInformation объекта TimeZoneManager, а соответствующая разметка первого поля ComboBox ссылается на свойства TimeZoneKey и Display.

Ч решил использовать класс NamedColor, который мы создали в статье "Шаблон данных DataTemplate в WinRT" для получения коллекции объектов NamedColor. Как видно из файла XAML, шаблон ItemTemplate, используемый для этих двух элементов управления, ссылается на свойства Color и Name класса NamedColor, а в каждом элементе ComboBox свойству SelectedValuePath присваивается свойство Name.

В этой статье мы рассмотрим новые API Java 8 для определения даты и времени, а также насколько проще создавать и манипулировать датами и временем.

1. Обзор

Java 8 представила новые API для Даты и времени для устранения недостатков более старых java.util.Дата и java.util.Календарь .

В рамках этой статьи давайте начнем с проблем в существующих Date и Calendar API и обсудим, как новые API Java 8 Date и Time решают их.

Мы также рассмотрим некоторые основные классы нового проекта Java 8, которые являются частью пакета java.time , например LocalDate , LocalDateTime, LocalDateTime, ZonedDateTime, Period, Duration и их поддерживаемые API.

Дальнейшее чтение:

Работа с параметрами даты весной

Проверьте, является ли строка Допустимой датой в Java

2. Проблемы с существующими API-интерфейсами даты и времени

  • Потокобезопасность – Классы Дата и Календарь не являются потокобезопасными, оставляя разработчикам решать головную боль, связанную с трудными проблемами отладки параллелизма и написанием дополнительного кода для обработки потокобезопасности. Напротив, новые API Date и Time , представленные в Java 8, являются неизменяемыми и потокобезопасными, что избавляет разработчиков от головной боли параллелизма.
  • Дизайн API и простота понимания – API Дата и Календарь плохо разработаны с неадекватными методами для выполнения повседневных операций. Новый API Date/Time является изоцентрическим и следует согласованным моделям домена для даты, времени, продолжительности и периодов. Существует большое разнообразие полезных методов, которые поддерживают самые распространенные операции.
  • ZonedDateиTime – Разработчикам пришлось написать дополнительную логику для обработки логики часового пояса со старыми API, в то время как с новыми API обработка часового пояса может выполняться с помощью Local и ZonedDate /| Time API.

3. Использование LocalDate, LocalTime и LocalDateTime

Наиболее часто используемыми классами являются LocalDate , LocalTime и LocalDateTime . Как следует из их названий, они представляют локальную дату/время из контекста наблюдателя.

Эти классы в основном используются, когда часовой пояс не требуется явно указывать в контексте. В рамках этого раздела мы рассмотрим наиболее часто используемые API.

3.1. Работа С LocalDate

Локальная дата представляет дату в формате ISO (гггг-ММ-дд) без времени .

Его можно использовать для хранения дат, таких как дни рождения и дни выплаты жалованья.

Экземпляр текущей даты может быть создан из системных часов, как показано ниже:

Local Date предоставляет различные служебные методы для получения разнообразной информации. Давайте быстро взглянем на некоторые из этих методов API.

Следующий фрагмент кода получает текущую локальную дату и добавляет один день:

В этом примере получается текущая дата и вычитается один месяц. Обратите внимание, как он принимает перечисление в качестве единицы времени:

Мы можем проверить, происходит ли дата в високосный год. В этом примере мы проверяем, является ли текущая дата високосным годом:

Связь одной даты с другой может быть определена до или после другой даты:

Границы дат могут быть получены с заданной даты. В следующих двух примерах мы получаем LocalDateTime , представляющий начало дня (2016-06-12T00:00) данной даты, и LocalDate , представляющий начало месяца (2016-06-01) соответственно:

Теперь давайте посмотрим, как мы работаем с местным временем.

3.2. Работа С Местным Временем

Местное время представляет время без даты .

Экземпляр текущего Местного времени может быть создан из системных часов, как показано ниже:

В приведенном ниже примере кода , мы создаем Местное время , представляющее 06:30 утра, путем анализа строкового представления:

Доступны различные методы получения, которые можно использовать для получения определенных единиц времени, таких как час, минута и сек, как показано ниже:

Мы также можем проверить, является ли определенное время до или после другого определенного времени. Приведенный ниже пример кода сравнивает два Местное время , для которых результат будет истинным:

Максимальное, минимальное и полуденное время суток можно получить с помощью констант в классе LocalTime . Это очень полезно при выполнении запросов к базе данных для поиска записей в течение заданного промежутка времени. Например, приведенный ниже код представляет 23:59:59.99:

Теперь давайте погрузимся в LocalDateTime .

3.3. Работа С LocalDateTime

LocalDateTime используется для представления комбинации даты и времени .

Это наиболее часто используемый класс, когда нам нужна комбинация даты и времени. Класс предлагает множество API, и мы рассмотрим некоторые из наиболее часто используемых.

Экземпляр LocalDateTime может быть получен из системных часов, аналогичных LocalDate и LocalTime:

Методы геттера доступны для извлечения определенных единиц измерения, аналогичных классам даты и времени. Учитывая приведенный выше экземпляр LocalDateTime , приведенный ниже пример кода вернет месяц февраль:

4. Использование API ZonedDateTime

В этом фрагменте кода мы создаем Зону для Парижа:

Набор всех идентификаторов зон можно получить следующим образом:

LocalDateTime может быть преобразован в определенную зону:

Метод ZonedDateTime предоставляет метод parse для получения конкретной даты часового пояса:

Экземпляр OffsetDateTime можно создать, как показано ниже, с помощью Zone Offset . Здесь мы создаем LocalDateTime , представляющий 6:30 утра 20 февраля 2015 года:

Затем мы добавим два часа к этому времени, создав смещение зоны и установив для экземпляра LocalDateTime :

Теперь у нас есть LocalDateTime 2015-02-20 06:30 +02:00. Теперь давайте перейдем к тому, как изменить значения даты и времени с помощью классов Period и Duration .

5. Использование периода и продолжительности

Класс Period представляет количество времени в годах, месяцах и днях, а класс Duration представляет количество времени в секундах и наносекундах.

5.1. Работа С Периодом

Класс Period широко используется для изменения значений заданной даты или для получения разницы между двумя датами:

Датой можно управлять с помощью Периода , как показано в следующем фрагменте кода:

Класс Period имеет различные методы получения, такие как getyear, getmonth и getday для получения значений из объекта Period . Приведенный ниже пример кода возвращает int значение 5, поскольку мы пытаемся получить разницу в днях :

Период между двумя датами может быть получен в определенной единице, такой как дни, месяц или годы, с помощью ChronoUnit.between:

Этот пример кода возвращает пять дней. Давайте продолжим, взглянув на класс Duration .

5.2. Работа С Длительностью

Подобно Period, класс Duration используется для работы с Time. В следующем коде мы создаем Местное время 6:30 утра, а затем добавляем продолжительность 30 секунд, чтобы сделать Местное время 06:30:30 утра:

Длительность между двумя моментами может быть получена либо как Длительность , либо как определенная единица измерения. В первом фрагменте кода мы используем метод between() класса Duration , чтобы найти разницу во времени между final Time и initialTime и вернуть разницу в секундах:

Во втором примере мы используем метод between() класса ChronoUnit для выполнения той же операции:

Теперь мы рассмотрим, как преобразовать существующую Дату и Календарь в новую Дату Время.

6. Совместимость с датой и календарем

Java 8 добавила их в метод Instant () , который помогает преобразовать существующие Данные и Календарь экземпляр в новый API даты и времени, как показано в следующем фрагменте кода:

LocalDateTime может быть построен из секунд эпохи, как показано ниже. Результатом приведенного ниже кода будет LocalDateTime , представляющий 2016-06-13T11:34:50:

Теперь перейдем к Дате и времени форматированию.

7. Форматирование даты и времени

Java 8 предоставляет API для удобного форматирования Даты и времени :

Приведенный ниже код передает формат даты ISO для форматирования локальной даты. Результат будет 2015-01-25:

DateTimeFormatter предоставляет различные стандартные параметры форматирования. Пользовательские шаблоны также могут быть предоставлены для метода форматирования, как показано ниже, который вернет Локальную дату как 2015/01/25:

Мы можем передать стиль форматирования как SHORT , LONG или MEDIUM как часть опции форматирования. Приведенный ниже пример кода даст вывод, представляющий LocalDateTime в 25-Jan-2015, 06:30:00:

Давайте рассмотрим альтернативы, доступные для Java 8 Core Date |/Time |/API.

8. Backport и альтернативные варианты

8.1. Использование проектной информации

Для организаций, которые находятся на пути перехода на Java 8 с Java 7 или Java 6 и хотят использовать API даты и времени, project threeten предоставляет возможность обратного порта. Разработчики могут использовать классы, доступные в этом проекте, для достижения той же функциональности, что и в новом Java 8 Date и Time API, и как только они перейдут на Java 8, пакеты могут быть переключены. Артефакт для проекта можно найти в центральном репозитории maven :

8.2. Библиотека Joda-Time

Другой альтернативой для Java 8 Date и Time library является Joda-Time library. На самом деле Java 8 Date Time API был совместно разработан автором библиотеки Joda-Time (Стивен Коулборн) и Oracle. Эта библиотека предоставляет практически все возможности, которые поддерживаются в Java 8 Date Time project. Артефакт можно найти в maven central , включив в свой проект приведенную ниже зависимость pom:

9. Заключение

Java 8 предоставляет богатый набор API с согласованным дизайном API для облегчения разработки.

Примеры кода для приведенной выше статьи можно найти в репозитории Java 8 Date/Time git.

Читайте также: