Php 日期时间“;“上个月的第一天”;第一天不回来

Php 日期时间“;“上个月的第一天”;第一天不回来,php,datetime,datediff,Php,Datetime,Datediff,我已经看过了,它和我的非常接近 以下是我的PHP代码: $start = new DateTime('0:00 first day of previous month', new DateTimeZone('UTC')); /* if (isset($_GET['year']) && isset($_GET['month']) && checkdate($_GET['month'], 1, $_GET['year'])) { $start = DateTi

我已经看过了,它和我的非常接近

以下是我的PHP代码:

$start = new DateTime('0:00 first day of previous month', new DateTimeZone('UTC'));
/*
if (isset($_GET['year']) && isset($_GET['month']) && checkdate($_GET['month'], 1, $_GET['year'])) {
    $start = DateTime::createFromFormat('Y-m-d', $_GET['year'] . '-' . $_GET['month'] . '-1');
}*/
$middle = DateTime::createFromFormat('U', strtotime('first day of last month', $start->format('U')));
$middle->setTimezone(new DateTimeZone('UTC'));
$end = DateTime::createFromFormat('U', strtotime('first day of 2 months ago', $start->format('U')));
$end->setTimezone(new DateTimeZone('UTC'));

var_dump($start);
var_dump($middle);
var_dump($end);
今天是8月27日,所以我预计是7月1日、6月1日和5月1日。以下是实际输出:

object(DateTime)[1]
  public 'date' => string '2013-07-01 00:00:00' (length=19)
  public 'timezone_type' => int 3
  public 'timezone' => string 'UTC' (length=3)

object(DateTime)[2]
  public 'date' => string '2013-05-02 00:00:00' (length=19)
  public 'timezone_type' => int 3
  public 'timezone' => string 'UTC' (length=3)

object(DateTime)[3]
  public 'date' => string '2013-04-02 00:00:00' (length=19)
  public 'timezone_type' => int 3
  public 'timezone' => string 'UTC' (length=3)
为什么它会在我这个月的第二天回来

我也尝试过,没有将
新日期时区('GMT')
作为初始
日期时间的构造函数的第二个参数,但它仍然给出相同的结果,只是时间不同。

此部分无关-问题已编辑 因为时区不同$start在“雨季河流时区”计算,而$MIDLE和$end在UTC时间计算。 “Rain River”时区与UTC有一个时间差(正好是第一个结果与第二个和第三个结果之间的小时差)

更新1-解决方案 问题似乎出在时间的某个地方。出于某种原因,它会产生一个偏移量为一天的结果(需要进一步解释)。一个简单的解决办法是,从该日期减去一秒钟,它将产生正确的结果

$timezone = new DateTimeZone('UTC');
$start = new DateTime('0:00 first day of previous month', $timezone );
$middle = DateTime::createFromFormat('U', strtotime('first day of last month',($start  ->format('U'))-1),$timezone);
echo $middle->format('Y-m-d')."\n";
结果:

2013-05-01
 2013-07-01
 2013-05-02  <--- BAD
更新2-问题原因 最终我发现问题源于第一个日期对象的实例化。这是一个例子

这将给出正确的结果:

$original = new DateTime('2013-05-01');
echo $original->format('Y-m-d')."\n";

$previous= DateTime::createFromFormat('U', strtotime('first day of last month',($original->format('U'))),new DateTimeZone('UTC'));
echo $previous->format('Y-m-d')."\n";
结果(OK):

结果:

2013-05-01
 2013-07-01
 2013-05-02  <--- BAD
2013-07-01
2013-05-02读完后,我有了一个更好的想法:

$start = new DateTime('0:00 first day of previous month');
/*
if (isset($_GET['year']) && isset($_GET['month']) && checkdate($_GET['month'], 1, $_GET['year'])) {
    $start = DateTime::createFromFormat('Y-m-d', $_GET['year'] . '-' . $_GET['month'] . '-1');
}*/
$middle = clone $start;
$middle->modify('first day of last month');
$end = clone $start;
$end->modify('first day of 2 months ago');

var_dump($start);
var_dump($middle);
var_dump($end);
输出:

object(DateTime)[1]
  public 'date' => string '2013-07-01 00:00:00' (length=19)
  public 'timezone_type' => int 3
  public 'timezone' => string 'America/Rainy_River' (length=19)

object(DateTime)[2]
  public 'date' => string '2013-06-01 00:00:00' (length=19)
  public 'timezone_type' => int 3
  public 'timezone' => string 'America/Rainy_River' (length=19)

object(DateTime)[3]
  public 'date' => string '2013-05-01 00:00:00' (length=19)
  public 'timezone_type' => int 3
  public 'timezone' => string 'America/Rainy_River' (length=19)

此外,我意识到a对于
$start
实例是一个更好的选择(这样我就不必克隆另外两个),但我还没有访问PHP5.5的权限。

我认为这是问题所在,但我也尝试将所有时间设置为UTC。。。请参阅编辑后的帖子。@rink.attendant.6是否有理由以不同的方式实例化日期?为什么不$start=新日期时间(“上个月的第一天”)$中间=新日期时间(“上个月的第一天”)$结束=新日期时间(“2个月前的第一天”);因为正如您在我的注释代码中所看到的,
$start
可能通过
$\u GET
(特别是下拉框)传递,因此
$middle
$end
需要相对于
$start
+1进行解释。。。每天都得学点新东西!:)这就是我们来这里的原因!:)我仍然希望有一位对php更有经验的人能够就日期对象的行为方式/原因提供意见。他们似乎在创建一些参考资料,但文档或其他在线讨论中没有任何内容……竖起大拇指,这是一种更干净的方式。然而,最初问题的一部分是为什么这段代码不能正常工作,我试图对此进行详细阐述。是的,所以对于DateTimeImmutable,只需更改DateTime>DateTimeImmutable,然后您就可以执行:$middle=$start->modify等操作。