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


Subtracting users TimeZone offset (e.g. +02:00) from a timestamp

背景:

我将时间列表显示为关联数组。阵列如下(上午11:00至12:00(:

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"
}

密钥是unix时间戳。该值是显示在用户时区中的格式化unix时间戳。

我的代码

这是我的注释类,它生成数组:

<?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
// }

问题

我希望我的时间严格从00:00开始,到24:00结束,但正如你所看到的,如果你运行代码,我会得到一个偏移量,这取决于我的用户时间偏移量。

这意味着,如果用户的时区为欧洲/伦敦+01:00,我的数组将从01:00开始。

问题在16号线上。正如您所看到的,如果您取消对第16行的注释并运行代码,它会起作用,但这只是因为我明确地从时间戳中减去了两个小时(以秒为单位(。

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

问题

有没有办法使用DateTime(或任何其他方法!(从$gmt_date变量中减去用户时区偏移量?

这是您的答案。使用DateTime对象并创建时区。

<?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);
    }
}