Как стать автором
Обновить

Комментарии 39

Краткая формулировка задачи: каким-то образом current_date, current_time и current_timestamp должны выдавать дату-время в зависимости от настроек в аккаунте пользователя и при этом на самом сервере будет стоять московское время.

Зачем?


В БД должны храниться данные в известном часовом поясе, а при вводе/выводе они должны конвертироваться в тот часовой пояс, который нужен пользователю.


(есть случаи, когда конвертация не имеет смысла, но это тема для отдельного обсуждения)

Ну видимо не хотелось переписывать софт, который разрабатывали Масквичи. Мне интересно, они там дату разных пользователей сверяют? Это же ад должен быть.
Абсолютно верно. Решали похожую задачу по хранению даты с таймзоной в базе (вообще думал что она распространенная и не должна вызывать сложностей). Вкратце: делим всю дату на 2 части, первая часть timestamp типа long, вторая часовой пояс (буквенное выражение или отклонение в часах, в зависимости от задачи). На клиент возвращается объект из двух частей и строится нужная дата со смещением.
Ну это неверное зависит от величины проекта. Вот представьте, у Вас один сервер с файрбердом, на нем 1000 баз пользователей, и у каждого пользователя его данные должны отображаться в его часовом поясе (который он настроит). При этом у вас php кода самой системы 3 мегабайта и половина из них запросы в БД, куча процедур и триггеров в каждой из БД, причем структура у каждого пользователя может отличаться, т.к. есть встроенный язык программирования для пользователей (аля как в 1С только немного глубже и через веб). И вы хотите в каждом месте делать доп манипуляции с датой? Это будет жесть. Механизм должен быть универсальный и простой.
И вы хотите в каждом месте делать доп манипуляции с датой?

Не в каждом, а в одном слое (скорее всего, в UI). Просто то, что вы описываете, выглядит как плохо спроектированная система.

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

По вашему описанию — делается в БД. А БД — это не UI.


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

1. Возможно мы неправильно друг друга поняли. Я подумал что UI по вашему это Update и Insert.
Смысл в том что все даты в добавлениях и апдейтах делаются через эти view, а в селекте нам уже не нужна математика никакая… там уже дата записана с учетом часового пояса.

2. Если мы рассматриваем мою систему, то тут не совсем корректно сопоставление пользователи — часовые пояса. Есть компании, у которых есть сотрудники. Каждой компании выдается аккаунт и вот на этот аккаунт своя база данных и тут можно выставлять часовой пояс. Все сотрудники компании которые работают в ее аккаунте, работают с настройками компании в целом, т.е. с часовым поясом который настроен у компании.
Я подумал что UI по вашему это Update и Insert.

Нет, UI — это User Interface.


Смысл в том что все даты в добавлениях и апдейтах делаются через эти view, а в селекте нам уже не нужна математика никакая…

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


Все сотрудники компании которые работают в ее аккаунте, работают с настройками компании в целом, т.е. с часовым поясом который настроен у компании.

Как мило. У компании один склад в Калининграде, второй в Иркутске. И как время выдачи товара фиксировать будем?

lair, соглашусь, в чем то вы правы. Приятно, когда конструктивная критика.

У компании один склад в Калининграде, второй в Иркутске. И как время выдачи товара фиксировать будем?


Согласен, это проблема. Вы заставили меня задуматься над ней. Но она точно не решится индивидуальной постановкой UTC сотруднику. Она решится индивидуально постановкой UTC складу! Нельзя чтобы данные склада отображались в UTC сотрудника, ведь для каждого сотрудника дата-время приема или выдачи товара будет отображаться разное — чего быть не должно (оба позвонят начальнику и скажут: один что товар выдан в 10.00, другой что в 12.00 :) и кому верить?). При этом на UTC компании это тоже не должно быть завязано — оно может быть совершенно другим. Т.е. склад — это просто отдельный модуль с индивидуальным UTC у каждого склада.

