[aCR]RASSVET
07.10.2009, 20:49
Здравствуйте. Здесь и сейчас я расскажу об автоматическом определении часового пояса в ваших WEB-приложениях. :-)
Обычно, сайты и форумы показывают Вам время в том часовом поясе, в котором расположен сервер с просматриваемым Вами сайтом. Реже - предлагают ручной выбор часового пояса. Сейчас же мы рассмотрим уникальный метод автоматического определения часового пояса, что позволит нам показать пользователю время в том часовом поясе, в котором он находится.
В книге PHP 5 (серия «В подлиннике») издательства «БХВ-Петербург» Дмитрия Котерова и Алексея Костарева авторы пишут:
Можно ли автоматически определить часовой пояс пользователя, который запустил скрипт из браузера? К сожалению, нет: а протоколе HTTP не существует заголовков запроса, предназначенных для передачи этой информации. Остаётся единственный метод — запросить зону у пользователя явно (например, при регистрации) и сохранить её где-нибудь для дальнейшего использования.
Протокол HTTP действительно не расчитан на передачу часового пояса или времени пользователя браузером на сервер. Но авторы не правы.
Наш метод будет заключаться в том, что мы не будем определять часовой пояс напрямую.
Допустим, пользователи могут в нашей системе оставлять комментарии.
При сохранении времени комментария - мы сохраняем текущее время сервера в качестве времени комментария.
Алгоритм отображения времени следующий:
1. Вычислить разницу между текущим временем сервера и временем комментария
2. Передать разницу JS-скрипту
3. С помощью JavaScript'а вычитаем разницу из текущего времени пользователя
4. Выводим время в нужном формате
На практике нам пригодятся несколько функций.
PHP-функция преобразования даты и времени из формата MySQL DATE или DATETIME в количество секунд, прошедших с начала эпохи UNIX до заданной даты:
function dataAndTime($text) {
$text = (string)$text;
$dt = explode(" ", $text);
$d = explode("-", @$dt[0]);
$t = explode(":", @$dt[1]);
if (count($t) != 3) $t = array(12, 0, 0);
if (count($d) != 3) {
trigger_error("dataAndTime error");
return -1;
}
if ($d[0] < 1900) return -1;
return (int)mktime($t[0], $t[1], $t[2], $d[1], $d[2], $d[0]);
}
PHP-функция вывода времени (можно также использовать в качестве Smarty-модификатора):
function writeTime($time, $format) {
$time1 = dataAndTime($time);
$time2 = time() - $time1;
return '<noscript>'.gmdate(preg_replace("#\{([a-zA-Z])\}#uis", "$1", $format), $time1).' [GMT]</noscript><script type="text/javascript">writeTime('.$time2.', "'.$format.'");</script>';
}
Таким образом, если Вы получите из MySQL время вида "2009-10-07 19:20:12" и отправите его в php-функцию writeTime, то эта функция сгенерирует следующий HTML-код:
<noscript>7 October 2009, 15:20 [GMT]</noscript><script type="text/javascript">writeTime(323, "{j} {F} {Y}, {H}:{i}");</script>
Здесь "{j} {F} {Y}, {H}:{i}" — формат вывода времени (второй параметр php-функции writeTime). Об этом чуть позже.
Если у человека выключены JS (что очень маловероятно) — он увидит время по Гринвичу.
Если JS включены - будет вызвана js-функция отображения времени writeTime. Вот её код:
function writeTime(time, format) {
document.write(phpDate(format, time));
}
Эта функция вызывает js-функцию форматирования даты, аналогичной php-функции date (только параметры замены передаются в фигурных скобках):
// функция-аналог PHP-функции date
function phpDate (text, start_time) {
// языковые настройки
var LANG = new Array();
LANG['tm'] = new Array('', 'января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря');
LANG['stm'] = new Array('', 'янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек');
LANG['td'] = new Array('', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', 'Воскресенье');
LANG['std'] = new Array('', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс');
// работаем
text = " " + text + " ";
var firstdate = new Date();
var user_time = Math.floor(firstdate.getTime() / 1000);
var date = new Date((user_time - start_time) * 1000);
var year = date.getFullYear();
text = text.replace(/{Y}/g, year); // год числом, 4 цифры
text = text.replace(/{y}/g, year.toString().substr(2,2)); // год числом, 2 цифры
if ((year/4) == Math.round(year/4)) {
text = text.replace(/{L}/g, "1"); // високосный год
} else {
text = text.replace(/{L}/g, "0"); // невисокосный год
}
var month = date.getMonth() + 1;
text = text.replace(/{n}/g, month); // месяц числом, 1-2 цифры
var monthn = (month < 10 ? '0' + month : month);
text = text.replace(/{m}/g, monthn); // месяц числом, 2 цифры
var textmonth = LANG['tm'][month];
var shorttextmonth = LANG['stm'][month];
var mnthct, startday;
switch (month) {
case 1: mnthct = 31; startday = 0; break;
case 2: mnthct = ((year/4) == Math.round(year/4) ? 29 : 28); startday = 31; break;
case 3: mnthct = 31; startday = ((year/4) == Math.round(year/4) ? 60 : 59); break;
case 4: mnthct = 30; startday = ((year/4) == Math.round(year/4) ? 91 : 90); break;
case 5: mnthct = 31; startday = ((year/4) == Math.round(year/4) ? 121 : 120); break;
case 6: mnthct = 30; startday = ((year/4) == Math.round(year/4) ? 152 : 151); break;
case 7: mnthct = 31; startday = ((year/4) == Math.round(year/4) ? 182 : 181); break;
case 8: mnthct = 31; startday = ((year/4) == Math.round(year/4) ? 213 : 212); break;
case 9: mnthct = 30; startday = ((year/4) == Math.round(year/4) ? 234 : 233); break;
case 10: mnthct = 31; startday = ((year/4) == Math.round(year/4) ? 264 : 263); break;
case 11: mnthct = 30; startday = ((year/4) == Math.round(year/4) ? 295 : 294); break;
case 12: mnthct = 31; startday = ((year/4) == Math.round(year/4) ? 335 : 334); break;
default: return false;
}
text = text.replace(/{F}/g, textmonth); // месяц прописью, полное название
text = text.replace(/{M}/g, shorttextmonth); // месяц прописью, короткое название
text = text.replace(/{t}/g, mnthct); // количество дней в месяце
var number = date.getDate();
text = text.replace(/{j}/g, number); // число числом, 1-2 цифры
var numbern = (number < 10 ? '0' + number : number);
text = text.replace(/{d}/g, numbern); // число числом, 2 цифры
var suffday = '';
suffday = get_suffday(number);
text = text.replace(/{S}/g, suffday); // суффикс числа
var nday = startday + number;
text = text.replace(/{z}/g, nday); // номер дня в году числом
var nweek = Math.ceil(nday/7);
text = text.replace(/{W}/g, nweek); // номер недели в году числом
var day = date.getDay();
if (day == 0) day = 7;
text = text.replace(/{w}/g, day); // день недели числом
var textday = LANG['td'][day];
var shorttextday = LANG['std'][day];
text = text.replace(/{l}/g, textday); // день недели прописью, полное название
text = text.replace(/{D}/g, shorttextday); // день недели прописью, короткое название
var hours24 = date.getHours();
var hours24n = (hours24 < 10 ? '0' + hours24 : hours24);
var hours12 = (hours24 > 12 ? hours24 - 12 : hours24);
var hours12n = (hours12 < 10 ? '0' + hours12 : hours12);
text = text.replace(/{g}/g, hours12); // часы числом, 1-2 цифры, 12-часовой формат
text = text.replace(/{G}/g, hours24); // часы числом, 1-2 цифры, 24-часовой формат
text = text.replace(/{h}/g, hours12n); // часы числом, 2 цифры, 12-часовой формат
text = text.replace(/{H}/g, hours24n); // часы числом, 2 цифры, 24-часовой формат
var minutes = date.getMinutes();
var minutesn = (minutes < 10 ? '0' + minutes : minutes);
text = text.replace(/{i}/g, minutesn); // минуты числом, 2 цифры
var seconds = date.getSeconds();
var secondsn = (seconds < 10 ? '0' + seconds : seconds);
text = text.replace(/{s}/g, secondsn); // секунды числом, 2 цифры
if (hours24 > 12) {
text = text.replace(/{a}/g, "pm");
text = text.replace(/{A}/g, "PM");
} else {
text = text.replace(/{a}/g, "am");
text = text.replace(/{A}/g, "AM");
}
return text;
}
Если наш формат — "{j} {F} {Y}, {H}:{i}", в браузере появится следующее:
7 октября 2009, 19:20
Если на компьютере изменить настройки времени, то изменится и время на сайте.
Авторы — Figaroo & Bloodthrist.
Обычно, сайты и форумы показывают Вам время в том часовом поясе, в котором расположен сервер с просматриваемым Вами сайтом. Реже - предлагают ручной выбор часового пояса. Сейчас же мы рассмотрим уникальный метод автоматического определения часового пояса, что позволит нам показать пользователю время в том часовом поясе, в котором он находится.
В книге PHP 5 (серия «В подлиннике») издательства «БХВ-Петербург» Дмитрия Котерова и Алексея Костарева авторы пишут:
Можно ли автоматически определить часовой пояс пользователя, который запустил скрипт из браузера? К сожалению, нет: а протоколе HTTP не существует заголовков запроса, предназначенных для передачи этой информации. Остаётся единственный метод — запросить зону у пользователя явно (например, при регистрации) и сохранить её где-нибудь для дальнейшего использования.
Протокол HTTP действительно не расчитан на передачу часового пояса или времени пользователя браузером на сервер. Но авторы не правы.
Наш метод будет заключаться в том, что мы не будем определять часовой пояс напрямую.
Допустим, пользователи могут в нашей системе оставлять комментарии.
При сохранении времени комментария - мы сохраняем текущее время сервера в качестве времени комментария.
Алгоритм отображения времени следующий:
1. Вычислить разницу между текущим временем сервера и временем комментария
2. Передать разницу JS-скрипту
3. С помощью JavaScript'а вычитаем разницу из текущего времени пользователя
4. Выводим время в нужном формате
На практике нам пригодятся несколько функций.
PHP-функция преобразования даты и времени из формата MySQL DATE или DATETIME в количество секунд, прошедших с начала эпохи UNIX до заданной даты:
function dataAndTime($text) {
$text = (string)$text;
$dt = explode(" ", $text);
$d = explode("-", @$dt[0]);
$t = explode(":", @$dt[1]);
if (count($t) != 3) $t = array(12, 0, 0);
if (count($d) != 3) {
trigger_error("dataAndTime error");
return -1;
}
if ($d[0] < 1900) return -1;
return (int)mktime($t[0], $t[1], $t[2], $d[1], $d[2], $d[0]);
}
PHP-функция вывода времени (можно также использовать в качестве Smarty-модификатора):
function writeTime($time, $format) {
$time1 = dataAndTime($time);
$time2 = time() - $time1;
return '<noscript>'.gmdate(preg_replace("#\{([a-zA-Z])\}#uis", "$1", $format), $time1).' [GMT]</noscript><script type="text/javascript">writeTime('.$time2.', "'.$format.'");</script>';
}
Таким образом, если Вы получите из MySQL время вида "2009-10-07 19:20:12" и отправите его в php-функцию writeTime, то эта функция сгенерирует следующий HTML-код:
<noscript>7 October 2009, 15:20 [GMT]</noscript><script type="text/javascript">writeTime(323, "{j} {F} {Y}, {H}:{i}");</script>
Здесь "{j} {F} {Y}, {H}:{i}" — формат вывода времени (второй параметр php-функции writeTime). Об этом чуть позже.
Если у человека выключены JS (что очень маловероятно) — он увидит время по Гринвичу.
Если JS включены - будет вызвана js-функция отображения времени writeTime. Вот её код:
function writeTime(time, format) {
document.write(phpDate(format, time));
}
Эта функция вызывает js-функцию форматирования даты, аналогичной php-функции date (только параметры замены передаются в фигурных скобках):
// функция-аналог PHP-функции date
function phpDate (text, start_time) {
// языковые настройки
var LANG = new Array();
LANG['tm'] = new Array('', 'января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря');
LANG['stm'] = new Array('', 'янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек');
LANG['td'] = new Array('', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', 'Воскресенье');
LANG['std'] = new Array('', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс');
// работаем
text = " " + text + " ";
var firstdate = new Date();
var user_time = Math.floor(firstdate.getTime() / 1000);
var date = new Date((user_time - start_time) * 1000);
var year = date.getFullYear();
text = text.replace(/{Y}/g, year); // год числом, 4 цифры
text = text.replace(/{y}/g, year.toString().substr(2,2)); // год числом, 2 цифры
if ((year/4) == Math.round(year/4)) {
text = text.replace(/{L}/g, "1"); // високосный год
} else {
text = text.replace(/{L}/g, "0"); // невисокосный год
}
var month = date.getMonth() + 1;
text = text.replace(/{n}/g, month); // месяц числом, 1-2 цифры
var monthn = (month < 10 ? '0' + month : month);
text = text.replace(/{m}/g, monthn); // месяц числом, 2 цифры
var textmonth = LANG['tm'][month];
var shorttextmonth = LANG['stm'][month];
var mnthct, startday;
switch (month) {
case 1: mnthct = 31; startday = 0; break;
case 2: mnthct = ((year/4) == Math.round(year/4) ? 29 : 28); startday = 31; break;
case 3: mnthct = 31; startday = ((year/4) == Math.round(year/4) ? 60 : 59); break;
case 4: mnthct = 30; startday = ((year/4) == Math.round(year/4) ? 91 : 90); break;
case 5: mnthct = 31; startday = ((year/4) == Math.round(year/4) ? 121 : 120); break;
case 6: mnthct = 30; startday = ((year/4) == Math.round(year/4) ? 152 : 151); break;
case 7: mnthct = 31; startday = ((year/4) == Math.round(year/4) ? 182 : 181); break;
case 8: mnthct = 31; startday = ((year/4) == Math.round(year/4) ? 213 : 212); break;
case 9: mnthct = 30; startday = ((year/4) == Math.round(year/4) ? 234 : 233); break;
case 10: mnthct = 31; startday = ((year/4) == Math.round(year/4) ? 264 : 263); break;
case 11: mnthct = 30; startday = ((year/4) == Math.round(year/4) ? 295 : 294); break;
case 12: mnthct = 31; startday = ((year/4) == Math.round(year/4) ? 335 : 334); break;
default: return false;
}
text = text.replace(/{F}/g, textmonth); // месяц прописью, полное название
text = text.replace(/{M}/g, shorttextmonth); // месяц прописью, короткое название
text = text.replace(/{t}/g, mnthct); // количество дней в месяце
var number = date.getDate();
text = text.replace(/{j}/g, number); // число числом, 1-2 цифры
var numbern = (number < 10 ? '0' + number : number);
text = text.replace(/{d}/g, numbern); // число числом, 2 цифры
var suffday = '';
suffday = get_suffday(number);
text = text.replace(/{S}/g, suffday); // суффикс числа
var nday = startday + number;
text = text.replace(/{z}/g, nday); // номер дня в году числом
var nweek = Math.ceil(nday/7);
text = text.replace(/{W}/g, nweek); // номер недели в году числом
var day = date.getDay();
if (day == 0) day = 7;
text = text.replace(/{w}/g, day); // день недели числом
var textday = LANG['td'][day];
var shorttextday = LANG['std'][day];
text = text.replace(/{l}/g, textday); // день недели прописью, полное название
text = text.replace(/{D}/g, shorttextday); // день недели прописью, короткое название
var hours24 = date.getHours();
var hours24n = (hours24 < 10 ? '0' + hours24 : hours24);
var hours12 = (hours24 > 12 ? hours24 - 12 : hours24);
var hours12n = (hours12 < 10 ? '0' + hours12 : hours12);
text = text.replace(/{g}/g, hours12); // часы числом, 1-2 цифры, 12-часовой формат
text = text.replace(/{G}/g, hours24); // часы числом, 1-2 цифры, 24-часовой формат
text = text.replace(/{h}/g, hours12n); // часы числом, 2 цифры, 12-часовой формат
text = text.replace(/{H}/g, hours24n); // часы числом, 2 цифры, 24-часовой формат
var minutes = date.getMinutes();
var minutesn = (minutes < 10 ? '0' + minutes : minutes);
text = text.replace(/{i}/g, minutesn); // минуты числом, 2 цифры
var seconds = date.getSeconds();
var secondsn = (seconds < 10 ? '0' + seconds : seconds);
text = text.replace(/{s}/g, secondsn); // секунды числом, 2 цифры
if (hours24 > 12) {
text = text.replace(/{a}/g, "pm");
text = text.replace(/{A}/g, "PM");
} else {
text = text.replace(/{a}/g, "am");
text = text.replace(/{A}/g, "AM");
}
return text;
}
Если наш формат — "{j} {F} {Y}, {H}:{i}", в браузере появится следующее:
7 октября 2009, 19:20
Если на компьютере изменить настройки времени, то изменится и время на сайте.
Авторы — Figaroo & Bloodthrist.