Думаю, Sciter тут представлять не надо и его все знают.
Есть в нем закавыка с контролом ввода даты.
В форме ввода я выбираю дату при помощи выпадающего календаря, далее эта дата заворачивается в JSON и отправляется на веб-сервер.
На веб-сервере я обнаруживаю, что получаю не ту дату, которую вводил, а UTC, то есть минус три часа поправки на мой часовой пояс, или иными словами не 25.03.2015, а 24.03.2015 21:00.
То есть контрол сам поправил введенную мной дату и привел ее к UTC.
Академически все правильно: Андрей считает, что в распределенных приложениях, которые могут работать с сервером откуда угодно, дату/время нужно приводить к UTC и я в этом с ним согласен.
Должен ли такое преобразование самостоятельно выполнять контрол, работающий в Presentation Layer?
Или же это ответственность Buisness Layer-а (контроллера, презентера или чего там еще)?
Т.е. я считаю, что я, если хочу, должен перед отправкой JSON на сервер самостоятельно внести коррекцию TimeZone во все даты в JavaScript/TIScript-контроллере, или как-то передать веб-серверу TimeZone клиента (через Cookie, через сессию, или вообще вынести настройку TimeZone пользователя в профиль пользователя, хранящийся в базе данных).
Оба неправы.
Дата (без времени) не должна преобразовываться вообще.
ДатаВремя в явном виде должна передаваться с timezone (datetimeoffset), коррекция только при выводе если необходимо (tolocaltime).
Если человек вводит дату\время локально, то нужно определять (передавать на клиент) таймзону по географии. Если невозможно, то хранить в профиле.
Re: Локализация дат и в распределенных приложениях
Здравствуйте, baranovda, Вы писали:
B>Думаю, Sciter тут представлять не надо и его все знают.
B>Есть в нем закавыка с контролом ввода даты. B>В форме ввода я выбираю дату при помощи выпадающего календаря, далее эта дата заворачивается в JSON и отправляется на веб-сервер. B>На веб-сервере я обнаруживаю, что получаю не ту дату, которую вводил, а UTC, то есть минус три часа поправки на мой часовой пояс, или иными словами не 25.03.2015, а 24.03.2015 21:00. B>То есть контрол сам поправил введенную мной дату и привел ее к UTC.
B>Академически все правильно: Андрей считает, что в распределенных приложениях, которые могут работать с сервером откуда угодно, дату/время нужно приводить к UTC и я в этом с ним согласен.
B>Должен ли такое преобразование самостоятельно выполнять контрол, работающий в Presentation Layer? B>Или же это ответственность Buisness Layer-а (контроллера, презентера или чего там еще)?
Я честно говоря не понимаю твою проблему...
Мне кажется ты как-то неправильно это все интерпретируешь.
Дано:
1. Sciter у которого есть тип Date который хранит UTC дату и время. Как и в JavaScript.
2. Есть <input|date> и <input|time> у которых value тоже Date.
3. Эти inputs показывают дату (UTC) с учетом текущей timezone пользователя (есть возможность задать любую timezone но это не важно в данном случае).
Ну вот какие проблемы с этим:
var birthday = $(input[type=date]);
// Values that user sees:
// birthday.value.day
// birthday.value.month
// birthday.value.year
// Also available
// birthday.value.UTCday
// birthday.value.UTCmonth
// birthday.value.UTCyear
?
То как ты кодируешь дату или время при JSON передаче абсолютно не релевантно. Это функция твоего контроллера который стоит между моделью данных и view.
JSON не специфицирует никак даты — т.е. это сугубо твой бизнес. Приведи свои форматы дат к Date (UTC) при отправке и получении JSON от сервера и проблемы нет.
И в общем случае сервер обязан хранить даты событий в UTC.
я думаю, что бизнес-слой должен помогать слою презентации с тайм-зоной, т.е. либо её "угадывать" для плохо профилированного пользователя, либо "почти принудительно подставлять" для хорошо-профилированного пользователя
при этом слой презентации должен отвечать за передачу на бизнес-слой полного времени, т.е. с указанием TZ, при этом TZ подставляется либо автоматически, но наглядно для пользователя через ту самую помощь бизнес-слоя, либо вручную, т.к. пользователю даётся возможность её указать.
хранение времени на backend'е нагляднее всего делается такими типами как oracle timestamp with tz — по ним суппорт, работающий на уровне БД, видит всё сразу без необходимости арифметизировать головой, при этом вся арифметика и сравнение поддержано БД на своём уровне
Re[2]: Локализация дат и в распределенных приложениях
Здравствуйте, gandjustas, Вы писали:
G>Дата (без времени) не должна преобразовываться вообще.
Как-то уж слишком категорично-оптимистично.
Скажем такая безобидная вещь как "день рождения"... я у себя на West Coast (UTC -8) ввожу её в систему.
И сервер, скажем, в Японии (UTC +9) сконфигурирован на посыл поздравлений по утру клиента.
Как это сделать без TZ?
Это я к тому что даже "просто дата" должна в общем случае храниться в системе с timezone.
Re[2]: Локализация дат и в распределенных приложениях
Здравствуйте, c-smile, Вы писали: CS>Я честно говоря не понимаю твою проблему... CS>Мне кажется ты как-то неправильно это все интерпретируешь. CS>То как ты кодируешь дату или время при JSON передаче абсолютно не релевантно. Это функция твоего контроллера который стоит между моделью данных и view.
Попробую на пальцах
Пример (рядом нужно положить plus.tis и plus.css):
<html>
<head>
<style>
@import url(plus.css);
</style>
<script type="text/tiscript">
include"plus.tis";
var Model = {
date: new Date();
}
function self#test1.onClick()
{
view.msgbox(#alert, self#date.value);
}
function self#test2.onClick()
{
view.msgbox(#alert, String.printf("%v", Model));
}
function self#test3.onClick()
{
var d = new Date("2015-03-24T21:00:00");
view.msgbox(#alert, Date.timeZoneOffset());
d.millisecond += Date.timeZoneOffset();
view.msgbox(#alert, d.toLocaleString());
Model.date = d;
}
</script>
</head>
<body>
<form model="Model">
Case date: <input type="date" name="date" id="date" />
</form>
<div model="Model">
Date: <output name="date" type="date"/> Time: <output name="date" type="time"/>
</div>
<button id="test1">Show control date</button>
<button id="test2">Show JSON</button>
<button id="test3">Set date</button>
</body>
</html>
a) Ввожу дату — 25.03.2015
б) На сервер приходит 2015-03-25T21:00:00 (UTC). Я эту дату сохраняю в базу
в) Теперь клиент перезапрашивает данные и мне нужно эту дату отрисовать например в <table>.
в.1) Сервер отдает дату, хранящуюся в базе данных as is. Выполним в Sciter self#date.value = new Date("2015-03-24T21:00:00"). В datepicker-е рисуется 24.03.2015
в.2) Сервер должен отдать клиенту дату с учетом клиентской TimeZone. Но откуда он ее в общем случае знает?
в.3) Клиентский контроллер должен сам интерпретировать полученное от сервера значение с учетом TimeZone клиентской рабочей станции: var d = new Date("2015-03-24T21:00:00"); d.millisecond += Date.timeZoneOffset();
В пункте в.3) и заключается весь геморрой, связанный с тем, что нужно везде и всюду держать в уме смещение.
Если выполнить в sciter мой пример, то проблема видна более выпукло. Три элемента прибайндены к одному и тому же полю модели, при этом видно, что date я выбираю 25.03.2015, а в output-ах рисуется 24.03.2015 21:00 CS>JSON не специфицирует никак даты — т.е. это сугубо твой бизнес. Приведи свои форматы дат к Date (UTC) при отправке и получении JSON от сервера и проблемы нет. CS>И в общем случае сервер обязан хранить даты событий в UTC.
ИМХО это диктуется бизнес-логикой. Взять ту же дату рождения человека — важный учетный и статистический показатель, UTC в данном случае вообще не нужно, а если клиент будет сам даты приводить к UTC — то даже вредно. В самом деле, человек родился 1 января 1960, а в базу ляжет 31 декабря 1959, и человек вылетит из статистики за 1960-й год
Re: Локализация дат и в распределенных приложениях
Здравствуйте, baranovda, Вы писали:
B>Должен ли такое преобразование самостоятельно выполнять контрол, работающий в Presentation Layer? B>Или же это ответственность Buisness Layer-а (контроллера, презентера или чего там еще)?
В бизнес-приложениях должно быть 2 разных типа даты-времени:
* global time (для фиксации момента наступления какого-либо факта, хранится в UTC + опционально timezone клиента). Для дотнета это будет System.DateTimeOffset.
* local time (шаблоны, расписания, время действия для всяких акций, даты договоров до заключения). Хранится просто абстрактная дата-время, без привязки к точному времени, операции сравнения к ней неприменимы. Для дотнета — System.DateTime.
Как правило local time используется только в шаблонах, при отработке в реальные бизнес-сущности данные переводятся в global time с учётом часовой зоны клиента.
Что куда относить — ответственность биз-логики, но само разделение обязательно. Это как с invariant string / current culture string: разные контексты, разная логика обработки, лучше не смешивать.
Re[2]: Локализация дат и в распределенных приложениях
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, baranovda, Вы писали:
S>* global time (для фиксации момента наступления какого-либо факта, хранится в UTC + опционально timezone клиента). Для дотнета это будет System.DateTimeOffset. S>* local time (шаблоны, расписания, время действия для всяких акций, даты договоров до заключения). Хранится просто абстрактная дата-время, без привязки к точному времени, операции сравнения к ней неприменимы. Для дотнета — System.DateTime.
Спасибо, это понятно. Вопрос заключается в том, должен ли UI-контрол ввода имплиситно трансформировать введенное значение в UTC,
или же это не его ответственность и контрол должен оперировать только локальными датой-временем, а трансформацией значения из/в UTC должен заниматься посредник (для веб, например какой-нибудь JavaScript-контроллер), который при необходимости добавляет-вычитает TimeZone
Re[3]: Локализация дат и в распределенных приложениях
Здравствуйте, baranovda, Вы писали:
B>Спасибо, это понятно. Вопрос заключается в том, должен ли UI-контрол ввода имплиситно трансформировать введенное значение в UTC,
Определяется биз-логикой.
Если это local time, то контрол должен отдавать значение как есть. Ну, или должен быть костыль, который приводит значение к тому, что ввёл пользователь.
Если это global time, то он практически никогда не задаётся через поле ввода, т.к. используется для фиксации конкретного момента времени. Если уж припёрло — контрол должен отдавать UTC time + таймзону пользователя (т.е. дотнетовский DateTimeOffset). Или снова костыль, чтобы привести значение контрола к нужному.
Re[3]: Локализация дат и в распределенных приложениях
Здравствуйте, c-smile, Вы писали:
CS>Это я к тому что даже "просто дата" должна в общем случае храниться в системе с timezone.
1. Обычное правило — дата должна храниться в UTC. Преобразования в локальную делаются "на клиенте" — там, где есть информация о географии. Т.е. когда я ввожу в систему дату "завтра в 8 утра", она конвертируется из моей локальной зоны и на сервере существует в UTC. При показе клиенту она конвертируется в его TZ, и запросто может оказаться 6ю вечера.
2. Два исключения:
— искусственная привязка к TZ. Например, если у меня еженедельный митинг назначен на 8:00 по времени Сиэтла, то я ожидаю, что он будет а 8:00 и зимой, и летом. Т.е. "абсолютное" время начала, по UTC, будет прыгать каждый раз при переходе с PST на PDT и обратно. Это заметно тем участникам, кто живёт по локальному времени с другими правилами Daylight Savings (например, всем россиянам). Если тот же митинг привяжу к времени Новосибирска (1:00), то он будет "прыгать" для участников из Сиэтла. Привязывать его к UTC не имеет смысла, т.к. тогда он будет "прыгать" для большинства участников.
— относительные времена. Скажем, будильник можно трактовать как регулярное ежедневное событие, но оно всегда привязано к локальному часовому поясу, и перемещается вместе со мной. Т.е. если у меня стоит будильник на 8 утра, то я ожидаю и в командировке просыпаться в 8 утра, а не в 6 вечера.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Локализация дат и в распределенных приложениях
Здравствуйте, baranovda, Вы писали: B>ИМХО это диктуется бизнес-логикой. Взять ту же дату рождения человека — важный учетный и статистический показатель, UTC в данном случае вообще не нужно, а если клиент будет сам даты приводить к UTC — то даже вредно. В самом деле, человек родился 1 января 1960, а в базу ляжет 31 декабря 1959, и человек вылетит из статистики за 1960-й год
Нет, вот в данном конкретном случае только UTC и нужно, т.к. рождение — это объективное событие, дата которого не зависит от выбранного календаря.
А вот "статистика" — это всего лишь точка зрения на объективную реальность. Грубо говоря, я могу построить гистограммы рождаемости по Григорианскому календарю, а могу — по Юлианскому.
Цифры, естественно, будут отличаться — но это потому, что отличаются мои запросы.
Если я захочу получить статистику, сравнивая, скажем, количество детей родившихся ночью с количеством родившихся днём, то мне придётся помимо дат рождения хранить ещё и географию — чтобы пересчитывать UTC в локальное астрономическое время.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Локализация дат и в распределенных приложениях
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, baranovda, Вы писали: S>Если это local time, то контрол должен отдавать значение как есть. Ну, или должен быть костыль, который приводит значение к тому, что ввёл пользователь
Немного покопал реализации input type=date
1) Спецификация W3С сообщает, что свойство value должно возвращать string в формате RFC 3339 (YYYY-MM-DD)
<!DOCTYPE html>
<html>
<head>
<script>
function test()
{
var d = document.getElementById("bday").value;
alert(d);
}
</script>
</head>
<body>
<p>
Depending on browser support:<br>
A date picker can pop-up when you enter the input field.
</p>
<form action="action_page.php">
Birthday:
<input type="date" name="bday" id="bday">
<input type="submit">
<button onclick="test()">Test</button>
</form>
<p><b>Note:</b> type="date" is not supported in Internet Explorer.</p>
</body>
</html>
Opera 12.17 и Chrome возвращают мне строку в соответствии со спекой W3C
3) Пробуем вместо input type="date" сделать input type="datetime".
<!DOCTYPE html>
<html>
<head>
<script>
function testget()
{
var d = document.getElementById("bday").value;
alert(d);
}
function testset()
{
var d = document.getElementById("bday");
d.value = "2002-05-30T09:30:10+06:00";
return false;
}
</script>
</head>
<body>
<form action="action_page.php">
Birthday:
<input type="datetime" name="bday" id="bday">
<input type="submit">
</form>
<button onclick="testget()">Get datetime</button>
<button onclick="testset()">Set datetime</button>
</body>
</html>
Chrome 41 такой контрол не поддерживает, но поддерживает datetime-local
Opera 12.17 приятно удивила: она нарисовала композитный контрол, состоящий из календаря и элемента ввода времени, и рядом подписала "UTC".
Свойство value этого контрола вернуло строку "2015-03-19T12:00Z"
При записи в этот контрол времени со смещением в Опере часовой пояс игнорируется.
Здравствуйте, baranovda, Вы писали:
B>* * * B>Пока делаю выводы, что в реализации броузеров контролы ввода датой-временем самодеятельности не проявляют
Наиди разницу в этих двух случаях:
value of W3C input date/time есть строка которая в общем случае к тому что ты передаешь на сервер в виде JSON отношения не имеет — ты должен её/их конвертирвать к представлению в BL/DB.
value of Sciter input date/time есть объект Date который в общем случае к тому что ты передаешь на сервер в виде JSON отношения не имеет — ты должен её/их конвертирвать к представлению в BL/DB.
Рззница как ты понимаешь лишь в реализации двух функций parseDate/emitDate ниже:
Здравствуйте, baranovda, Вы писали:
B>Свойство value этого контрола вернуло строку "2015-03-19T12:00Z" B>При записи в этот контрол времени со смещением в Опере часовой пояс игнорируется.
input|date, input|time и input|calendar в Sciter имеют value of Date type по одной простой причине: устранение неоднозначности.
Вот скажем есть <input type=date> и ты ему значение устанавливаешь строкой "15.03.15".
Что должно показаться? Учитывая то что HTML не специфицирует реакцию на ошибку parsing.
В Sciter перед тем как показать ты вынужден сделать new Date("15.03.15") что вызовет throw error в коде.
Re[4]: Локализация дат и в распределенных приложениях
Здравствуйте, Sinclair, Вы писали:
S>2. Два исключения: S>- искусственная привязка к TZ. Например, если у меня еженедельный митинг назначен на 8:00 по времени Сиэтла, то я ожидаю, что он будет а 8:00 и зимой, и летом. Т.е. "абсолютное" время начала, по UTC, будет прыгать каждый раз при переходе с PST на PDT и обратно. Это заметно тем участникам, кто живёт по локальному времени с другими правилами Daylight Savings (например, всем россиянам). Если тот же митинг привяжу к времени Новосибирска (1:00), то он будет "прыгать" для участников из Сиэтла. Привязывать его к UTC не имеет смысла, т.к. тогда он будет "прыгать" для большинства участников.
Всё так но с одним исключением: сервер время начала совещания должен отдавать в UTC иначе люди из Сиэтла и из Новосиба не встретяться никогда.
Сервер хранит дату начала совещания как пару office-location / start-offset-minutes. Но отдает всегда в UTC.
Т.е. Вася Новосибирский должен видеть митинги офиса в Сиэтле в локальной зоне Новосиба. Или Гаваев каких если туда Васю забросила суровая программерская доля в тот момент.
Re[6]: Локализация дат и в распределенных приложениях
Здравствуйте, c-smile, Вы писали:
CS>Рззница как ты понимаешь лишь в реализации двух функций parseDate/emitDate ниже: CS>Что в этих parseDate/emitDate такого военного ?
Падажьжьи.
Вот взял твой пример as is, Sciter 3.2.0.6
Загрузил страницу.
Нажал на кнопку Load.
В дэйтпикере нарисовалось у тебя что? У меня — 24.03.2015, хотя json.date = "2015-03-25".
И при нажатии на Save диалог показывает 2015-03-24
Вот картинка
PS Я прекрасно понял, что творится там внутрях: после вызова parseDate дата автоматом конвертнулась в UTC, но такое поведение обескураживает, так как распарсили одно, а в месседжбоксе видим другое.
Если б я хотел отправить на сервер дату именно в UTC, я бы хотел взять локальную дату-время, вычесть из нее смещение и отправить результат.
Здравствуйте, c-smile, Вы писали:
CS>Всё так но с одним исключением: сервер время начала совещания должен отдавать в UTC иначе люди из Сиэтла и из Новосиба не встретяться никогда.
Вопрос "отдачи" для меня вторичен — если клиент достаточно умён, чтобы конвертировать UTC в локальную, то ок.
А если нет — то серверу придётся хранить зону в предпочтениях пользователя — вместе с locale для языка интерфейса и представления валют, дат, и чисел.
CS>Сервер хранит дату начала совещания как пару office-location / start-offset-minutes. Но отдает всегда в UTC. CS>Т.е. Вася Новосибирский должен видеть митинги офиса в Сиэтле в локальной зоне Новосиба. Или Гаваев каких если туда Васю забросила суровая программерская доля в тот момент.
Совершенно верно.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Локализация дат и в распределенных приложениях
Здравствуйте, baranovda, Вы писали:
B>Кто прав?
Я не знаю Sciter, но...
Нужно уметь различать дату и время события. Время — оно одно для всех (если не учитывать релятивистские эффекты), а вот дата...
Дата зависит от календаря и перевести одну дату в другую не так-то просто и не всегда однозначно возможно. За примерами далеко ходить не надо. Допустим вы хотите назначить встречу в день Пасхи или в первый день рамадана. В зависимости от года этой дате будет соответствовать разный день в Григорианском календаре.
И каждый день — без права на ошибку...
Re: Локализация дат и в распределенных приложениях
Здравствуйте, baranovda, Вы писали:
B>Кто прав?
Не знаю что такое sciter, решайте сами.
Жизнь она такая, вся сякая. История из жизни, только пункты изменены. Сидят люди в Магадане. И выполняют задания из москвы. А в москве 21 число по московскому времени. Москвичи наглые, они так привыкли. А в Магадане исполнить 21 числа понималось не так как эти наглые Москвичи думают. Проблема была большая и плотная, и решилась простейшим способом. Всех не отправили в Москву... То есть не то чтобы неотправили, а все компьютеры перевели на московское время. И стало им хорошо, тепло и пушисто...
Сейчас работаем над решениями с повышенной мобильностью. Для разрешение вышеописанных проблем, пользователь работает по серверному времени, о чем ему и сообщается в документации/обучении. Юзверям так удобней. А программистам — просто нужно адаптировать функцию Now и давить пояса при стандартной сериализации.