$cache[$key] = empty($arr) ? NULL : $arr; return $cache[$key]; } // 门户 获取需要在频道显示的栏目主题数据 function portal_channel_thread($fid) { global $forumlist; if (empty($fid)) return NULL; $orderby = array('tid' => 1); $page = 1; // 遍历所有在频道显示内容的栏目 $category_forumlist = channel_category($fid); $arrlist = array(); $forum_tids = array(); $tidlist = array(); if ($category_forumlist) { foreach ($category_forumlist as &$_forum) { // 频道显示数据 $arrlist['list'][$_forum['fid']] = array( 'fid' => $_forum['fid'], 'name' => $_forum['name'], 'rank' => $_forum['rank'], 'type' => $_forum['type'], 'url' => $_forum['url'], 'channel_new' => $_forum['channel_new'], ); $forum_thread = thread_tid__find(array('fid' => $_forum['fid']), $orderby, $page, $_forum['channel_new'], 'tid', array('tid')); // 最新信息按栏目分组 foreach ($forum_thread as $key => $_thread) { $forum_tids[$key] = $_thread; } unset($forum_thread); } $tidlist += $forum_tids; } unset($category_forumlist); // 获取属性对应的tid集合 list($flaglist, $flagtids) = flag_thread_by_fid($fid); empty($flagtids) || $tidlist += $flagtids; unset($flagtids); // 频道置顶 $stickylist = sticky_list_thread($fid); empty($stickylist) || $tidlist += $stickylist; // 在这之前合并所有二维数组 tid值为键/array('tid值' => tid值) $tidarr = arrlist_values($tidlist, 'tid'); // 在这之前使用$tidarr = array_merge($tidarr, $arr)前合并所有一维数组 tid/array(1,2,3) if (empty($tidarr)) { $arrlist['list'] = isset($arrlist['list']) ? array_multisort_key($arrlist['list'], 'rank', FALSE, 'fid') : array(); return $arrlist; } $tidarr = array_unique($tidarr); $pagesize = count($tidarr); // 遍历获取的所有tid主题 $threadlist = well_thread_find_asc($tidarr, $pagesize); // 遍历时为升序,翻转为降序 $threadlist = array_reverse($threadlist); foreach ($threadlist as &$_thread) { // 各栏目最新内容 isset($forum_tids[$_thread['tid']]) AND $arrlist['list'][$_thread['fid']]['news'][$_thread['tid']] = $_thread; // 全站置顶内容 isset($stickylist[$_thread['tid']]) AND $arrlist['sticky'][$_thread['tid']] = $_thread; // 首页属性主题 if (!empty($flaglist)) { foreach ($flaglist as $key => $val) { if (isset($val['tids']) && in_array($_thread['tid'], $val['tids'])) { $arrlist['flaglist'][$key][array_search($_thread['tid'], $val['tids'])] = $_thread; ksort($arrlist['flaglist'][$key]); $arrlist['flag'][$_thread['tid']] = $_thread; } } } } unset($threadlist); if (isset($arrlist['sticky'])) { $i = 0; foreach ($arrlist['sticky'] as &$val) { ++$i; $val['i'] = $i; } } if (isset($arrlist['flag'])) { $i = 0; foreach ($arrlist['flag'] as &$val) { ++$i; $val['i'] = $i; } } if (isset($arrlist['flaglist'])) { foreach ($arrlist['flaglist'] as &$val) { $i = 0; foreach ($val as &$v) { ++$i; $v['i'] = $i; } } } isset($arrlist['list']) AND $arrlist['list'] = array_multisort_key($arrlist['list'], 'rank', FALSE, 'fid'); return $arrlist; } ?>php - How to deal with timezones between server and client? - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

php - How to deal with timezones between server and client? - Stack Overflow

programmeradmin0浏览0评论

I'm developing a website where I have to deal with different possible timezones from the users. This becomes a great problem since the website hosts time-delicate events like auctions.

All dates/times on the server are in UTC. Database stores everything in UTC timestamps. PHP default timezone is set to UTC too (date_default_timezone_set('UTC');).

Now, my problem is how I should interact with the users, whether I'm only showing a date or, more important, I'm reading a date/time from user input.

A concrete example:

  • An auction has a deadline, which I store in database as UTC.
  • When I view the auction on the website, a javascript timer uses a Date object to calculate the remaining time. It automatically converts the timezone to GMT+0100 (my local timezone). So if the deadline is '2013-08-08 10:46:08' (UTC), the javascript date object will return Aug 08 2013 11:26:15 GMT+0100 (GMT Standard Time).
  • If the current time is greater than 11:46:08 then the timer says that the remaining time is 00:00 (which is correct).
  • But if I try to insert a bid, the server accepts since the condition on the MySQL INSERT evaluates to true:

    INSERT INTO Bids ... WHERE ... AND auction_deadline > NOW() ...

( because auction_deadline = '2013-08-08 10:46:08' and NOW() = '2013-08-08 10:26:50')