Потом есть еще одна причина почему нельзя давать сотрудникам индивидуальный UTC, и он должен быть у компании. В частности у меня в системе можно помимо подразделений объединять сотрудников в группы, например в одном подразделении службы сети связи может быть группа сотрудников занимающийся телефонией, группа занимающиеся интернетом, телевидением и т.д. И можно например настроить чтобы задача с типом интернет пришла в это подразделение автоматически данной группе, и даже распределилась ее сотрудником по какому-то алгоритму. Может так быть, что в группу объединяются сотрудники из разных подразделений, но работающие над одной задачей каждый со своей стороны. Для этих групп могут ставиться задачи именно на группы со многими различными алгоритмами распределения, на группы могут формироваться графики работ (именно группы). Есть для групп SCRUM доски.
И вот представьте ситуацию, у одного сотрудника из группы стоит один UTC, а у другого другой! И какой при этом UTC отображать в графике группы в которую входят оба сотрудника? Это просто билеберда получится.
При этом я согласен с вами, что если один работает в Калининграде а второй в Иркутске… возможно надо просто глубже делать деление системы, вводит понятия офисов, где должно быть свое UTC и при этом запрещать программно объединять сотрудников из разных офисов. В общем действительно надо подумать.
Тут еще видимо есть у меня и дополнительная проблема, у меня в системе встроенный язык программирования (свой) и вся внутренняя кухня аккаунта сделана на нем, а все php-шное — это фактически интерпретатор, поэтому индивидуальный UTC на каком-то модуле должен реализовываться на уровне программирования на внутреннем языке, а не на интерпретаторе или базе данных.

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

По поводу
А теперь представьте, что вам надо посчитать продолжительность выполнения задачи, которая начата до перевода времени с летнего на зимнее, а закончена — после.

Если будет необходим такой подсчет, то такой его нюанс можно реализовать программно. Момент перевода времени известен, сделать IF в процедуре, например если время перевода попадет между датами начала и конца — прибавить к продолжительности час (или вычесть — по ситуации). В общем тут я проблемы не вижу.

Вы, похоже, не понимаете, что такое UTC.


оба позвонят начальнику и скажут: один что товар выдан в 10.00, другой что в 12.00 :) и кому верить?

Никому не верить, верить системе, которая скажет, что товар выдан в 11 по времени склада.


И какой при этом UTC отображать в графике группы в которую входят оба сотрудника?

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


Тут еще видимо есть у меня и дополнительная проблема, у меня в системе встроенный язык программирования (свой) и вся внутренняя кухня аккаунта сделана на нем, а все php-шное — это фактически интерпретатор, поэтому индивидуальный UTC на каком-то модуле должен реализовываться на уровне программирования на внутреннем языке, а не на интерпретаторе или базе данных.

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


Если будет необходим такой подсчет, то такой его нюанс можно реализовать программно. Момент перевода времени известен, сделать IF в процедуре, например если время перевода попадет между датами начала и конца — прибавить к продолжительности час (или вычесть — по ситуации). В общем тут я проблемы не вижу.

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

А почему в качестве точки отсчёта выбрано московское время, а не UTC?
Потому что они в Москве физически. Так удобнее, помимо самих баз данных пользователей есть еще куча служебных вещей.
Вы решаете проблему, которая возникла из-за того, что вы (или кто-то) что-то неправильно делали изначально. Зачем вообще надо хранить время в любом локальном (naive, не-aware, итд) времени, вот как должен вопрос ставиться. Если датавремя представляет конкретную точку во врмени, то оно всегда должно храниться в БД вместе с таймзоной, либо просто подразумеваться UTC (что предпочтительнее и не отменяет первого варианта).
Это сложно. Представляете в 3 мб php кода (половина их которого гигантские sql запросы) Вам надо везде делать операции преобразования времени! В детсяти тысячах мест! А так Вам не надо задумываться над всем этим, все в базе данных решено уже. Да и лишние операции, быстродействие ниже и т.д. (хоть это и копейки). И например у нас реализовано программируемое API, т.е. пользователь может в своей БД создать триггер специальный, который передаст инфорамцию во вне. В этом случае там будет время по МСК? Или принимать данные извне как? В общем много причин почему сделано так.

