在处理用户提供的本地datetime
值时,由于夏时制转换,很可能出现时间无效或不明确的情况。
PHP有很好的时区支持,但我似乎找不到任何东西来解决这个问题。我能找到的最接近的东西是DateTimeZone::GetTransitions。它提供了原始数据,所以我可以看到一些方法可以在此基础上编写。但它们已经存在于某个地方了吗?如果没有,谁能提供一个好的实现?我希望他们能像这样工作:
php prettyprint-override">$tz = new DateTimeZone('America/New_York');
echo $tz->isValidTime(new DateTime('2013-03-10 02:00:00')); # false
echo $tz->isAmbiguousTime(new DateTime('2013-11-03 01:00:00')); # true
我不知道任何现有的实现,而且我还没有理由使用像这些这样的高级日期/时间特性,所以这里是一个干净的实现。
为了启用问题中说明的语法,我们将扩展DateTimeZone
,如下所示:
class DateTimeZoneEx extends DateTimeZone
{
const MAX_DST_SHIFT = 7200; // let's be generous
// DateTime instead of DateTimeInterface for PHP < 5.5
public function isValidTime(DateTimeInterface $date);
public function isAmbiguousTime(DateTimeInterface $date);
}
为了避免分散注意力的细节使实现变得混乱,我将假设$date
参数是用正确的时区创建的;这与问题中给出的示例代码形成了对比。
也就是说,正确的结果不会由此产生:
$tz = new DateTimeZoneEx('America/New_York');
echo $tz->isValidTime(new DateTime('2013-03-10 02:00:00'));
但取而代之的是:
$tz = new DateTimeZoneEx('America/New_York');
echo $tz->isValidTime(new DateTime('2013-03-10 02:00:00', $tz));
当然,由于$tz
已经被对象称为$this
,因此应该很容易扩展这些方法,从而消除这个需求。无论如何,使界面超级用户友好不在本答案的范围之内;接下来,我将集中讨论技术细节。
public function isValidTime(DateTime $date)
{
$ts = $date->getTimestamp();
$transitions = $this->getTransitions(
$ts - self::MAX_DST_SHIFT,
$ts + self::MAX_DST_SHIFT
);
if (count($transitions) == 1) {
// No DST changes around here, so obviously $date is valid
return true;
}
$shift = $transitions[1]['offset'] - $transitions[0]['offset'];
if ($shift < 0) {
// The clock moved backward, so obviously $date is valid
// (although it might be ambiguous)
return true;
}
$compare = new DateTime($date->format('Y-m-d H:i:s'), $this);
return $compare->modify("$shift seconds")->getTimestamp() != $ts;
}
不难看出如何利用这一事实:创建一个新的datetime
实例,该实例等于输入的$date
,然后以挂钟时间为单位将其前移,以秒为单位将其前移等于DST移位(在进行此调整时必须不考虑DST)。如果结果的时间戳(这里使用DST规则)等于输入的时间戳,那么输入是无效的日期/时间。
该实现与ISValidTime
非常相似,只有一些细节发生了变化:
public function isAmbiguousTime(DateTime $date)
{
$ts = $date->getTimestamp();
$transitions = $this->getTransitions(
$ts - self::MAX_DST_SHIFT,
$ts + self::MAX_DST_SHIFT);
if (count($transitions) == 1) {
return false;
}
$shift = $transitions[1]['offset'] - $transitions[0]['offset'];
if ($shift > 0) {
// The clock moved forward, so obviously $date is not ambiguous
// (although it might be invalid)
return false;
}
$shift = -$shift;
$compare = new DateTime($date->format('Y-m-d H:i:s'), $this);
return $compare->modify("$shift seconds")->getTimestamp() - $ts > $shift;
}
最后一点取决于PHP日期函数的另一个实现细节:当要求为一个不明确的日期/时间生成时间戳时,PHP生成第一次(以绝对时间表示)出现的时间戳。这意味着对于给定的DST更改,最近的模糊时间和最早的非模糊时间的时间戳将相差大于DST偏移量(具体地说,差异将在范围[offset+1
,2*offset
],其中offset
是绝对值)。
该实现利用了这一点,再次向前执行“挂钟移位”,并检查结果与输入$date
之间的时间戳差异。
请参见实际操作中的代码。
问题内容: 我正在使用PHP中的一维数组。我想检测重复值的存在,然后计算重复值的数量并输出结果。例如,给定以下数组: 我想打印: 关于如何解决这个问题有什么建议吗? 谢谢。 麦克风 问题答案: 您可以使用array_count_values函数 将输出
在一个小行星游戏中,我在旋转精灵时尝试使用XNA进行2D碰撞检测时遇到了一些问题。在子弹击中小行星之前,碰撞一直在发生(看起来是从各个方向),当飞船撞上小行星时,碰撞也是不准确的。我使用一个矩阵来旋转飞船发射的子弹,然后是一个小行星的矩阵,并且在一个Xbox独立游戏论坛上使用了每像素碰撞检测样本。 这是我的子弹矩阵…原点和位置是子弹的矢量2属性 和小行星... 我是编程新手,在过去的几天里,我一直
我的应用程序中有回收器视图。UI类似于Google Play Store应用程序。它有两个视图寻呼机和项目的列表和网格以交替的方式。所有数据都是从web服务中提取的,并在两个API调用中被分叉。列表和网格的数据是从另一个API填充的。问题是,当我快速滚动recyclerview时,我会遇到这种崩溃。滚动recyclerview时,用于在列表/网格中加载数据的API调用来自。阅读了许多关于这个主题的
关于测试XML标记的正确嵌套的一个问题: null 发现/lastname标记在其父标记之外的代码或方向是什么,父标记是to,/to pair? 干杯。
问题内容: 我想说出JS中有效和无效日期对象之间的区别,但不知道如何: 有编写函数的想法吗? 建议使用Ash 来分析日期字符串,这为检查日期字符串是否有效提供了一种权威方法。 如果可能的话,我希望我的API接受Date实例,并能够检查/确认它是否有效。Borgar的解决方案可以做到这一点,但是我需要在浏览器中对其进行测试。我也想知道是否有更优雅的方法。 Ash使我考虑完全不让我的API接受实例,这
我尝试使用request.meta['http_user_agent']来检测浏览器。但这将返回我测试时的浏览器类型列表 **我无法得到它返回值的模式。谁能告诉我如何得到浏览器名称