Create new datetime object each time - php

I have created different vars using date_format from one datetime object $date_obj.
$date_obj = date_create($date);
$year = date_format($date_obj, 'Y');
$month = date_format($date_obj, 'm');
$day = date_format($date_obj, 'd');
However I have read (lost source) that this is bad practice? Instead I should create a new datetime object each time because the original object isn't referenced, but directly manipulated.
$date_obj_1 = date_create($date);
$year = date_format($date_obj_1, 'Y');
$date_obj_2 = date_create($date);
$month = date_format($date_obj_2, 'm');
$date_obj_3 = date_create($date);
$day = date_format($date_obj_3, 'd');
Is this true?

The DateTime object is an object, and therefore is passed by reference.
In your example above this won't matter, because you only format a date, you do not manipulate it. However, if you use a DateTime object as an argument in a function and inside this function you manipulate the object, your changes will be visible outside of that function:
function addDays($date,$days){
$date->add(new DateInterval($days.' days'));
}
$date_obj_1 = date_create($date);
$formatedDate1 = date_format($date_obj_1, 'Y-m-d');
addDays($date_obj_1,10);
$formatedDate2 = date_format($date_obj_1, 'Y-m-d');
In the above example $formatedDate1 is different from $formatedDate1 because $date_obj_1 was passed by reference
EDIT: for a detailed explanation on my above snipped look at the comments section. #Xatoo explained it pretty good.

date_format isn't manipulating the DateTime object. What you do is the equivalent of:
$dateObject = new DateTime($date);
$year = $dateObject->format('Y');
$month = $dateObject->format('m');
$day = $dateObject->format('d');
This is absolutely fine, dateObject is not changed by calling the format method on it.

Related

Using DateTime to produce different date strings in PHP

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

get last month and year using carbon laravel

This might be a simple, I've $month and $year, but I'm trying to get lastMonthYear and lastToLastMonthYear.
$date = Carbon::create($year, $month)->startOfMonth();
$sameMonthLastYear = $date->subYear()->format('Ym');
$lastMonthYear = $date->subMonth()->format('Ym');
$LastToLastMonthYear = $date->subMonth()->format('Ym');
Considering $month=9 and $year=2021, I'm trying to get
sameMonthLastYear = 202009
lastMonthYear = 202108
lastToLastMonthYear = 202107
but I'm getting
sameMonthLastYear = 202009
lastMonthYear = 202008
lastToLastMonthYear = 202008
Because $date value is keep updating for every line. Is there any way to get the expected result?
The right way is to use CarbonImmutable:
$date = CarbonImmutable::create($year, $month);
$sameMonthLastYear = $date->subYear()->format('Ym'); //202009
$lastMonthYear = $date->subMonth()->format('Ym'); //202108
$LastToLastMonthYear = $date->subMonths(2)->format('Ym'); //202107
With CarbonImmutable, the changes you make to $date are not persisted.
I also removed the startOfMonth method, it was useless since by default, the Carbon instance will be:
Carbon\CarbonImmutable #1630454400 {#5430
date: 2021-09-01 00:00:00.0 UTC (+00:00),
}
You can use copy() method:
$date = Carbon::create($year, $month)->startOfMonth();
$sameMonthLastYear = $date->copy()->subYear()->format('Ym');
$lastMonthYear = $date->copy()->subMonth()->format('Ym');
$LastToLastMonthYear = $date->copy()->subMonths(2)->format('Ym');

How to add time of timeType to DateTimeType