Но я как бы не претендую на правильность. Я просто описал способ как это можно сделать, кому-то понравится, а кто-то придумает как сделать по своему. Но данный способ оказался наиболее простым и эффективным.
Это не сложно, это единственный правильный путь работы со временем.
Это должно делаться (и у всех делается) в одном месте — в той или иной прослойке, которая у вас работает с БД. В большинстве бд-фреймворках/орм итд всё это есть искаропки, конечно, потому что по-другому просто нельзя.
В этом случае там будет время по МСК? Или принимать данные извне как?
Пусть хоть по тихоокеанскому, время никогда нельзя передавать, обрабатывать и хранить без привязанной таймзоны (или подразумевания что там UTC, что очевидно для случая, например, типа unixtime). Нет понятия «время по МСК», время оно и есть время — просто временной штамп. По МСК оно может стать при показе его в этой таймзоне. Нет, можно и передавать его по МСК и даже хранить (только непонятно зачем), но надо тогда так и оперировать везде «01.02.2016 22:22:58; МСК», потому что нет времени «01.02.2016 22:22:58» — это не время, а билиберда.
Так же всё и про «принимать извне».
Не, я просто ещё раз прочитал всё, и не могу понять — у вас в конкретной колонке в БД в каком виде лежит время? Во всех в «московской таймзоне» а вы просто во вьюхах его конвертируете и отдаёте наружу? Просто вот это конкретно сбивает с толку: «Благодаря этому, во всех записях в БД всегда будет проставляться время пользователя, а не московское». Все именно от этого в ужас пришли. Это надо подробнее объяснить вам, потому что не верится в такое.
У юзера сейчас рисуется допустим 12:00 для какой-то сущности, если юзер меняет таймзону (допустим соседнюю на час) то он увидит теперь везде 13:00? Правильно же? Тогда как это делается с учётом, что в БД неизвестное время неизвестной таймзоны?
Нет, view используется при запаси или изменении данных. Селект при этом будет обычный, и в нем уже будет время пользователя. В этом то и преимущество. Никакой дополнительной математики при выводе данных.
Если вы боитесь что при изменении часового пояса может получится белеберда с записями в старом часовом поясе, то во первых такие изменения делает только администратор аккаунта, во вторых это как правило разово (разве что компания решит куда-то переехать), в третих ведутся логи изменений, т.е. можно посмотреть когда было изменение часового пояса и с какого на какой и понять что откуда растет. Я в этом не вижу проблемы. Ну зачем компании больше одного раза менять часовой пояс? Они же сами себе хаос делают…
Вот тут немного не понял…
Поясните пожалуйста логику работы программы при таком случае: сегодня я в Петропавловске, а завтра в Петрозаводске. Сегодня я начал забивать отчёт, а завтра хочу его расширить новыми данными. Какое время мне инсентировать и какое я буду видеть на экране, когда вернусь в Москву?
Ну если мы рассматриваем мою систему, то есть аккаунт компании, аккаунту выделяется база данных и в настройках можно выставить часовой пояс (для компании). При изменении настроек сформируются соответствующие view в БД и будет в дальнейшем писаться соответствующее время, где бы сотрудник не находился, хоть в антарктиде если там есть интернет. В общем неважно где вы физически, время будет — тот момент когда вы сделаете запись по московскому времени (в моем случае) скорректированное до часового пояса из настроек.

Я не претендую на то что это единсвенно-правильный вариант, каждый его реализует все равно по своему. Статью я написал потому, что в свое время я не нашел нигде описанного способа как такое сделать и сделать это на практике у меня получилось. Может кому-то пригодиться если будет стоять похожая задача.
Статью я написал потому, что в свое время я не нашел нигде описанного способа как такое сделать

Может потому что так никто не делает?) Дело не в том, что у вас правильный или неправильный вариант реализации, вам пытаются объяснить, что сам подход неправильный, независимо от того, как он реализован. Как-то даже странно, что при проектировании системы "с огромным числом потенциальных пользователей в любом регионе" работа с временными зонами была недостаточно продумана.


Как я понял, между базой и пользователем у вас есть прослойка на PHP. Скорее всего, там есть какая-нибудь функция query(), которая выполняет запросы на чтение. Вот там после запроса можно пробегаться по полям результата и для полей datetime и timestamp делать конвертацию в таймзону пользователя. А в базе все хранить в одной фиксированной таймзоне с известным смещением (неважно, в UTC или по Москве).

Ну на самом деле на php у меня — интерпретатор, структура конфигурации аккаунта хранится в самой базе и интерпретируеся при выводе страницы, пользователю предоставляется специальный язык программирования для конфигурирования аккаунта (и базы данных и веба), вот там как раз создаются и компилируются процедуры и триггеры в БД.
В php как вы описали — делать не вариант, учитывая то, что пользователь строит сам конфигурацию, вы никогда не угадаете что это дата которую надо форматнуть (вернее угадаете, но не понятно зачем такие сложности то вообще и дополнительное процессорное время). Если так и делать то надо обрабатывать не результаты вывода query(), а в самом поле sql. Т.е. на уровне компилирования процедур на внутреннем языке. Собственно, грубо говоря, так и сделано, только через VIEW.
Почему неправильно делать именно каждому пользователю свой UTC (а надо делать компании) я описывал уже подробно «mail-online 17 декабря 2016 в 15:05» (CTRL-F сделайте)

