3

There's something ugly about this way of producing 2 date strings a year apart

$obj_now = new DateTime();
$obj_year_ago = new DateTime();
$obj_year_ago->modify( '- 1 year');
$string_now = $obj_now->format('Y-m-d') ;
$string_year_ago = $obj_year_ago->format('Y-m-d') ;

It works but seems a clunky to me (and therefore probably inefficient).

To frame the question; if I have to produce dates based on a reference date (these are used in different ways in different forms). Do I need one object to each date or can I perform calculations to produce my strings from one DateTime object?

The difficulty I see is if I use $obj_now->modify()` it's no longer 'now'

Chris Pink
  • 1,558
  • 1
  • 15
  • 28
  • I think we hit the 'self-taught PHP' ceiling. I have no idea of the implications of creating multiple DateTime objects, whether they are resource hungry or not. There's three dates that are calculated from now (which could be generated from one DateTime) and the DateTime retrieved from the database. So maybe @José Carlos PHP is the method, generate static date strings from now although it has to be said the DateTime objects are very easy to manipulate. So if I need 4 DateTime objects then hopefully I'm not clagging up my memory usage. – Chris Pink Nov 05 '21 at 08:46

3 Answers3

4

Modify changes the DateTime object, but not the format method. Here's how you can do the following:

$curDate = new DateTime('Now');
$dates = [];
for($i=0;$i<3;$i++){
  $dates[] = $curDate->format('Y-m-d');
  $curDate->modify('-1 year');
}
var_dump($dates);
//array(3) { [0]=> string(10) "2021-11-04" [1]=> string(10) "2020-11-04" [2]=> string(10) "2019-11-04" }

If you don't want the modify to change the original object, you can use DateTimeImmutable. To get the same result as above, the code for DateTimeImmutable is like this:

$date = new DateTimeImmutable('Now');
$dates = [];
for($i=0;$i<3;$i++){
  $curDate = $date->modify('-'.$i.' year');
  $dates[] = $curDate->format('Y-m-d');
}
var_dump($dates);

For more information see DateTimeImmutable vs DateTime

jspit
  • 7,276
  • 1
  • 9
  • 17
2

Obviously, after modify() the datetime has changed and it's no longer 'now'. But you can do your job using just one object simply changing your instructions order:

$obj = new DateTime();
$string_now = $obj->format('Y-m-d');
$obj->modify('- 1 year');    
$string_year_ago = $obj->format('Y-m-d');
José Carlos PHP
  • 1,417
  • 1
  • 13
  • 20
2

Edit: As mentioned by the user IMSoP (Thank you!) the date object parameter gets modified. Therefore I changed the function to use a copy of the object to prevent this.

I would prefere to use a function for it. First of all you can, but not have to declare an date object. Second, the object you declared before the function calls doesn't get modified only to get the information you need.

<?php

/**
 * @param DateTime $dt_date
 * @param String $s_format
 * @param String $s_modifier
 * @return String
 */
function dateGetFormatedStringModified($dt_date, $s_format, $s_modifier = ''){
    $dt_temp = clone $dt_date;
    if(!empty($s_modifier)){
        $dt_temp->modify($s_modifier);
    }
    return $dt_temp->format($s_format);
}

$string_year_ago = dateGetFormatedStringModified(new DateTime(), 'Y-m-d', '- 1 year');
$string_now = dateGetFormatedStringModified(new DateTime(), 'Y-m-d');

echo $string_now; // 2021-11-04
echo $string_year_ago; // 2020-11-04

?>

Different approach would be DateTimeImmutable. This prevents the date getting changed if modify is used.

$date = new DateTimeImmutable();
$date_last_year = $date->modify('-1 year');
echo $date->format('Y-m-d');
echo $date_last_year->format('Y-m-d');

You also can combine modify with format within one line

$date = new DateTimeImmutable();
echo $date->format('Y-m-d');
echo $date->modify('-1 year')->format('Y-m-d');
Bonus
  • 31
  • 3
  • 2
    I think the way you've written the function there is a bad idea: it would be very easy to forget / not realise that it modified the passed object, and write something like `$date = new DateTime('now'); $yesterday = dateGetFormatedStringModified($date, 'Y-m-d', '-1 day'); $tomorrow = dateGetFormatedStringModified($date, 'Y-m-d', '+1 day');` which won't do what you expect. – IMSoP Nov 04 '21 at 11:32