php - 不同时区的每小时日志 PHP 和 MySQL

标签 php mysql timezone

我希望通过我的 api 从不同时区向我的用户提供简单的日志,我有点迷茫,希望能得到一些帮助。

我有下表称为日志:

CREATE TABLE `logs` (
   `id` INT(11) NOT NULL AUTO_INCREMENT,
   `userId` int(11) NOT NULL,
   `ip` VARCHAR(45) NOT NULL,
   `timestamp` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
   PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

我有一个小时表来绑定(bind)我 24 小时内的查询。

CREATE TABLE `log_hours` (
   `id` INT(11) NOT NULL AUTO_INCREMENT,
   `hourId` int(11) NOT NULL,
   PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO log_hours
    (hourId)
VALUES
    (1),
    (2),
    (3),
    (4),
    (5),
    (6),
    (7),
    (8),
    (9),
    (10),
    (11),
    (12),
    (13),
    (14),
    (15),
    (16),
    (17),
    (18),
    (19),
    (20),
    (21),
    (22),
    (23),
    (24);

每次我获得 api 命中时,我都会存储日志并获取以下数据。

id | userId |   ip    | timestamp
1    1        0.0.0.0   2018-08-23 14:20:34
2    1        0.0.0.0   2018-08-23 14:20:34
3    1        0.0.0.0   2018-08-23 14:20:34
4    1        0.0.0.0   2018-08-23 14:20:34
5    1        0.0.0.0   2018-08-23 14:20:34

现在,如果我像下面这样运行我的查询。

SELECT DW.hourId AS hour, ifnull(t.hits,0) hits from log_hours DW left join (            
    SELECT COUNT( * ) AS hits, HOUR( logs.timestamp ) AS `hour` 
    FROM logs WHERE DAY( logs.timestamp ) = DAY(CURDATE()) 
    AND MONTH( logs.timestamp ) = MONTH(CURDATE()) 
    AND `userId` = 1 GROUP BY HOUR( logs.timestamp )) t on DW.hourId = t.hour 
    ORDER BY hour ASC

这工作正常,并给我这样的每个小时的日志。

enter image description here

现在我卡在时区上了,我的数据库时区设置为 BST。

例如,假设我有一个美国用户,如果他们在他们的时区访问 api,mysql 会自动将他们的时区转换为我的 BST 时区,以便输出数据有意义吗?

我应该使用 datetime NOT NULL DEFAULT CURRENT_TIMESTAMP 还是应该使用 INT 并使用 php time() 函数来插入记录?

我应该先通过 php 从我的时区返回数据,然后再转换为他们的数据吗?在这种情况下,最佳做法是什么?

编辑:

如果我在这里问愚蠢的问题但真的想完全理解这个过程,首先很抱歉。

我在什么时候检索用户的本地时区?我应该将它作为必需的参数添加到 API 中吗?

这是我的 PHP 代码,我只是将所有内容添加到一个函数中,以便更容易阅读我的过程是 MVC。

public function usage_get(){

        $userId = $this->get('userId'); // i am obviously not getting the users info this way this is just for the example

        // DO I MAKE THEM SEND THEIR TIMEZONE TO THE API AS A PARAM THEN USE IT IN MYSQL
        //https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_convert-tz?
        $timezone = $this->get('timezone');

        // DO I SOMEHOW RETRIEVE THE TIME ZONE BASE ON IP AND GET IT THAT WAY?

        $query = $this->db->query("SELECT DW.hourId AS hour, ifnull(t.hits,0) hits
        from log_hours DW 
        left join (

            SELECT COUNT( * ) AS hits, HOUR( logs.timestamp ) AS `hour`
            FROM logs
            WHERE DAY( logs.timestamp ) = DAY(CURDATE())
            AND MONTH( logs.timestamp ) = MONTH(CURDATE())
            AND `userId` = ".$this->db->escape_str($userId)."
            GROUP BY HOUR( logs.timestamp )

        ) t  on DW.hourId = t.hour ORDER BY hour ASC");

        // DO I RUN A PHP FUNCTION AFTER THE MYSQL BASED ON TIMEZONE?

        if($query->num_rows() > 0){

            $this->response([
                'status'  => TRUE,
                'message' => 'Success',
                'data'    => $query->result(),
            ], REST_Controller::HTTP_OK);


        }else{ 

            $this->response([
                'status' => FALSE,
                'message' => 'Error'
            ], REST_Controller::HTTP_OK);

        }

    }

最佳答案

保持简单永远是最好的主意。保存所有独立于本地时间的日期。在我看来,其他一切都是不好的做法,因为本地时间只会导致以后的困惑和问题。

假设我有一个美国用户,如果他们在他们的时区访问 api,mysql 会自动将他们的时区转换为我的 BST 时区以便输出数据有意义吗?

如果您想将日志时间作为本地时间进行转换。在数据库中,应始终存储 UTC(+/-0)。在 MySQL 中,您可以在查询期间使用 CONVERT_TZ 函数 ( https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_convert-tz )。

我应该使用 datetime NOT NULL DEFAULT CURRENT_TIMESTAMP 还是应该使用 INT 并使用 php time() 函数来插入记录?

CURRENT_TIMESTAMP 似乎是正确的方法,因为它是独立的 ( Should MySQL have its timezone set to UTC? )。我看不出有任何理由使用 PHP time() 函数,因为 CURRENT_TIMESTAMP 是最精确的,并且如果服务器时间设置正确则始终正确,但是基本上应该有除了 PHP 调用和实际数据库插入之间的毫秒数之外没有区别。

我是否应该先通过 php 从我的时区返回数据,然后将其转换为他们的数据?在这种情况下,最佳做法是什么?

在我看来,使用数据库进行转换是最好的(最快的)- 至少如果您可以编写自己的 SQL 查询。否则通过 PHP 的转换是完全合法的,但是有一些最小的开销。之前有人问过如何做到这一点:Convert UTC dates to local time in PHP

我在什么时候检索用户的本地时区?我应该将它作为必需的参数添加到 API 中吗?

这是一个应用程序架构的问题,没有“规则”。检索用户时区的可能性:

  1. GeoIP:使用 GeoIP 和基于位置的匹配将 IP 与区域匹配。与许多解决方案一样,这里的缺点是,如果他们使用 VPN 或代理,它将显示 VPN 或代理 IP 的区域,而不是其背后的用户物理 IP。

  2. JavaScript:Javascript 是客户端,虽然很像 GeoIP,但如果客户端位于 VPN 或代理之后,同样的问题仍然存在。您不会显示用户的时区,您将显示 VPN 或代理的时区 ( Getting the client's timezone in JavaScript )。

  3. 询问用户:时区以某种方式作为参数传递。

对于 API,我肯定会推荐后者 - 要求时区作为参数或简单地向它们传递时间 UTC (+-0)。也许正在使用您的 API 的用户有一个配置文件,他们可以在其中设置时区?

如果不考虑向他们传递一个结果,其中包含 UTC (+-0) 时间以及本地时间和猜测的时区简码。任何实现都是有效的,只要明确结果是针对哪个时区以及用户如何正确查询即可。

关于php - 不同时区的每小时日志 PHP 和 MySQL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51987448/

相关文章:

php - Magento错误: Can't retrieve entity config:

PHP session 在移动浏览器上过早销毁

带有屏幕和 Ts3Musicbot 的 PHP shell_exec

mysql - 如何从mysql中的字母数字字符串中提取数字部分?

mysql查询计数未返回所有数据

google-app-engine - Google Analytics API 使用哪个时区?

php - WooCommerce Wordpress 插件问题

mysql - 如何使用 ipv6 从 wordpress 连接到 mysql

c++ - boost:从机器获取带有当前时区的当前 local_date_time

Java GregorianCalendar 更改时区