【问题标题】:How to calculate a date difference in calendar months?如何计算日历月的日期差异?
【发布时间】:2011-09-29 17:41:13
【问题描述】:
$time_start = mktime(12,0,0,1,1,2011);
$time_end = mktime(12,0,0,7,1,2011);
$format = '%m months';

$start_date = new DateTime(date(DATE_ATOM,$time_start));
$end_date = new DateTime(date(DATE_ATOM,$time_end));
$diff = $start_date->diff($end_date, true);
echo $diff->format($format);

输出“5 个月”,我猜是因为 DST 导致它延迟了一个小时。但是,我需要计算日历月的差异;是否有另一个类/函数可以做到这一点?


添加了一些修复:

if($time_start > $time_end) list($time_start, $time_end) = array($time_end, $time_start);
$time_end += (date('I',$time_end)-date('I',$time_start))*3600; // correct for DST
$start_date = new DateTime(date(DATE_ATOM,$time_start));
$end_date = new DateTime(date(DATE_ATOM,$time_end));
$start_date->modify('12pm'); // ignore time difference
$end_date->modify('12pm');
$diff = $start_date->diff($end_date);
echo $diff->format($format);

这似乎给出了我想要的结果,但我还没有完全测试它。


更多修复,基于 Herbert 的建议:

if($time_start > $time_end) list($time_start, $time_end) = array($time_end, $time_start);
$start_date = new DateTime();
$end_date = new DateTime();
$start_date->setTimestamp($time_start);
$end_date->setTimestamp($time_end);
$diff = $start_date->diff($end_date);
$hours = $diff->format('%h');
$mins = $diff->format('%i');
$secs = $diff->format('%s');
$start_date->setTime(12,0,0);//ignore time difference for date calculations
$end_date->setTime(12,0,0);
$diff = $start_date->diff($end_date);
$years = $diff->format('%y');
$months = $diff->format('%m');
$weeks = $diff->format('%w');
$days = $diff->format('%d');

请注意,$start_date->modify('12pm') 实际上并没有做任何事情。不知道为什么它没有出错。

【问题讨论】:

  • 可能是 5 个月 29 天或其他时间 - 尝试输出包括天数在内的完整期间(%m 只为您提供完整日期的月份部分
  • 加油马克。有了 15k,你不应该这么快就扔掉 bug 这个词。 var_dump($diff); 看看 Pekka 提到了什么。
  • 嗯,你说的都是 5 个月,29 天,23 小时(我猜是夏令时)是正确的,但这并不是重点。如果一个人查看这两个日期,他会认为它们相隔 6 个月,因为它们相差 6 个日历月。这就是我需要的答案。
  • 那么 DateDiff::format 可能不适合您 - 也许您需要查看一个“漂亮的日期”库,该库以对人类有意义的方式汇总句点。
  • 我得到 6 个月的精确度。好奇。

标签: php datetime date-math


【解决方案1】:

更新

在纠结了很多不同的想法后,我突然想到时间戳是 GMT (UTC)。 date(DATE_ATOM,$time_start) 正在应用默认时区。但是,如果您显式地设置时间戳,DateTime 将假定为 UTC——因此,没有 DST 问题。

以下代码似乎无论时区或 DST 都可以工作。

<?php

$time_start = mktime(12,0,0,1,1,2011);
$time_end = mktime(12,0,0,7,1,2011)

$start_date = new DateTime();
$end_date = new DateTime();

$start_date->setTimestamp($time_start);
$end_date->setTimestamp($time_end);

$diff = $start_date->diff($end_date);

$format = '%m months';
echo $diff->format($format);

?>

我测试了一些边缘情况——包括日期和时间,以及各种时区——但我没有测试每一种的可能性,所以如果你遇到问题,我很想听听。

【讨论】:

  • 我怀疑当切换到 UTC 导致一天发生变化时,UTC 技巧会失败。如果我没有在正确的位置添加/减去小时,我的技巧也可能会产生相同的效果......
  • 这是一个有趣的问题,我完全打算继续努力。 :-)
  • @Mark:我想我找到了解决办法。
  • 我认为你可能是对的。 Unix 时间戳总是在 GMT 中,所以如果我们保持一致,我认为我们应该是安全的。感谢你的帮助!如果我遇到任何问题,我会告诉你的。
  • 在调用 setTimestamp 后转储 $start_date 实际上确实显示了我的默认时区,而不是 GMT/UTC...但它似乎仍然有效。
猜你喜欢
  • 2018-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-03
  • 1970-01-01
  • 2019-12-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多