Comments 29
При отправке данных на сервер клиент должен преобразовать все в UTC
В сочетании с "клиенту доверять нельзя" (а ему доверять нельзя) вы получаете потерю информации. Вы не знаете, какой часовой пояс был у клиента, и как он его преобразовал в UTC. Более того, если клиент передает время в UTC, не указывая, что это UTC (т.е., тогда, когда вы отказались от контроля за передачей смещения), вы не знаете, передал он UTC, или же свое локальное время.
Намного проще требовать от клиента время с явно указанным смещением — в этом случае вы не теряете никакой информации, но всегда гарантированно можете получить из этого UTC.
+4
Там далее в статье написано, что есть требования при которых такой подход не будет работать, и нужно хранить дополнительно смещение часового пояса. Противоречия нет, просто последовательные соображения )
0
При общении с неизвестным клиентом эти требования есть всегда — поэтому проще и не формулировать правила "клиент должен все преобразовывать в UTC", оно все равно никогда не будет выполняться.
(и, кстати, описанной мной ситуации там нет)
(и, кстати, описанной мной ситуации там нет)
0
Если под неизвестным клиентом подразумевается, что серверное АПИ будет непонятно кто по итогу использовать, то соглашусь. Такое ограничение для "произвольных" клиентов может оказаться неочевидным и неожиданным. Чуть позже обновлю статью.
0
Под неизвестным клиентом подразумевается любой, который вами полностью не контролируется. Даже если его код полностью вам подконтролен, но он установлен на неизвестном вам устройстве — это в данном контексте неизвестный вам клиент, потому что вы понятия не имеете, какой там часовой пояс.
+1
Если код полностью подконтролен и нет требований, по которым есть надобность хранить часовой пояс клиента — не вижу проблемы сделать на клиенте преобразование в UTC перед отправкой. Тут абсолютно равноценно — что клиент преобразует сам, что перешлет на сервер локальное время + смещение, для того, чтобы сервер сам уже выполнил это преобразование.
0
Тут абсолютно равноценно — что клиент преобразует сам, что перешлет на сервер локальное время + смещение, для того, чтобы сервер сам уже выполнил это преобразование.
Неравноценно. Вы потеряли информацию (например, что клиент думал, что у него часовой пояс +4, хотя по всем разумным признакам должен думать, что +3). Лучше всего это работает, если передавать одновременно часовой пояс (как название) и смещение, но это уже требует выхода за рамки стандартов, и потому редко когда реализуемо.
(и да, именно поэтому часовой пояс клиента надо хранить по умолчанию, а не только тогда, когда на это есть явные требования)
+1
Не совсем понял — эта информация о смещении для дальнейшего саппорта? Чтобы была возможность потом посмотреть, откуда всязалась ошибка в смещении? Если так — окей, понял.
0
Второй нюанс с получением текущего времени — это то, что клиенту доверять нельзяидеально, когда клиентское время вообще нигде не фигурирует в БД в качестве метки времени, а везде используется только время БД (для MS SQL — это getUTCDate()).
Но такое не всегда возможно сделать эффективно без лишнего roundtrip сервер-клиент-сервер. В таких случаях я в начале сессии клиент-сервер обычно вместе с каким-нибудь полезным ответом сервера (например, подтверждения авторизации) шлю клиенту UTC-время БД. Клиент в свою очередь, считает на своей стороне разницу между UTC-временем по своим часам и полученным от сервера, считает поправку, и использует эту поправку при отправке на сервер меток времени. Конечно, здесь появляется погрешность на время прохода пакета от клиента к серверу, но это все равно лучше, чем просто отправлять время на клиентской стороне. Такой подход мной использовался, например, в авторизационных токенах с временем жизни порядка минуты.
0
Сыграем в смешную игру. Давно хотел в нее сыграть, а тут отличный повод выдался.
Менеджер Иванов, находясь в Москве, 2 марта 2016 года выдал поручение инженеру Петрову, находящемуся в командировке в Хабаровске. Сроком исполнения поручения в системе документооборота Ивановым было установлено 11 марта 2016 года без указания времени.
Вопрос — какой срок исполнения поручения должен быть отображен Петрову? При решении задачи учитывать, что:
1. система документооборота, используемая Ивановым и Петровым поддерживает установку времени для поручений;
2. рабочий день Иванова по нормативным документам — с 9 утра до 6 вечера, рабочий день Петрова не нормирован, график — 2/1, 11 марта у него выходной.
Менеджер Иванов, находясь в Москве, 2 марта 2016 года выдал поручение инженеру Петрову, находящемуся в командировке в Хабаровске. Сроком исполнения поручения в системе документооборота Ивановым было установлено 11 марта 2016 года без указания времени.
Вопрос — какой срок исполнения поручения должен быть отображен Петрову? При решении задачи учитывать, что:
1. система документооборота, используемая Ивановым и Петровым поддерживает установку времени для поручений;
2. рабочий день Иванова по нормативным документам — с 9 утра до 6 вечера, рабочий день Петрова не нормирован, график — 2/1, 11 марта у него выходной.
0
Такие вопросы надо выяснять у заказчика и фиксировать в документации, а не играть в подобные игры.
+5
Это я к вопросу о передачи дат без преобразований и часовых поясов. Довольно шаткое положение, как по мне.
0
Приведенный вами пример не является случаем даты без времени. Если менеджер и вводит только дату, то показываться требуемое время исполнения должно как дата + время, а это уже само по себе противоречит исходному условию. Более того — назначение срока исполнения без конечного времени само по себе выглядит не очень удачным решением. Если я выполню задание в 23:30 1 фераля по московскому времени или 3:30 ночи 2 февраля — может ли так случиться, что для бизнеса по итогу разницы между этими временами нет, хотя дата исполнения стоит 1 февраля?
0
По московскому времени. В филиалах и командировках, как раз чтобы в такие игры не играть, ориентируются на время головной организации.
0
А почему нельзя хранить метки в epoch time?
+1
В смысле в количестве секунд, прошедших с 1 января 1970 года?
0
Да
0
Это уже давно устаревший подход, он как минимум не позволяет:
- хранить смещение часового пояса
- хранить даты ранее 1970 года
- иметь точность выше секундной
- сразу визуально понимать при отладке, что за время записано в поле
0
- если вам это очень надо для показа пользователю, храните отдельным полем. Преобразовать можно на стороне клиента
- отрицательные значения
- хранить ms epoch
- настройте отображение, если вам надо.
0
Зачем делать вручную все вышеперечисленное, если уже давно существуют типы, которые все это делают "под капотом"?
+2
Зачем писать свои велосипеды под таймзоны, когда
а) Работа с тамзонами — это боль и унижение. См, например, https://habrahabr.ru/company/mailru/blog/242645/ или https://habrahabr.ru/post/100741/ или http://stackoverflow.com/questions/178704/are-unix-timestamps-the-best-way-to-store-timestamps
б) что вы имеете под "вручную"? Конвертировать human-readable в timestamp и обратно? А ваша контвертация между конечным форматом и форматом для пользователя — это ли не велосипед с ручным приводом?
Кстати, укажите, где написано, что unix timestamp — устаревший подход, а ваш UTC — новый и хороший?
а) Работа с тамзонами — это боль и унижение. См, например, https://habrahabr.ru/company/mailru/blog/242645/ или https://habrahabr.ru/post/100741/ или http://stackoverflow.com/questions/178704/are-unix-timestamps-the-best-way-to-store-timestamps
б) что вы имеете под "вручную"? Конвертировать human-readable в timestamp и обратно? А ваша контвертация между конечным форматом и форматом для пользователя — это ли не велосипед с ручным приводом?
Кстати, укажите, где написано, что unix timestamp — устаревший подход, а ваш UTC — новый и хороший?
0
Извините, я не очень понял. Как хранение времени в формате unix timestamp избавляет от отображения этого времени по-разному для разных временных зон? И чем он отличается от того, что вы называете "ваш UTC"?
+3
Устаревший ваш подход только в том, что используется целочисленный тип, на замену которого уже давно есть типы "datetime", которые и отображают хорошо при чтении из базы и из дебага, а классы, которые есть в платформах еще и сами всю конверсию умеют делать с помощью утилитных методов.
Не "мой" метод — новый и хороший, это уже давно общая практика. Он по сути говорит о том же, что и вы — что нужно хранить в универсальном времени. Только вы говорите о том, что для этого нужно хранить какое-то там количество секунд, а я говорю о том, что для этого есть готовые типы, которые, более того, умеют еще и смещение таймзоны хранить, если надо. В чем проблема?
Не "мой" метод — новый и хороший, это уже давно общая практика. Он по сути говорит о том же, что и вы — что нужно хранить в универсальном времени. Только вы говорите о том, что для этого нужно хранить какое-то там количество секунд, а я говорю о том, что для этого есть готовые типы, которые, более того, умеют еще и смещение таймзоны хранить, если надо. В чем проблема?
0
Внутри эти готовые типы (по крайней мере "Дата и время" из вашей классификации) скорее всего и хранят unix timestamp, или какую-то подобную метку времени. Просто во многих случаях гораздо удобнее мыслить timestamp-ами, так как они представляют собой просто абсолютный момент времени во вселенной, независимо от временной зоны, тогда не приходится говорить ни о каких конвертациях, вы просто сравниваете числа, передаете числа из одной зоны в другую, применяете ту или иную таймзону для отображения timestamp-а.
+1
Sign up to leave a comment.
Правильная работа с датой и временем