1 (16.09.2010 03:48 отредактировано Dexus)

Тема: Часовой пояс сервера/клиента и летнее время

Приветствую всех!

Сабж - это вообще довольно-таки больной вопрос для очень многих форумных движков. В punbb, начиная с 1.2 это так поныне и осталось в todo и частично криво сделано. Все запросы по этой теме остаётся без реальных ответов.

Одно из самых "оптимальных" решений на мой взгляд осуществлено в форуме ixbt. Там всё просто - используется javascript-форматирование временнОй отметки в формате UNIXTIME. Таким образом, всеми часовыми поясами и летним временем занимается сам браузер, и даже указывать где-то свой часовой пояс нет необходимости - браузер сам знает какой часовой пояс установлен в операционке, и как нужно корректировать GMT время.

План модификаций приблизительно таков:
1. Серверное время (o_server_timezone) в норме всегда должно быть 0 (если сервер сконфигурирован нормально) - временные отметки должны сохраняться в таблицах в нормированном виде для GMT+00;
2. Функция date() в include/functions.php/format_time() должна быть заменена на dategm();
3. По-идее нужно сделать альтернативную функцию format_time(), которая бы возвращала временную отметку в формате <noscript>%default_timestamp%</noscript><script>pun_time(%UNIXTIME%);</script>
Включить в каждую нужную страницу файл с джава-скриптом:

function date(fmt,ts){// http://kevin.vanzonneveld.net
var jd=new Date(ts*1e3),f,fC=/\\?([a-z])/gi,
tw=["Sun","Mon","Tues","Wednes","Thurs","Fri","Satur"],
to=["January","February","March","April","May","June","July","August","September","October","November","December"],
fCC=function(t,s){return f[t]?f[t]():s;};
_p=function(n,c){if((n=n+"").length<c){return new Array((c+1)-n.length).join("0")+n;}else return n;};
f={
d:function(){return _p(jd.getDate(),2);},
D:function(){return tw[jd.getDay()].slice(0,3);},
j:function(){return jd.getDate();},
l:function(){return tw[jd.getDay()]+'day';},
N:function(){return jd.getDay()||7;},
S:function(){var t={1:"st",2:"nd",3:"rd",21:"st",22:"nd",23:"rd",31:"st"};return t[jd.getDate()]||'th';},
w:function(){return jd.getDay();},
z:function(){var a=new Date(jd.getFullYear(),jd.getMonth(),jd.getDate()),b=new Date(jd.getFullYear(),0,1);return Math.round((a-b)/864e5);},
W:function(){var a=new Date(jd.getFullYear(),jd.getMonth(),jd.getDate()-(jd.getDay()||7)+3),b=new Date(a.getFullYear(),0,4);return 1+Math.round((a-b)/6048e5);},
F:function(){return to[jd.getMonth()];},
m:function(){return _p(jd.getMonth()+1,2);},
M:function(){return to[jd.getMonth()].slice(0,3);},
n:function(){return jd.getMonth()+1;},
t:function(){return (new Date(jd.getFullYear(),jd.getMonth()+1,0)).getDate();},
L:function(){var y=jd.getFullYear(),a=y&3,b=y%400,c=y%100;return 0+(!a &&(c||!b));},
o:function(){var n=jd.getMonth()+1,W=f.W();return jd.getFullYear()+(n===12&&W<9?-1:n===1&&W>9);},
Y:function(){return jd.getFullYear();},
y:function(){return (jd.getFullYear()+"").slice(-2);},
a:function(){return jd.getHours()>11?"pm":"am";},
A:function(){return jd.getHours()>11?"PM":"AM";},
B:function(){return _p(Math.floor(((jd.getUTCHours()+1)*3600+jd.getUTCMinutes()*60+jd.getUTCSeconds())/86.4)%1e3,3);},
g:function(){return jd.getHours()%12||12;},
G:function(){return jd.getHours();},
h:function(){return _p(jd.getHours()%12||12,2);},
H:function(){return _p(jd.getHours(),2);},
i:function(){return _p(jd.getMinutes(),2);},
s:function(){return _p(jd.getSeconds(),2);},
u:function(){return _p(jd.getMilliseconds()*1e3,6);},
e:function(){return 'Not supported';},
I:function(){var Y=jd.getFullYear(),a=new Date(Y,0),c=Date.UTC(Y,0),b=new Date(Y,6),d=Date.UTC(Y,6);return 0+((a-c)!==(b-d));},
O:function(){var a=jd.getTimezoneOffset();return(a>0?"-":"+")+_p(Math.abs(a/60*100),4);},
P:function(){var O=f.O();return (O.substr(0,3)+":"+O.substr(3,2));},
T:function(){return 'UTC';},
Z:function(){return -jd.getTimezoneOffset()*60;},
c:function(){return 'Y-m-d\\TH:i:sP'.replace(fC,fCC);},
r:function(){return 'D, d M Y H:i:s O'.replace(fC,fCC);},
U:function(){return jd.getTime()/1e3|0;}
};return fmt.replace(fC,fCC);}
function pun_time(t){
d_=date(d_m,t);
if(d_==d0)d_=dn0;else if(d_==d1)d_=dn1;else if(d_==d2)d_=dn2;
return d_+' '+date(d_t,t);
}