Кстати, может кто знает, в битриксе, мегаплане, клиентской базе и т.д. есть настойка часового пояса вообще? Я например обыскал все настройки в битриксе — я не нашел… У меня есть такое подозрение, что никто не просто так не делает, а никто вообще не сделал такого в принципе.
что пользователь строит сам конфигурацию, вы никогда не угадаете что это дата которую надо форматнуть

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


У меня есть такое подозрение, что никто не просто так не делает, а никто вообще не сделал такого в принципе.

Да ладно. В Jira это есть, скажем. В любом приличном современном мессенджере это есть.


(ну и в ERP-системе, в разработке которой я участвую, тоже есть, чего уж)

оба позвонят начальнику и скажут: один что товар выдан в 10.00, другой что в 12.00

Начальник компании, работающей в разных регионах, должен уточнить, в каком часовом поясе эти данные.
Представьте эту ситуацию в реальности, без использования компьютеров. Один сотрудник уехал в командировку в другой часовой пояс, ему звонит другой со склада, и говорит "товар только что прибыл". Какое время он должен начальнику сказать?


И вот представьте ситуацию, у одного сотрудника из группы стоит один UTC, а у другого другой! И какой при этом UTC отображать в графике группы в которую входят оба сотрудника?

В графике (в БД) время хранится в фиксированном часовом поясе. Каждому сотруднику он отображается в его часовом поясе. Чтобы сотрудник знал, что информация "в 12:00 мне позвонят из города N" это по его локальному времени.


вы никогда не угадаете что это дата которую надо форматнуть (вернее угадаете, но не понятно зачем такие сложности)

Насколько я понял из документации, ibase_field_info() возвращает информацию о типе поля в результате запроса. Особых сложностей тут нет, а надо все это, чтобы правильно учитывать время и правильно его отображать. Без ограничений бизнес-логики типа "и при этом запрещать программно объединять сотрудников из разных офисов".


Если так и делать то надо обрабатывать не результаты вывода query(), а в самом поле sql

Если так делать, то надо это делать в представлении при рендеринге значения со временем (заодно и формат можно задать, "d.m.Y" или "m.d.Y" или любой другой):


<td><?= $formatter->asDatetime($row['created_at']) ?></td>
Вернее в селекте в некоторых случаях тоже может использоваться эти view, например в каких-то фильтрах по умолчанию подставляться. Но у меня в реализации этого нет проблем, т.к. эти параметры вшиты во внутренний язык программирования аккаунта, поэтому пользователь не будет задумываться и даже видеть эти внутренние процессы напрямую, для него просто будет текущая дата-время и все.
У юзера сейчас рисуется допустим 12:00 для какой-то сущности, если юзер меняет таймзону (допустим соседнюю на час) то он увидит теперь везде 13:00? Правильно же?


Нет, юзер увидит 12.00 везде. В старых записях все останется по прежнему. Но новая запись будет не 12.01 а уже 13.01 в случае +1 в таймзоне.
Нет, юзер увидит 12.00 везде.
Это же катастрофически неправильно. 12:00 в соседней таймзоне это не 12:00 же.
Или обратное: То есть юзер создал в 12:00 запись. Потом мгновенно переместился в соседнюю таймзону и создал запись и у вас в БД запишется две записи:
12:00
13:00
И потом он будет видеть эти два времени в таком виде из любой таймзоны? Несмотря на то, что на самом деле это одно и то же время?

Теперь более реальный случай: юзер из Челябинска (+05:00) такой в 12:00 создал запись и видит 12:00, о, думает всё нормально. А теперь в эту же запись (в это время или же назаватра) смотрит юзер из Москвы (+03:00) и какое время он видит то? 12:00 что ли? Если 12:00, то это жесть полная. Если 10:00 то как раз в этом вопрос — непонятно как это сделано, если, блин, вы не знаете что такое 12:00 на самом деле и в какой таймзоне («локальное время пользователя»).
Мне кажется что подразумевается: компания работает только в одном часовом поясе, сотрудников из другого часового пояса не будет (либо они работают по времени компании).
Ну а с законодательным изменением часовых поясов еще не сталкивались, разработка началась после последнего изменения.

