donglingyi4679 2013-08-28 00:34
浏览 73
已采纳

DateTime“上个月的第一天”没有返回第一天

I looked at this answer already, and it's quite close to what I have.

Here is my PHP code:

$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);

Today is August 27th, so I would expect July 1, June 1, and May 1. Here's what the actual output is:

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)

Why is it returning the second day of the months for me?

I've also tried it without the new DateTimeZone('GMT') as the second parameter of the constructor for the initial DateTime but it still gives me the same result, just with different times.

  • 写回答

2条回答 默认 最新

  • doujianwei8217 2013-08-28 00:40
    关注

    this part irrelevant - question was edited

    Because of the timezone difference. $start is calculated in the 'Rainy River timezone', while $middle and $end are in UTC time. The 'Rainy River timezone has a -06:00 hour offset from UTC (exactly the difference in hours between the first with the second and third results).

    update 1 - solution

    It seems the problem lies somewhere around strtotime. For some reason it yields a result with an offset of one day (further explanation needed). A simple solution, is to subtract one second from that date and it will produce the correct result.

    $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')."
    ";
    

    Result:

    2013-05-01
    

    update 2 - reason for problem

    Eventually I find out that the problem originates from the instantiation of the fisrt date object. Here is an illustration.

    This will give a correct result:

    $original = new DateTime('2013-05-01');
    echo $original->format('Y-m-d')."
    ";
    
    $previous= DateTime::createFromFormat('U', strtotime('first day of last month',($original->format('U'))),new DateTimeZone('UTC'));
    echo $previous->format('Y-m-d')."
    ";
    

    Result (OK):

    2013-05-01
    2013-04-01   <--- OK
    

    However, this will not (only first line different, as in the original code):

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

    Result:

     2013-07-01
     2013-05-02  <--- BAD
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 如何用Labview在myRIO上做LCD显示?(语言-开发语言)
  • ¥15 Vue3地图和异步函数使用
  • ¥15 C++ yoloV5改写遇到的问题
  • ¥20 win11修改中文用户名路径
  • ¥15 win2012磁盘空间不足,c盘正常,d盘无法写入
  • ¥15 用土力学知识进行土坡稳定性分析与挡土墙设计
  • ¥70 PlayWright在Java上连接CDP关联本地Chrome启动失败,貌似是Windows端口转发问题
  • ¥15 帮我写一个c++工程
  • ¥30 Eclipse官网打不开,官网首页进不去,显示无法访问此页面,求解决方法
  • ¥15 关于smbclient 库的使用