2016-06-08 58 views
0

最近让我陷入麻烦的一件事是PHP的date_sun_info()函数。它返回一个数组,其中包含有关日光和日落等日光的信息,以及各种暮色阶段。但是,使用这个函数时,它看起来好像PHP总是按时间顺序计算适当的参数。这可能会产生问题,具体取决于您想要这些参数的时区。date_sun_info()针对特定的日历日期

让我们这两个例子(假设我们使用UTC作为默认的时区,即date_default_timezone_set("UTC")):

date_sun_info(strtotime("2013-01-01"),31.5,35.2) 

回报

sunrise: 2013-01-01 04:38:39 
sunset: 2013-01-01 14:47:28 
transit: 2013-01-01 09:43:03 
civil_twilight_begin: 2013-01-01 04:12:02 
civil_twilight_end: 2013-01-01 15:14:05 
nautical_twilight_begin: 2013-01-01 03:41:47 
nautical_twilight_end: 2013-01-01 15:44:20 
astronomical_twilight_begin: 2013-01-01 03:12:11 
astronomical_twilight_end: 2013-01-01 16:13:56 

注意如何将所有的cacluated参数准确落入日历传递给函数的日期。但是,现在让我们来看看值地球的另一面:

date_sun_info(strtotime("2013-01-01"),-44.5,-176.2) 

返回

sunrise: 2013-01-01 16:05:13 
sunset: 2013-01-02 07:32:39 
transit: 2013-01-01 23:48:56 
civil_twilight_begin: 2013-01-01 15:28:55 
civil_twilight_end: 2013-01-02 08:08:56 
nautical_twilight_begin: 2013-01-01 14:41:04 
nautical_twilight_end: 2013-01-02 08:56:47 
astronomical_twilight_begin: 2013-01-01 13:40:01 
astronomical_twilight_end: 2013-01-02 09:57:50 

显然,一些参数不落入送入功能日历日期,但计算为指定的时区。 I noticed that this has thrown other people off in the past as well。但是,在某些情况下,希望获得指定日历日期的一天中不同阶段的时间。在上面的例子中的情况下,输出必须是这样的:

transit: 2013-01-01 00:48:26 
sunset: 2013-01-01 08:32:38 
civil_twilight_end: 2013-01-01 09:09:01 
nautical_twilight_end: 2013-01-01 09:57:01 
astronomical_twilight_end: 2013-01-01 10:58:26 
astronomical_twilight_begin: 2013-01-01 14:39:57 
nautical_twilight_begin: 2013-01-01 15:41:01 
civil_twilight_begin: 2013-01-01 16:28:52 
sunrise: 2013-01-01 17:05:10 

我写了一个自定义函数来解决这个问题:

function adjustedSunInfo($date,$lat,$lon) { 
    $sinfo=date_sun_info (strtotime($date) ,$lat,$lon); 
    $sinfoMinus=date_sun_info (strtotime($date)-86400 ,$lat,$lon); 
    $sinfoPlus=date_sun_info (strtotime($date)+86400 ,$lat,$lon); 

    foreach($sinfo as $key=>$val) { 
     if(date("d",$val)>date("d",strtotime($date))) { 
      $sinfo[$key]=$sinfoMinus[$key]; 
     } else if(date("d",$val)>date("d",strtotime($date))) { 
      $sinfo[$key]=$sinfoPlus[$key]; 
     } 
    } 

    asort($sinfo); 
    return $sinfo; 
} 

然而,问题是,是否有一个(无证)标志可以传递给PHP - 或任何其他技巧 - 以获得所需的信息?

+0

对于所有未来的读者而言,如果在使用DST的时区使用'86400'或'60 * 60 * 24'或类似方法增加时间,您将在特定日期和输出中获得或失去一小时可能会受到负面影响。我意识到这个问题使用UTC(无DST),但答案是。幸运的是,答案不会使用'86400'增加时间。我只提出这一点,因为在没有确认可能的后果的情况下,在时间上有很多实例增加了'86400'。 – mickmackusa

回答

0

我不确定我是否理解你的问题100%,但可能是你已经过分了解了这一点。我自己经常犯这个罪。

此外,我不确定您使用的是什么版本的PHP,因为date_sun_info会返回associative array of timestamps ,这与您的示例输出不符。

总之,要回答你的问题: -

是否有可以传递到PHP的(无证)标志 - 或任何其他的技巧 - 以获得所需的信息?

有没有标志(肯定没有记录),但有一些技巧。返回的时间戳是事件的GMT(例如日出),所以您只需将所需的时区应用到它。 DateTime classes将使这个很容易。

此处作为一例是我怎么会重写你的函数: -

/** 
* Get an array of human readable times for sun events 
* @param \DateTime $date A \DateTime Object set to the desired date 
*      and the correct timezone for the place in question 
* @param float $lat The latitude of the place in question 
* @param float $lon The longitude of the place in question 
* 
* @return array An associative array of human readable times sorted in chronological order. 
*/ 

function adjustedSunInfo(\DateTime $date,$lat,$lon) { 
    $sinfo=date_sun_info ($date->getTimestamp() ,$lat,$lon); 

    foreach($sinfo as $key=>$val) { 
     //You should check that $val isn't 1 or empty first 
     $time = new \DateTime('@' . $val); 
     $time->setTimezone($date->getTimeZone()); 
     $sinfo[$key] = $time->format('Y m d H:i:s'); 
    } 

    asort($sinfo); 
    return $sinfo; 
} 

$time = new \DateTime('2013-01-01', new \DateTimeZone('Pacific/Chatham')); 
var_dump(adjustedSunInfo($time, -44.5, -176.2)); 

See it working

您的示例位置就在查塔姆群岛附近,因此我使用了他们的时区。你需要知道有问题的时区才能得到准确的答案。

这种方法不会因DST变化或闰年而受到影响,因为您的意愿会变得更加简单和易于阅读,我希望您会同意。

我希望这能解决您的问题。

1.有时可能会返回1或空数组元素。