Here is an example of the code I used:
<?php
date_default_timezone_set("Europe/London");
$date1 = date_create("2014-04-05");
$date2 = $date1;
date_add($date2, new DateInterval("P1M"));
echo "Date 1: ".date_format($date1, "Y-m-d")."<br/>";
echo "Date 2: ".date_format($date2, "Y-m-d")."<br/>";
?>
The result for this would be:
Date 1: 2014-05-05
Date 2: 2014-05-05
I was expecting the result of:
Date 1: 2014-04-05
Date 2: 2014-05-05
How can I get the expected result and fix this?
I can only use PHP, HTML and CSS so no jQuery or Javascript please.
The clone keyword is what you need.
$date2 = clone $date1;
When an object is cloned, a shallow copy of all of the object's properties. Any properties that are references to other variables, will remain references.
If your object $date2 holds a reference to another object $date1 which it uses and when you replicate the parent object you want to create a new instance of this other object so that the replica has its own separate copy.
Source
This is due to how objects are assigned by reference since PHP 5; after assignment, changes made to one object are reflected in the other as well.
The generic solution is to clone the object:
$date2 = clone $date1;
In this case you could also use the DateTimeImmutable interface (introduced in 5.5) which creates new instances whenever you attempt to modify it, e.g. using ->add().
$date1 = new DateTimeImmutable('2014-04-05');
$date2 = $date1;
$date2 = $date2->add(new DateInterval('P1M'));
echo "Date 1: ".date_format($date1, "Y-m-d")."<br/>";
echo "Date 2: ".date_format($date2, "Y-m-d")."<br/>";
This code can be made easier by doing this:
$date1 = new DateTimeImmutable('2014-04-05');
$date2 = $date1->add(new DateInterval('P1M'));
Related
What is the "cleanest" way to add a date and a time string in PHP?
Albeit having read that DateTime::add expects a DateInterval, I tried
$date = new \DateTime('17.03.2016');
$time = new \DateTime('20:20');
$result = $date->add($time);
Which was no good and returned nothing to $result.
To make a DateInterval from '20:20', I only found very complex solutions...
Maybe I should use timestamps?
$date = strtotime($datestring);
$timeObj = new \DateTime($timestring);
// quirk to only get time in seconds from string date
$time = $timeObj->format('H') * 3600 + $timeObj->format('i') * 60 + $timeObj->format('s');
$datetime = $date+$time;
$result = new \DateTime;
$result->setTimestamp($datetime);
In my case, this returns the desired result, with the correct timezone offset. But what do you think, is this robust? Is there a better way?
If you want to add 20 hours and 20 minutes to a DateTime:
$date = new \DateTime('17.03.2016');
$date->add($new \DateInterval('PT20H20M'));
You do not need to get the result of add(), calling add() on a DateTime object will change it. The return value of add() is the DateTime object itself so you can chain methods.
See DateInterval::__construct to see how to set the intervals.
DateTime (and DateTimeImmutable) has a modify method which you could leverage to modify the time by adding 20 hours and 20 minutes.
Updated
I've included examples for both DateTime and DateTimeImmutable as per the comment made, you don't need to assign the outcome of modify to a variable because it mutates the original object. Whereas DateTimeImmutable creates a new instance and doesn't mutate the original object.
DateTime
<?php
$start = new DateTimeImmutable('2018-10-23 00:00:00');
echo $start->modify('+20 hours +20 minutes')->format('Y-m-d H:i:s');
// 2018-10-23 20:20:00
Using DateTime: https://3v4l.org/6eon8
DateTimeImmutable
<?php
$start = new DateTimeImmutable('2018-10-23 00:00:00');
$datetime = $start->modify('+20 hours +20 minutes');
var_dump($start->format('Y-m-d H:i:s'));
var_dump($datetime->format('Y-m-d H:i:s'));
Output
string(19) "2018-10-23 00:00:00"
string(19) "2018-10-23 20:20:00"
Using DateTimeImmutable: https://3v4l.org/oRehh
I'm new to php and I'm still trying to understand object usage.
This is my script:
$Date1=date_create_from_format('Y-m-d', '2017-01-01');
$Date2=$Date1;
$Date2->modify('last day of');
echo '</br>Date1='.$Date1->format('Y-m-d');//output: Date1=2017-01-31
echo '</br>Date2='.$Date2->format('Y-m-d');//output: Date2=2017-01-31
My goal is to have two different date objects:
the 1st from the string date;
the 2nd containing the last day of the month
How can I do that?
Use clone to create identical copy of object
$Date1=date_create_from_format('Y-m-d', '2017-01-01');
$Date2=clone $Date1;
$Date2->modify('last day of');
echo '</br>Date1='.$Date1->format('Y-m-d');
echo '</br>Date2='.$Date2->format('Y-m-d');
Try this:
$Date2 = clone $Date1;
$Date1 = DateTimeImmutable::createFromFormat('Y-m-d' '2017-01-01');
The method you are using creates a mutable object, but you're looking for an immutable one. The immutable one will return a new date object instead of changing the current one.
See documentation for the DateTimeImmutable class.
Is it possible to clone a DateTime Obj and call a method all in the same statement? I know it can be done on object instantiation. I tried a test script on cloning but it didn't work.
<?php
// instead of
$nextDay = clone $startDate;
$nextDay->add(new DateInterval('P1D'));
// something like this instead
$test = ['test' => (clone $nextDay)->add(new DateInterval('P1D'))];
?>
It is in PHP7, but not in PHP5
$startDate = new DateTime();
$endDate = (clone $startDate)->add(new DateInterval('P7D'));
echo $endDate->format('Y-m-d');
will work in PHP7
EDIT
However, you can get start and end date simply in PHP5 by taking advantage of DateTimeImmutable, where the add() method leaves the original value unchanged, but return a new object:
$startDate = new DateTimeImmutable();
$endDate = $startDate->add(new DateInterval('P7D'));
echo $startDate->format('Y-m-d'), PHP_EOL;
echo $endDate->format('Y-m-d'), PHP_EOL;
this is what I have got:
$_SESSION["chosen_exam_start_time"] = new DateTime();
$schedule_date = $_SESSION["chosen_exam_start_time"];
$schedule_date->setTimeZone(new DateTimeZone('Europe/London'));
$triggerOn = $schedule_date->format('Y-m-d H:i:s');
so I have a date passed within the session called "chosen_exam_start_time".
Now what I am struggling to do is add on $triggerOn.
So currently if I do
die(var_dump($triggerOn));
I get :
string(19) "2016-03-28 17:17:57"
What I want to do is if I have another variable which tells me a value like 10, how would I be able to add that value on to the $triggerOn. So that it will be:
string(19) "2016-03-28 17:27:57"
What I have done up to now is :
$_SESSION["chosen_exam_start_time"] = new DateTime();
$schedule_date = $_SESSION["chosen_exam_start_time"];
$schedule_date->setTimeZone(new DateTimeZone('Europe/London'));
$triggerOn = $schedule_date->format('Y-m-d H:i:s');
$value = 10;
$triggerOn->modify((int) $value.' minute');
die(var_dump($triggerOn));
However this die is not printing anything out now
I doesn't make sense to make any sort of calculation using strings. Just imagine you had this:
$price = 'Thirty five point nine';
$discount = 'Twenty percent';
... and you wanted to apply the discount ;-)
If your current architecture makes it impossible to keep the original DateTime object (I don't know, I don't have enough information for that) you'd better create a new one:
<?php
$triggerOn = '2016-03-28 17:17:57';
$minutes_to_add = 10;
$triggerOnDateTime = new DateTime($triggerOn, new DateTimeZone('Europe/London'));
$triggerOnDateTime->modify( sprintf('%d minutes', $minutes_to_add) );
$triggerOn = $triggerOnDateTime->format('Y-m-d H:i:s');
You are looking for the modify function on a datetime object.
$trigger->modify((int) $value.' minute');
Note I just pulled this from the Carbon Library, which is a very useful wrapper for DateTime giving you a good bit of syntactic sugar such as:
$trigger->addMinutes(10);
I have a date:
$launched=new DateTime();
I would like to create a new DateTime using $launched but adding days. Something like:
$expired=new DateTime($launched->modify("+$expiry days"));
How can I do this?
Assuming you are using PHP 5.5 or newer DateTimeImmutable makes this easy:
$launched = new DateTimeImmutable();
$expired = $launched->modify("+$expiry days");
DateTimeImmutable does not modify the original object which is what DateTime does. So you can just assign the resulting object return by modify() to a variable and have a new object with a date in the future.
If you are using an older, and obsolete, version of PHP you can clone the original object to achieve the same result:
$launched = new DateTimeImmutable();
$expired = clone $launched;
$expired->modify("+$expiry days");