检查时间是否在两次之间,给出错误的答案

时间:2013-09-21 10:15:08

标签: php time strtotime

<?php
    $saturday = array(
        '00:00 - 01:00' => 'Nightshow',
        '01:00 - 02:00' => 'Nightshow',
        '02:00 - 03:00' => 'Nightshow',
        '03:00 - 04:00' => 'Nightshow',
        '04:00 - 05:00' => 'Nightshow',
        '05:00 - 06:00' => 'Early birds',
        '06:00 - 07:00' => 'Early birds',
        '07:00 - 08:00' => 'Cox n Crendor in the morning',
        '08:00 - 09:00' => 'Cox n Crendor in the morning',

        ...

        '23:00 - 24:00' => 'John late night'
    );


    foreach($saturday as $timeD => $show){
        if(!empty($timeD) && isset($timeD)){
            $timesplit = explode(' -', $timeD);

            if (time() > strtotime('today '. $timesplit[0]) && time() < strtotime('today '. $timesplit[1])) {

                echo $show;
            }
        }
    }
?>

再次问好Stackoverflow!

我有一个数组,包含代表日程安排的一天中的某些时间(24小时格式)。我正在尝试做的是检查目前正在播出的节目。我上面尝试的东西不起作用 - 时间结果是几个小时或者他们完全错了,甚至没有按照一定的顺序。我不明白什么是错的。我该如何解决这个问题?

提前致谢!

2 个答案:

答案 0 :(得分:3)

我相信你遇到了一些基本的时区问题。

Timezone Basic

时区转换可能令人沮丧,但一旦你习惯了它,它就会非常直接。

当我们处理时间时,我们还需要注意strtotime()date()等功能。这两个函数 受时区设置的影响。当我说时区设置时,我的意思是你的php.ini中的值date.timezone

例如,我设置date.timezone = Asia/Singapore,它是UTC + 8时区:

我们说UTC时间现在是2013-02-05 00:00:00 UTC,时间戳应该是1360022400

  • time()会给我1360022400
  • strtotime('2013-02-05 00:00:00')会给我1359993600(或-28800,或-8小时!)

注意strtotime的行为方式?它实际上使用这个事实,PHP环境是UTC + 8时区,并认为你指定的日期时间是+8时区,因此它为你推迟了8个小时,以正确表示它以UTC时间戳。这就是问题所在。

解决方案

通常,我会做什么(也许某人可以提供更好的解决方案?)是在模糊的日期时间后面添加UTC并迫使我们以UTC时区计算所有内容。所以只需这样做:

strtotime('2013-02-05 00:00:00 UTC')

现在将为您提供1360022400,或者在UTC时间为00:00:00。当time()返回真实的UTC时间戳时进行时间敏感计算时,这尤其好。

有些说明:

  • time()将始终为您提供UTC时间戳,无论时区设置是
  • strtotime()将始终受时区设置的影响,因此如果您正在进行时间敏感的比较,请尝试确保它们全部采用UTC格式。
  • date()也受到时区设置的影响,其中date('Y-m-d H:i:s', 1360022400)将为您提供2013-02-05 08:00:00,为了解决这个问题,我们改为使用gmdate ('Y-m-d H:i:s', 1360022400)

您的问题

所以,既然你似乎在处理时间敏感的决定,一个问题,如果我与你住在不同的时区,我是否需要看到与你相同的结果?


如果我们(我和你)需要看到完全相同的结果,那么你应该这样做:

//Let's say the timezone required for that decision made is UTC+6
$event_timezone_offset = 6 * 3600;

foreach($saturday as $timeD => $show){
  if(!empty($timeD)){ //you don't need isset here as !empty taken care of it
    list($startTime, $endTime) = explode(' - ', $timeD);
    $start = strtotime('today '.$startTime.' UTC') - $event_timezone_offset;
    $end = strtotime('today '.$endTime.' UTC') - $event_timezone_offset;
    $now = time();
    if ($start <= $now && $now < $end) { //notice the inclusive <=
        echo $show;
    }
}

对于第strtotime('today '.$startTime.' UTC') - $event_timezone_offset;行,让我们逐步完成:

我们假设现在的当地时间是07:00 (UTC+6),您应该看到'Cox n Crendor ..':

  • time()将为您提供2013-09-21 01:00:00 UTC
  • 的确切UTC时间戳
  • strtotime('today 07:00 UTC')会为您提供2013-09-21 07:00:00 UTC
  • 的时间戳
  • 一旦您执行- $event_timezone_offset,您就会获得2013-09-21 01:00:00 UTC
  • 的时间
  • 所以if ($start <= $now)将是真的,你应该看到'Cox n Crendor ..'

如果我和你需要根据我们各自的本地时间戳得到不同的结果,那么你需要sniff user's timezone using javascript,或者要求他们通过一些后端设置设置时区,并使用相同的逻辑来通过设置$event_timezone_offset = $user_timezone_offset确定结果。


我希望这不会太混乱,但处理所有这些数学真的很有趣。

答案 1 :(得分:1)

(您必须在脚本中稍后用当前时间戳$fake_timestamp替换time() ...但我需要这样进行测试。)

<?php


    $saturday = array(
        '00:00 - 01:00' => 'Nightshow',
        '01:00 - 02:00' => 'Nightshow',
        '02:00 - 03:00' => 'Nightshow',
        '03:00 - 04:00' => 'Nightshow',
        '04:00 - 05:00' => 'Nightshow',
        '05:00 - 06:00' => 'Early birds',
        '06:00 - 07:00' => 'Early birds',
        '07:00 - 08:00' => 'Cox n Crendor in the morning',
        '08:00 - 09:00' => 'Cox n Crendor in the morning',
        '23:00 - 24:00' => 'John late night'
    );

    //$current_day_timestamp = gettimeofday(); //bug? returns time(), not day!time
    $current_day_timestamp = strtotime('TODAY');
    //print 'Current day time: '.$current_day_timestamp.'<br />';

    //Trying to "find" Early birds 05:00-06.00, setting "current time" to 05:30
    $fake_timestamp = $current_day_timestamp + 5.5 * 3600;
    //print 'fake time: '.$fake_timestamp.'<br />';

    foreach ($saturday AS $hours => $show) {
      $hours = explode(' - ', $hours);
      $show_start = strtotime($hours[0]);
      $show_end = strtotime($hours[1]);
      if ($show_start < $fake_timestamp AND $show_end > $fake_timestamp) {
        print $show;
      }
      //print $show.'<hr />';
      //print 'show start: '.$show_start.'<br />';
      //print 'show end: '.$show_end.'<br /><br />';
    }

?>