du7999 2016-09-30 17:49 采纳率: 100%
浏览 49
已采纳

从时间戳中减去用户TimeZone偏移量(例如+02:00)

Background:

I am displaying a list of times as an associative array. The array looks like this (11:00 AM to 12:00 AM):

array(5) {
  [1475226000]=>
  string(35) "September 30, 2016, 11:00 am +02:00"
  [1475226900]=>
  string(35) "September 30, 2016, 11:15 am +02:00"
  [1475227800]=>
  string(35) "September 30, 2016, 11:30 am +02:00"
  [1475228700]=>
  string(35) "September 30, 2016, 11:45 am +02:00"
  [1475229600]=>
  string(35) "September 30, 2016, 12:00 pm +02:00"
}

The key is a unix timestamp. The value is the formatted unix timestamp displayed in the users time zone.

My Code

Here is my commented class that generates the array:

<?php

class Time
{
    public function __construct()
    {
        date_default_timezone_set('UTC');
    }

    public function getTimeSlots($year, $month, $day, $start_time = '11:00', $end_time = '12:00')
    {
        $date = $year . '-' .  $month . '-' . $day;
        // get GMT timestamp of 2016-09-30 00:00 Europe/London
        $gmt_date = strtotime($this->getRelativeDateTime($date));

        $gmt_date = $gmt_date - 7200;
        // subtract from or add to $gmt_date whatever our timezone offset in hours is

        // get start time offset in seconds from 2016-9-30 00:00
        $seconds_start = strtotime('1970-01-01 ' . $start_time . ' UTC');
        // get end time offset in seconds from 2016-9-30 00:00
        $seconds_end   = strtotime('1970-01-01 ' . $end_time . ' UTC');

        $unix_seconds_start = $gmt_date + $seconds_start; // GMT
        $unix_seconds_end   = $gmt_date + $seconds_end;

        // echo $unix_seconds_start . date('Y-m-d H:i', $unix_seconds_start);
        // echo '<br>';
        // echo $unix_seconds_end . date('Y-m-d H:i', $unix_seconds_end);

        while ($unix_seconds_start <= $unix_seconds_end) {

            $dt = new DateTime('@' . $unix_seconds_start);
            $dt->setTimezone(new DateTimeZone('Europe/Paris'));
            $slots[$unix_seconds_start] = $dt->format('F j, Y, H:i a P');
            $unix_seconds_start = $unix_seconds_start + 900;

        }
        echo '<pre>', var_dump($slots), '</pre>';
    }

    public function getRelativeDateTime($date)
    {
        $date = new DateTime($date, new DateTimeZone('Europe/Paris'));
        return $date->format('Y-m-d H:i');
    }
}

$time = new Time;
$time->getTimeSlots('2016', '09', '30');

// we want var_dump to show the following
// --------------------------------------
//
// array () {
//     from 00:00
//     1234567890 (unix timestamp) => '00:00' (users time)
//     1234567890 (unix timestamp) => '00:15' (users time)
//     1234567890 (unix timestamp) => '00:30' (users time)
//     1234567890 (unix timestamp) => '00:45' (users time)
//     to  24:00
// }

Issue

I want my times to start strictly at 00:00 AM and end at 24:00pm for the user, however as you can see if you run the code I am getting an offset depending on my users time offset.

That means if the user has his time zone as Europe/London +01:00 my array starts at 01:00.

The problem is on line 16. As you can see if you uncomment line 16 and run the code it works but only because I am explicitly subtracting two hours (in seconds) from the timestamp.

http://sandbox.onlinephpfunctions.com/code/d19b6fc5335f41af491dfedcfae2c390aa3000ec

Question

Is there a way using DateTime (or any other method!) to subtract the users time zone offset from the $gmt_date variable?

  • 写回答

1条回答 默认 最新

  • dongshi6528 2016-09-30 18:49
    关注

    This is your answer. Use DateTime object and create a timezone.

    <?php
    
    $tz_array = array('UTC', 'Europe/Paris', 'Asia/Jerusalem');
    
    foreach ($tz_array as $tz) {
        $time = new Time($tz);
        $time->getTimeSlots('2016', '09', '30');
    }
    
    class Time {
    
        /** @var DateTimeZone */
        private $tz;
    
        public function __construct($tz) {
            $this->tz = new DateTimeZone($tz);
        }
    
        public function getTimeSlots($year, $month, $day, $start_time = '11:00', $end_time = '12:00') {
    
            $from = new DateTime("$year-$month-$day $start_time:00", $this->tz);
            $to = new DateTime("$year-$month-$day $end_time:00", $this->tz);
    
            $unix_seconds_start = $from->getTimestamp();
            $unix_seconds_end = $to->getTimestamp();
    
            $interval = new DateInterval('PT900S'); // 900 seconds interval
    
            $slots = array();
    
            while ($unix_seconds_start <= $unix_seconds_end) {
    
                $slots[$unix_seconds_start] = $from->format('F j, Y, H:i a P');
                $from->add($interval);
                $unix_seconds_start = $from->getTimestamp();
            }
    
            echo
            "Time slots demo for timezone ",
            $this->tz->getName();
            var_dump($slots);
        }
    
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 TI的insta-spin例程
  • ¥15 完成下列问题完成下列问题
  • ¥15 C#算法问题, 不知道怎么处理这个数据的转换
  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!
  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?
  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮
  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?