All this mumbo jumbo of timezone melts my brains. What am I missing here? I'm almost certain that storing all dates/times in UTC inside the database is the best. I just can't think crystal clear how do deal with it between the user and the database.

I'm developing a website where I have to deal with different possible timezones from the users. This becomes a great problem since the website hosts time-delicate events like auctions.

All dates/times on the server are in UTC. Database stores everything in UTC timestamps. PHP default timezone is set to UTC too (date_default_timezone_set('UTC');).

Now, my problem is how I should interact with the users, whether I'm only showing a date or, more important, I'm reading a date/time from user input.

A concrete example:

  • An auction has a deadline, which I store in database as UTC.
  • When I view the auction on the website, a javascript timer uses a Date object to calculate the remaining time. It automatically converts the timezone to GMT+0100 (my local timezone). So if the deadline is '2013-08-08 10:46:08' (UTC), the javascript date object will return Aug 08 2013 11:26:15 GMT+0100 (GMT Standard Time).
  • If the current time is greater than 11:46:08 then the timer says that the remaining time is 00:00 (which is correct).
  • But if I try to insert a bid, the server accepts since the condition on the MySQL INSERT evaluates to true:

    INSERT INTO Bids ... WHERE ... AND auction_deadline > NOW() ...

( because auction_deadline = '2013-08-08 10:46:08' and NOW() = '2013-08-08 10:26:50')

All this mumbo jumbo of timezone melts my brains. What am I missing here? I'm almost certain that storing all dates/times in UTC inside the database is the best. I just can't think crystal clear how do deal with it between the user and the database.

Share Improve this question asked Aug 8, 2013 at 11:07 Renato RodriguesRenato Rodrigues 1,0382 gold badges20 silver badges37 bronze badges 1
  • If you need some code to clarify my question, say it please. – Renato Rodrigues Commented Aug 8, 2013 at 11:08
Add a comment  | 

6 Answers 6

Reset to default 3

Your problem doesn't involve timezones at all, just the fact that clients can turn their clocks or have their clock skewed considerably. For that the fix is to poll the server every once in a while for an offset fix to use in calculations.

In fact, you don't even need date objects. There is a certain universal instant in time when the auction ends. Let's say it is 1375960662823. Right now, the universal instant in time is 1375960669199, so from that we see that the auction ends in 6 seconds (1375960662823 - 1375960669199 ~ 6000 ). It will end in 6 seconds regardless if I am in Morocco or Japan. Do you understand it yet?

To generate these numbers, on the client side you can call var now = Date.now() + skewFix where skewFix is the correction that needs to applied in case client has time skew or manually set their computer to wrong time.

In PHP, you can generate it with $now = time() * 1000;

This is rather a typical subject yet very complex for most to understand. First thing, you never mention the DAYLIGHT SAVING. yeah I am increasing your tension :).

Now let us see how we can do this. You did a good job by saving the Time in UTC. Now, I hope you have registered members and that each member has ability to set their preferred timezone, otherwise you will show Server' timezone based time to them.

When you through "start time" to user you must send them after converting UTC time to their time, similarly when you accept TIME from browser be it user action or javascript you need to convert that time to UTC considering the fact that user is that time zone that he select for his profile.

Hope that clear the idea on where you are going wrong? Please read through day light saving as that will play an important role too when you move ahead with other logic on same.

EDIT:

You can use javascript's Timezone offset, for auto submission and user input based on his settings.

Date in JavaScript uses local timezone. You should get UTC time for the user and send it to the server

new Date
Thu Aug 08 2013 17:00:14 GMT+0530 (India Standard Time)
(new Date("Thu Aug 08 2013 17:00:14")).toUTCString();
"Thu, 08 Aug 2013 11:30:14 GMT"

This will resolve the timezone issue between the server and client.

You said

( because auction_deadline = '2013-08-08 10:46:08' and NOW() = '2013-08-08 10:26:50')

In MySQL - NOW returns the current time in the server's local time zone (docs).

You probably want something like UTC_TIMESTAMP which returns the current time in UTC (docs).

Also - you probably shouldn't accept any input time from the client JavaScript at all. Only trust your own clock. When a bid is placed, use the time on your server in MySQL or in PHP. Don't accept it as input.

You can do the following

once page is loaded, send an ajax request to server with timezone offset of user. You can get timezone offset using the following code.

var curdate = new Date()
var offset = curdate.getTimezoneOffset()

offset is timezone offset in minute.

I think it will help.

everytime when you get the date from the clientside, you can use the getUTC to convert to UTC date ie:

var todayDate = new Date(); 

var todayDateInUTC = new Date(todayDate.getUTCFullYear(), todayDate.getUTCMonth(), todayDate.getUTCDate(),  todayDate.getUTCHours(), todayDate.getUTCMinutes(), todayDate.getUTCSeconds());

so right before you insert the bid date to database, use the getUTC functions to convert it into UTC format.

发布评论

评论列表(0)

  1. 暂无评论