А также в хедере инициализировать необходимые переменные (языковые и временнЫе).

<script type="text/javascript">
<!-- //<![CDATA[
var d_m="<?php echo $pun_config['o_date_format']; ?>",
d_t="<?php echo $pun_config['o_time_format']; ?>",
dn0='<?php echo $lang_common['Today'] ?>',
dn1='<?php echo $lang_common['Yesterday'] ?>',
dn2='<?php echo $lang_common['Yesterday2']; ?>';
var now=<?php echo time();?>;
//]]> -->
</script>

Аналог PHP'шного date() взял с http hmm/phpjs.org/functions/date:380 , сделав несколько исправлений и "развернув" бОльшую часть алиасов (это я сделал с целью вставлять весь этот скрипт в хедер страницы, но только с теми буквами, которые нужны при текущей конфигурации 'o_date_format' и 'o_time_format' - по дефолту там будут лишь 6 строк для Y,m,d,H,i,s).

Таким образом это будет работать и без javascript и с javascript, при этом во втором случае время будет локальным за счёт браузера _всегда_. В своей "сборке" я это пока еще не сделал, но нахожусь на пути к этому.

ЗЫ: Что за чертовщина тут происходят? Почему все ссылки (в том числе и очень короткие) превращаются в какую-то трёхэтажную абракадабру? Даже [ url=][/url ] толком не работает.

Поделиться

2 (16.09.2010 04:01 отредактировано Dexus)

Re: Часовой пояс сервера/клиента и летнее время

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

ЗЫ: В этом форуме, кстати, время отображается криво (без учёта летнего). Вот я это запостил в 17:45 а у меня показывает 16:45.

Поделиться

3

Re: Часовой пояс сервера/клиента и летнее время

Давай ссылку на свой форум для подглядывания wink

Моя сборка FluxBB 1.4

Сайт Visman

Поделиться

4 (16.09.2010 07:57 отредактировано Dexus)

Re: Часовой пояс сервера/клиента и летнее время

volutar.no-ip.org/forum
джаваскрипт пока что внешний, поэтому в общем-то избыточен.
В идеале думаю должен генериться /cache/cache_time.php который будет инклудиться из хедера, и в котором бы "компилились" только нужные java строчки.

ЗЫ: Я еще целиком нахожусь в 1.2 версии, и заметил что в 1.3 каждый пользователь в профиле может задавать формат времени, только из списка предзаданных. Этот список редактируем, можно ли добавить допустим часовой пояс в эту текстовку?

Поделиться

5 (17.09.2010 06:52 отредактировано Dexus)

Re: Часовой пояс сервера/клиента и летнее время

Обнаружилось, что тэг <noscript> нельзя помещать внутри параграфов - яко бы этот тэг - блочный элемент, в отличие от того же <script> (sic!). Казалось бы - элементы одинаковой природы и синтаксиса, но...
Короче было решено слегка переделать механизм коррекции дат.

Текст который возвращает новый time_format() <span id="ts" title="%UNIXTIME%">%PRERENDERED_TIME%</span>
В конце страницы воткнуть небольшой скрипт:

<script>
var tls=document.getElementsByTagName('span');
for(i=0;i<tls.length;++i)if(tls[i].id=='ts')tls[i].innerHTML=pun_ts(tls[i].title);
</script>

Который банально пробегается по всем элементам страницы и меняет время на "откорректированное". Если по какой-то причине он не сможет исполниться (отключен javascript или еще что), то внутренности этих тегов останутся дефолтовыми.

Добавлено спустя 45 минут 3 секунды:

В данном случае при загрузке страницы с огромным количеством дат браузер будет какое-то тормозить после загрузки пока не отпроцессит их.
Альтернативный вариант №2:
Текст который возвращает новый time_format() <span id="ts">%PRERENDERED_TIME%</span><script>pun_ts(%UNIXTIME%)</script>

function pun_ts(t){d_=date(d_m,t);
if(d_==d0)d_=dn0;else if(d_==d1)d_=dn1;else if(d_==d2)d_=dn2;
document.write(d_+' '+date(d_t,t))
tls=document.getElementById('ts');
if(tls){tls.innerText='';tls.id='ts_old'}}

Т.е. вставляется откорректированная дата и обнуляется предыдущий тэг <span id="ts"> вместе со всем содержимым. При этом загрузка страницы происходит "плавно" и подмена происходит "на лету".

Собственно этот вариант и был успешно использован.

Поделиться

6

Re: Часовой пояс сервера/клиента и летнее время

Кстати эта система великолепно работает и для гостей (посетителей без профиля). А как в этом форуме? И в других? Не знаете?

Поделиться