Я хочу рассказать о простой задаче — вывод даты на главной странице Mail.Ru. Маленькая задача, нетривиальное решение.
Решение в лоб:
function print_date(date){
return date.getDate() + ' ' + getMonth(date.getMonth()) …
}
print_date( new Date() );
Недавно появлся еще один блок на странице. Начался чемпионат мира по хоккею, и надо выводить начало матча. Но время у каждого пользователя должно быть синхронизировано с его часовым поясом.
Тоже не слишком сложно — от сервера нам приходит timestamp начала матча. На клиенте вызываем уже сделанную нами функцию.
print_date( new Date(timestamp) );
Однако не всегда возможно правильно автоматом определять регион пользователя. Например, мой домашний провайдер в нашем районе стал выдавать IP-адреса из диапазона, которого у него раньше не было. Все порталы предлагали мне разные места на нашей планете, но в одном они все были согласны: я точно нахожусь далеко от Москвы. Именно для таких ситуаций мы предлагаем пользователю выбрать город самостоятельно.
Естественно, все даты должны быть синхронизированы с выбранным городом, а это означает, что текущее смещение пользователя относительно Гринвича может быть некорректным.
У нас есть timestamp начала матча и часовой пояс выбранного города. На клиенте делаем дату и смещаем ее на разницу между текущим смещением пользователя и смещением в выбранном городе.
var date = new Date(timestamp);
date.setMinutes(town_offset + date.getTimezoneOffset())
print_date(date)
Почему плюс между own_offset и date.getTimezoneOffset(), можно прочитать тут: developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset#Description
Теперь, если пользователь в Самаре, но выбрал Москву, мы корректируем объект Date на разницу между этими двумя городами.
С выводом времени начала матча разобрались, но есть еще и текущая дата. А с ней не все так гладко. При выводе даты матча мы используем timestamp из базы, а при выводе текущей даты мы используем new Date() на клиенте.
var date = new Date();
date.setMinutes(town_offset + date.getTimezoneOffset())
print_date(date)
А это значит, что мы используем timestamp пользовательского компьютера. Пользователь может вручную перевести свои часы, и тогда мы получаем некорректный текущий timestamp. Поэтому текущий timestamp мы тоже вынуждены передавать с сервера.
var date = new Date(server_timestamp);
date.setMinutes(town_offset + date.getTimezoneOffset())
print_date(date)
Но и это не конец — часы на главной странице должны «тикать», пусть мы не можем доверять пользовательскому timestamp, но на смещение timestamp относительно загрузки страницы можно положиться. На то, что пользователь собьет себе локальные часы именно посередине просмотра новостей на главной, закладываться не будем.
var begin = new Date().getTime();
function get_delta(){
return new Date().getTime() - begin;
}
function update_time(){
var date = new Date(server_timestamp + get_delta());
date.setMinutes(town_offset + date.getTimezoneOffset())
print_date(date)
}
Андрей Сумин
Руководитель разработки клиентской части Mail.Ru, компания Mail.Ru Group
Егор Дыдыкин
Тимлид команды разработки главной страницы портала Mail.Ru, компания Mail.Ru Group
Автор: AndrewSumin