I want to add variable of type TimeType to a variable of DateTimeType
I have triying this code :
$newDate = $dateAppointment->add($duration);
but i got this error
Warning: DateTime::add() expects parameter 1 to be DateInterval,
object given
Examples of data:
$dateAppountment = 2019-03-21 10:15:00
$duration : 00:15:00
I suppose there's some kind of transformer already exists in symfony, but I can't find it. So, here's a custom code how to convert time from DateTime to DateInterval and add it to another \DateTime:
$dateAppointment = (new \DateTime());
$dtDuration = (new \DateTime())->setTime(1, 15, 0);
$duration = $duration->format('\P\TH\Hi\Ms\S');
$newDate = $dateAppointment->add(new \DateInterval($duration));
Fiddle: https://3v4l.org/5lFlQ
Here is an example:
$duration = '1970-01-01 01:00:00.000000';
$timeObject = DateTime::createFromFormat('Y-m-d H:i:s.u', $duration, new DateTimeZone('UTC'));
$date = '2019-03-21 10:15:00';
$dateObject = DateTime::createFromFormat('Y-m-d H:i:s', $date);
$modify = '+' . $timeObject->format('U') . ' second';
echo $dateObject->modify($modify)->format('Y-m-d H:i:s');
Just get the seconds from your duration object and add them to your date object. If you used modify, there are a lot of things you can do.

Creating a Timestamp from a URL string

I have read the manual - but can't seem to find what I need. I don't need the actual date - I need the date I tell it is from the URL
This is what I have currently:
//create search string for posts date check
if($Day <= 9) {//ensure day is dual digit
$fix = 0;
$Day = $fix . $Day;
}
$Day = preg_replace("/00/", "/0/", $Day);
$date = $_GET["Year"];
$date .= "-";
$date .= $_GET["Month"];
$date .= "-";
$date .= $_GET["Day"];
$currently = mktime (0,0,0,$Month,$Day,$Year,0); //create a timestamp from date components in url feed
//create display date from timestamp
$dispdate = date("l, j F Y",$currently);
When I echo $date it reads correctly for the variable string supplied in the URL but $dispdate always returns the current day that it actually is today. I need $currently to be the timestamp of the date in the URL too.
You seem to construct a valid, readable datestring from the GET parameters. Use
$currently = strtotime($date).
It will return a timestamp that you can use to create the $dispdate like you already do with the date function.
Seems like not all the OP's code was posted, so this is based on what is known.
In the line:
mktime (0,0,0,$Month,$Day,$Year,0)
You are using variables that aren't shown to us (so we must assume are not being set to anything). Above this line you are building a "$date" variable with the URL parameters. This is what should be used in your mktime function.
You could use a Datetime object, pass the given parameters and format the output anyway you want.
<?php
//replace with GET params
$year = 2015;
$month = 10;
$day = 01;
$datetime = new Datetime($year.'-'.$month.'-'.$day);
echo $datetime->format('Y-m-d');
?>

php - datetimezone

I'm using functions with the datetime object that require a datetimezone object as an argument. I see a list of timezones here:
http://www.php.net/manual/en/class.datetimezone.php
but there's not things like 'est'. How could I create a 'datetimezone' object from EST?
$tz = new DateTimeZone('EST');
In http://www.php.net/manual/en/timezones.php you can find in the OTHER section the EST there.
To create one use date_default_timezone_set('EST');
To make sure you have it do echo date_default_timezone_get();
A very verbose loop. The construct function for the DateTime class isn't working properly for me but this works.
$date = "2011/03/20";
$date = explode("/", $date);
$time = "07:16:17";
$time = explode(":", $time);
$tz_string = "America/Los_Angeles"; // Use one from list of TZ names http://us2.php.net/manual/en/timezones.php
$tz_object = new DateTimeZone($tz_string);
$datetime = new DateTime();
$datetime->setTimezone($tz_object);
$datetime->setDate($date[0], $date[1], $date[2]);
$datetime->setTime($time[0], $time[1], $time[2]);
print $datetime->format('Y/m/d H:i:s');
?>
Be aware of that some TimeZone abbreviations like EST are not unique. See http://www.timeanddate.com/library/abbreviations/timezones/.
The usage of EST is not recommended, see
http://www.php.net/manual/en/timezones.others.php.
Use for example America/New_York instead.

Categories