Php 不同时区的每小时日志;MySQL

Php 不同时区的每小时日志;MySQL,php,mysql,timezone,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, PRIM

我正在寻找通过我的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;
我有一个小时表,可以在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
这很好,给了我每小时的日志,就像这样

现在我被困在时区上,我的数据库时区设置为BST

比如说,我在美国有一个用户,如果他们在他们的时区中点击了api,mysql会自动将他们的时区转换为我的BST时区,这样输出数据才有意义吗

我应该使用datetime NOT NULL默认当前时间戳,还是应该使用INT并使用php time()函数插入记录

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

编辑:

SELECT CONVERT_TZ('2004-01-01 12:00:00','GMT','MET');
date_default_timezone_set('America/Los_Angeles');
./mysql_tzinfo_to_sql /usr/share/zoneinfo | ./mysql -uroot -proot mysql
CONVERT_TZ(NOW(), @@session.time_zone, 'America/Los_Angeles')
2018-08-24 02:07:36

CONVERT_TZ(NOW(), @@session.time_zone, 'Indian/Antananarivo')
2018-08-24 12:07:36

CONVERT_TZ(NOW(), @@session.time_zone, 'Asia/Dhaka')
2018-08-24 15:07:36

CONVERT_TZ(NOW(), @@session.time_zone, 'Antarctica/Troll')
2018-08-24 11:07:36
首先,如果我在这里问了一些愚蠢的问题,但我真的很想完全理解这个过程,我很抱歉

在什么时候检索用户的本地时区?我应该将其作为必需参数添加到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
函数()

我应该使用datetime NOT NULL默认当前时间戳,还是应该使用INT并使用php time()函数插入记录

CURRENT\u TIMESTAMP
似乎是正确的方法,因为它是独立的()。我看不出有什么好的理由使用PHP
time()
函数,因为
CURRENT\u TIMESTAMP
是最精确的,如果服务器时间设置正确,那么总是正确的,但是基本上,除了PHP调用和实际数据库插入之间的毫秒之外,应该没有区别

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

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

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

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

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

  • JavaScript:JavaScript是客户端的,尽管很像GeoIP,但如果客户端位于VPN或代理之后,同样的问题仍然存在。您将不会显示用户的时区,而是显示VPN或代理()的时区

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

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

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

    最后的想法(我的问题解决方案是):

    SELECT CONVERT_TZ('2004-01-01 12:00:00','GMT','MET');
    
    date_default_timezone_set('America/Los_Angeles');
    
    ./mysql_tzinfo_to_sql /usr/share/zoneinfo | ./mysql -uroot -proot mysql
    
    CONVERT_TZ(NOW(), @@session.time_zone, 'America/Los_Angeles')
    2018-08-24 02:07:36
    
    CONVERT_TZ(NOW(), @@session.time_zone, 'Indian/Antananarivo')
    2018-08-24 12:07:36
    
    CONVERT_TZ(NOW(), @@session.time_zone, 'Asia/Dhaka')
    2018-08-24 15:07:36
    
    CONVERT_TZ(NOW(), @@session.time_zone, 'Antarctica/Troll')
    2018-08-24 11:07:36
    
    好的,首先感谢Blackam提供的信息,我也一直在阅读这篇文章

    据我所知,UTC是24小时时钟起点的参考,然后可以将其偏移以转换为正确的时区。该时区以前是GMT或GMT,不确定,但它是起点

    当最初的时间参考必须被定义时,人们同意将其相对于地球上的某一点。格林威治,伦敦的一个自治区,是本初子午线(0度经度)的所在地,被选为这一点

    然后,偏移量由PHP或MySql中基于字符串参数计算偏移量的函数表示,例如,这些函数可以更改并存储在全局数据库中

    MySQL:

    SELECT CONVERT_TZ('2004-01-01 12:00:00','GMT','MET');
    
    date_default_timezone_set('America/Los_Angeles');
    
    ./mysql_tzinfo_to_sql /usr/share/zoneinfo | ./mysql -uroot -proot mysql
    
    CONVERT_TZ(NOW(), @@session.time_zone, 'America/Los_Angeles')
    2018-08-24 02:07:36
    
    CONVERT_TZ(NOW(), @@session.time_zone, 'Indian/Antananarivo')
    2018-08-24 12:07:36
    
    CONVERT_TZ(NOW(), @@session.time_zone, 'Asia/Dhaka')
    2018-08-24 15:07:36
    
    CONVERT_TZ(NOW(), @@session.time_zone, 'Antarctica/Troll')
    2018-08-24 11:07:36
    
    PHP:

    SELECT CONVERT_TZ('2004-01-01 12:00:00','GMT','MET');
    
    date_default_timezone_set('America/Los_Angeles');
    
    ./mysql_tzinfo_to_sql /usr/share/zoneinfo | ./mysql -uroot -proot mysql
    
    CONVERT_TZ(NOW(), @@session.time_zone, 'America/Los_Angeles')
    2018-08-24 02:07:36
    
    CONVERT_TZ(NOW(), @@session.time_zone, 'Indian/Antananarivo')
    2018-08-24 12:07:36
    
    CONVERT_TZ(NOW(), @@session.time_zone, 'Asia/Dhaka')
    2018-08-24 15:07:36
    
    CONVERT_TZ(NOW(), @@session.time_zone, 'Antarctica/Troll')
    2018-08-24 11:07:36
    
    在模糊地理解了这一点后,我现在可以看到我的设置的解决方案,因为我将有来自不同时区的多个用户注册我的服务。对我来说,在他们的帐户配置文件下有一个选项来设置他们正确的时区是有意义的

    这使我能够获取他们的时区,然后更新mysql查询以返回他们时区中的正确数据。我同意Blackam,我更喜欢使用mysql

    我的过程如下

  • 存储时间或设置为UTC的Mysql数据库(仍在查找 正确的方法。)
  • **更新:**

    我想我已经做到了