Нет. Если мы рассматриваем мой случай, то таймзона меняется для аккаунта. Аккаунт выдается для компании в которой работают сотрудники, и на этот аккаунт как раз выделяется база данных в которых прописываются данные view. Если оба сотрудника (юзера) работают в этом аккаунте, то время их записи будет отображаться в таймзоне аккаунта. Если стоит таймзона Челябинска (+5) и юзер из москвы сделал запись в 12:00 (+3) по своему времени, то в БД запись будет 14:00 и откуда бы и кто бы не смотрел это будет запись 14:00 всегда. Всегда в UTC Челябнска откуда бы она сделана не была.
Всегда в UTC Челябнска откуда бы она сделана не была.

Маленький хинт: UTC Челябинска ничем не отличается от UTC Москвы, и в обоих них эта запись будет отражаться в 9:00.

Всегда в UTC Челябнска откуда бы она сделана не была.
Это шутка такая или вы реально не понимате даже что такое UTC???

Вы бы описали подробнее свое приложение, а то выглядит как будто вы сначала создали себе проблему, а потом героически ее решили, притом непонятно с какой целью.
У вас не бывает случая, когда несколько пользователей работают с одной БД? Почему обязательно нужна конвертация на стороне БД, а не в PHP? И кстати почему вью, а не процедура?

View, по смыслу легче процедур, и лучше обрабатываются оптимизатором.
это облачная платформа erp-platforma.com, с системой автоматизации для предприятий, типа битрикса если в курсе что это такое, только круче, т.к. есть встроенный язык программирования и каждый пользователь может сам настраивать свою БД или веб интерфейс в аккаунте, ну и куча фишечек и плюшечек типа SCRUM досок, программируемого API и т.п. + универсальная система задач, которая подходит даже для провайдеров. Но это не суть важно т.к. все настолько универасально, что каждый пользователь может создать себе любой модуль сам, хоть бухгалтерию написать…

Т.к. все универсально и индивидуально, то каждому пользователю и выделяется своя БД, вернее даже 4 штуки, основная, файловая, для безопасных ссылок и бд для логов. Я некоторые из технических реализаций этих вещей в следующих статьях буду описывать. Еще много всего интересного можно написать, следующая думаю будет звучать «Как вести логи изменений данных пользователями в базе данных, сохраняя их в другой базе данных (чтобы основная база данных не засорялась мусором и не росла)» — интереснейшая вещь была с технической точки зрения.

View — так проще, как в запросе вы процедуру планируете использовать, left join? это неудобно, а тут просто вместо например timestamp пишете d_timestamp и все работает.
Простите, наболело, но руки оторвать за такую работу с датами. Дата сама по себе не имеет привязки к часовому поясу это тупо Long. К часовому поясу привязано представление даты (строка, виджет). Можно использовать концепцию Model-View, где сама дата это модель, а строка или виджет на форме это представление. Как только вы начинаете модифицировать дату, ваш код становится некорректным. В транспорте дата это или Long, или строка но обязательно с таймзоной.

>> Благодаря этому, во всех записях в БД всегда будет проставляться время пользователя => а потом примут закон о смещении часовых поясов и корректность прошлых данных накроется медным тазом.
Вот тоже подумал про законные смещения. У нас за последний десяток лет два раза принимали закон о переходе на час и, соответственно, о не переходе. В итоге, когда я захочу получить срез данных за последние пять лет — я не понятно что увижу…
Ну она в любом случае накроется если это случиться. Разобраться что за последние 5 лет творилось с часовыми поясами и переходами на летне-зимнее время… так там чет ногу сломит. Но мне кажется это на самом деле не критично, ибо на фоне 5 лет час туда сюда сколько процентов занимает? Час это 1/43800. Это потеря точности 0.0022831%
Тут конечно вопрос что вам необходимо, но проработав 10 лет в телекоме я никогда не сталкивался с тем чтобы делать подобные анализы и тем более со 100% точностью. Детализации делали, да, но там юникстайм который был на оборудовании и никто не заморачивался. В случае перехода на зимнелетнее время получалось что траифк писался 2:59, потом 2:00. Грубо говоря час накладывался друг на друга (или был промежуток в другом случае)
Но мне кажется это на самом деле не критично,

Это вам так кажется, пока этот час внезапно не выпадает на смену дня, и у вас в документе написана одна дата, а в системе — другая.

А не пробовали проверять что происходит с датами при использовании ON EXTERNAL DATA SOURCE в dsql?
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории