-2

I want to make array of previous month 1st and last day. From my starting \DateTime $date=2018-04-30. When I change my starting \DateTime to 2018-05-31 and my expected result is an array that contains:

[
  ['2018-03-01', 2018-03-31],
  ['2018-02-01', 2018-02-28],
  ['2018-01-01', 2018-01-31],
  ['2018-01-01', 2018-03-31],
  ['2017-03-01', 2018-03-31],
]

I have currently done:

$monthAgoStart = clone $date;
$monthAgoEnd = clone $date;
$month2agoStart = clone $date;
$month2agoEnd = clone $date;
$month3agoStart = clone $date;
$month3agoEnd = clone $date;
$currentYearStart = clone $date;
$yearAgo = clone $date;
$monthAgoStart->modify('first day of previous month');
$monthAgoEnd->modify('last day of previous month');
$month2agoStart->modify('first day of this month')->modify('-2 months');
$month2agoEnd = new \DateTime($month2agoEnd->modify('-1 months')->format('y-m-0'));
$month3agoStart= new \DateTime($month3agoStart->modify('-3 months')->format('y-m-1'));
$month3agoEnd = new \DateTime($month3agoEnd->modify('-3 months')->format('y-m-0'));
$currentYearStart->modify('first day of January');
$yearAgo->modify('-12 months');

Result array:

$dates = [
  'ago1month' => ["start" => $monthAgoStart, "end" => $monthAgoEnd],
  'ago2month' => ["start" => $month2agoStart, "end" => $month2agoEnd],
  'ago3month' => ["start" => $month3agoStart, "end" => $month3agoEnd],
  'yearStart' => ["start" => $currentYearStart, "end" => $monthAgoEnd],
  'yearAgo' => ["start" => $yearAgo, "end" => $monthAgoEnd],
];

My code generates:

{"ago1month":{
         "start":{"date":"2018-03-01"},
         "end":{"date":"2018-03-31"}
    },
    "ago2month":{
         "start":{"date":"2018-02-01"},
         "end":{"date":"2018-02-28 "}
    },
    "ago3month":{
         "start":{"date":"2018-01-01 "},
         "end":{"date":"2017-12-31"}
    },
    "yearStart":{ 
        "start":{"date":"2018-01-01"},
        "end":{"date":"2018-03-31"}
    },
"yearAgo":{ 
        "start":{"date":"2017-04-30"},
        "end":{"date":"2018-03-31 "}
    }
}

What is best option to solve my problem? I was planning to make strings and create new DateTime for each array record, but want to be sure if there are no other way to do this. Still wrong: "yearAgo":{ "start":{"date":"2017-04-30"}} "ago3month":{"end":{"date":"2017-12-31"}}

---edit---

I used Carbon library that solves my issue. Similar question here,

Aipo
  • 1,805
  • 3
  • 23
  • 48
  • 1
    I don't understand your expected array. Especially `['2018-01-01', 2018-01-31], ['2018-01-01', 2018-03-31],` Do you meant 2018-01-31 instead of 2018-03-31? But then it would be duplicate with the one above.. – Xatenev Jul 20 '18 at 13:23
  • Why would -12 months from 4/30 or 5/31 return `2017-03-01`? – Devon Bessemer Jul 20 '18 at 13:24
  • @Xatenev it seems only the first 3 lines are the previous months, the last two are supposed to be last quarter and last year – Karsten Koop Jul 20 '18 at 13:26
  • 1
    I think you'd have a much easier time if you used `DateTimeImmutable` instead of `DateTime`. You wouldn't need to clone anything, and you'd avoid your underlying objects being changed when you modify them. – iainn Jul 20 '18 at 13:28
  • It feels like you have working code. If you are seeking refinement advice, perhaps migrate to CodeReview. If you have a "problem", it isn't clear to me. – mickmackusa Jul 20 '18 at 14:04
  • 1
    @mickmackusa My code doesn't work as expected. I don't want any `format` function to use and get my code working. Should I create `new DateTime (string)` for each element of my array? No other solutions? – Aipo Jul 20 '18 at 14:07
  • @mickmackusa [Cross-posted and about to get closed on Code Review](https://codereview.stackexchange.com/q/200084/52915). The question should've been cleaned up here instead of cross-posted. – Mast Jul 23 '18 at 06:34
  • @Mast looks like the OP pulled it. I did say that the question was unclear to me. – mickmackusa Jul 23 '18 at 06:48

1 Answers1

2

When retrieving the last day of the month, you should use t from the date format.

You can also simplify your code and make it much easier to read by cloning $date when you need it or using DateTimeImmutable.

$month3agoEnd = (clone $date)->modify('-3 months')->format('Y-m-t');

This turns out to be 2018-03-31 as expected. Using Y-m-0 returns 2018-03-0 which you have processed inside of a new \DateTime object, so your code is actually written as:

 $month3agoEnd = new DateTime('2018-03-0');

This actually returns a new DateTime instance set to 2018-02-28 so I'm not sure how you managed to get 2017-12-31.

Devon Bessemer
  • 34,461
  • 9
  • 69
  • 95
  • 1
    `$month3agoEnd = (clone $date)->modify('-3 months')->format('Y-m-t');` What about php 5.6 solution? – Aipo Jul 23 '18 at 07:43
  • 1
    @pvaitonis This won't work in 5.6, but 5.6 is almost end of life, and I'm not aware of any OS distribution supporting 5.6 longer. So I wouldn't recommend building new projects for 5.6. http://php.net/supported-versions.php. You could still use DateTimeImmutable or just use clone $date on a separate line. – Devon Bessemer Jul 23 '18 at 12:14