PHP DateTime - modify reference - php

I'm trying to modify a DateTime object in a function passed as an reference:
<?php
$date = new DateTime('2012-02-12');
for($n1 = 0; $n1 < 10; $n1++) {
$date->modify('first day of next month');
setDate($date, 15);
echo $date->format('Y-m-d') . "<br />\n";
}
function setDate(&$date, $day) {
$date->setDate($date->format('Y'), $date->format('m'), $day);
}
?>
But the result is not as expected. Did I got something wrong with this references stuff?
EDIT:
Expected result:
2012-03-15
2012-04-15
...
Result with function above:
2012-03-01
2012-04-01
...

My PHP didn't like the 'first day of nest month' bit, but worked with '+1 month'. Since you are setting the day absolutely I wouldn't worry about it not being on the first. Or if it needs to be you can set it to the first before you go into the loop.
So, this worked for me. I added the new DateTimeZone('America/New_York') so it would stop bugging me about it not being set (shared server.) And removed the pass by reference (&) bit since all objects are passed by reference by default in PHP now.
<?php
$date = new DateTime('2012-02-12',new DateTimeZone('America/New_York'));
for($n1 = 0; $n1 < 10; $n1++) {
$date->modify('+1 month');
setDate($date, 15);
echo $date->format('Y-m-d') . "<br />\n";
}
function setDate($date, $day) {
$date->setDate($date->format('Y'), $date->format('m'), $day);
}
?>

You are already passing a reference to the DateTime object. There is no need to pass an instance of DateTime implicitly as a reference. If you need a copy of the DateTime object, you will need to use clone keyword.
As far as the result, it iterates over 15th of every sequential month, which, reading the code, I expected to be the outcome.

Related

How to insert in a wordpress page a widget that shows days since a specific order was made?

I have to output this information but I am not used to work with PHP, donĀ“t know what I am doing wrong.
I query woocommerce order date like this:
$order = wc_get_order(456);
$orderdate = $order->date_created;
That seems to be working ok, it returns a date in this format:
2020-10-15T17:38:37-03:00
For current date, I create a variable like this:
$date = date('d-m-y h:i:s');
But when I try to output the difference in days between order date and current, it always give me 0
This is how I tried to calculate the difference:
function dateDiff($date1, $date2)
{
$date1_ts = strtotime($date);
$date2_ts = strtotime($orderdate);
$diff = $date2_ts - $date1_ts;
return round($diff / 86400);
}
$dateDiff = dateDiff($date1, $date2);
echo ("day difference is: " . $dateDiff );
Thanks a lot for reading, hope you can help me.
Short explanation of what is wrong with your code:
$dateDiff = dateDiff($date1, $date2);
In your case dateDiff is a function which expects two parameters $date1 and $date2. But you are passing non existing variables to the function. They do not exist out of the function scope, because you didn't declare them.
Then you are trying to get timestamps from dates which are in parent scope and probably getting NULL as a result from both cases :)
$date1_ts = strtotime($date);
$date2_ts = strtotime($orderdate);
Small improvements:
Its better to use DateTime class when you are working with dates. DateTime class has powerful method called format that allows you to output date in suitable format for you.
If we combine what you did into one piece of code with some changes, then we will get this:
$order = wc_get_order(456);
$order_date = new DateTime($order->date_created);
$current_date = new DateTime();
function dateDiff($date1, $date2)
{
// check if diff is not equal to zero in order to avoid division be zero exception
if ($diff = abs(strtotime($date2) - strtotime($date1))) {
return round($diff / 86400);
}
return 0;
}
echo ("day difference is: " . dateDiff(
$current_date->format('d-m-Y h:i:s'),
$order_date->format('d-m-Y h:i:s')
) . " days");

About the order of variable declaration in PHP

I've tried the following code in php :
<?php
$year=1900;
$month=1;
$tmp = date_create_from_format("Y-n-d",$year."-".$month."-01");
$start_datetimeobject = $tmp;
$end_datetimeobject = date_add($tmp, date_interval_create_from_date_string("1 month"));
$end_datetimeobject = date_sub($end_datetimeobject,date_interval_create_from_date_string("1 day"));
$end_date = date_format($end_datetimeobject,"Y-m-d");
$start_date = date_format($start_datetimeobject,"Y-m-d");
echo "Start = ",$start_date;
echo nl2br("\n");
echo "End = ",$end_date;
?>
and got the following result :
Start = 1900-01-31
End = 1900-01-31
... which I find surprising.
Now if I modify my code to define the $start_date variable immediately after having assigned the datetime object :
<?php
$year=1900;
$month=1;
$tmp = date_create_from_format("Y-n-d",$year."-".$month."-01");
$start_datetimeobject = $tmp;
$start_date = date_format($start_datetimeobject,"Y-m-d");
$end_datetimeobject = date_add($tmp, date_interval_create_from_date_string("1 month"));
$end_datetimeobject = date_sub($end_datetimeobject,date_interval_create_from_date_string("1 day"));
$end_date = date_format($end_datetimeobject,"Y-m-d");
echo "Start = ",$start_date;
echo nl2br("\n");
echo "End = ",$end_date;
?>
... it works as I expected :
Start = 1900-01-01
End = 1900-01-31
Can someone explain me why ? I am not very familiar with PHP but have practiced Perl in the past, and I don't understand what happens ...
This is due to date_add altering its received date in place. I'd highly recommend using DatetimeImmutable instead whenever possible to avoid such situations. It will ensure (as the class name indicates) that your dates can never be altered (methods will return altered copies instead).
Let's take the relevant lines of your first sample, one by one:
$tmp = date_create_from_format("Y-n-d",$year."-".$month."-01");
This creates a DateTime object and binds the $tmp variable to it.
$start_datetimeobject = $tmp;
This makes $start_datetimeobject reference the same object as $tmp (so, that same date), since objects are copied "by reference" in PHP.
$end_datetimeobject = date_add($tmp, date_interval_create_from_date_string("1 month"));
This adds 1 month to the date referenced by $tmp, modifying it. Since $start_datetimeobject references the same object, it will now reference the +1 month date as well.
Therefore, when you do this a few lines further:
$start_date = date_format($start_datetimeobject,"Y-m-d");
The start date is based on an unwanted $start_datetimeobject date.
This doesn't happen in your second sample because by doing that last line first,
it happens before $start_datetimeobject gets modified.

Missing Week in PHP's DateTime->modify('next week')

I think I am fully aware of ISO 8601 and that the first week of a year is the week that has a Monday in it. However I came across a strange behavior in PHP (5.6) DateTime Class.
Here is my code:
$start = new DateTime('2009-01-01 00:00');
$end = new DateTime();
$point = $start;
while($point <= $end){
echo $point->format('YW');
$point = $point->modify('next week');
}
This puts out correctly
200901
200902
200903
...
But if I pick as a start date something earlier in 2008 like $start = new DateTime('2008-01-01 00:00'); then I get a different result:
...
200852
200801 // <=== 2008??
200902
200903
...
Is this a PHP bug or am I'm missing something here?
Tinkered with this and finally figured it out
$start = new DateTime('2008-12-29 00:00');
$end = new DateTime('2009-01-7 00:00');
$point = $start;
while($point <= $end){
echo $point->format('YW') . "\t";
echo $point->format('m-d-Y') . "\n";
$point = $point->modify('next week');
}
So the first date here is 2008-12-29. Thus Y is correct. But 2008-12-29 is also week 1. So the W is also correct
https://3v4l.org/JZtqa
It's not a bug! Inspired by #Machavity and based on this this similar question I found a solution:
echo $point->format('oW');
instead of
echo $point->format('YW')
produces:
...
200852
200901
200902
...
no matter when the start date is. It's really a RTM case, as the PHP manual states:
o ==>
ISO-8601 year number. This has the same value as Y, except that if the
ISO week number (W) belongs to the previous or next year, that year is
used instead. (added in PHP 5.1.0)

Why is my while loop not working when no echo is put inside?

I got a pretty simple code that will take 2 dates and loop my data until the end date is reached.
$start = new DateTime($senddate);
$now = new DateTime("NOW");
$end = new DateTime ($end);
//We check if starting date is >= now()
if ($start->date <= $now->date){
$start = $now;
}
$i=0;
if ($frequency==4){
while ($start->date <= $end->date) {
$calcdate[$i]=$start->date;
$start->modify('+1 month');
$i++;
echo '<!--';
print_r($start);
echo '-->';
}
As you see there is a print_r inside the loop.
Everything work fine :)
BUT, if I remove it, then the loop never end .. I tried to add if($i>50) exit; without anymore success. I don't understand why this loop doesn't work when no pint_r is inside.
Thanks for your help
I would suggest that you have a read of the PHP DateTime manual, there is a lot of good information there that will help you with what you are trying to do.
As far as I can tell, you are trying to carry out an operation on a monthly basis between two dates that span the current date. There is a simpler way of doing it utilising the DatePeriod class.
Something like this:-
$start = new \DateTime('yesterday');// Just for demo purposes
$now = new \DateTime(); //No need for "now" as it is the default
$end = new \DateTime('+ 6 month');// again, for demo purposes
$interval = new \DateInterval('P1M');
if($now >= $start){ // you can do direct comparisons on DateTime objects
$period = new \DatePeriod($start, $interval, $end);
foreach($period as $date){
// Each $date is a DateTime instance that you can
// operate on as you see fit, I have just var_dumped it out.
var_dump($date);
}
}
The above code can be seen working here http://3v4l.org/1I30E
My error came from this line $calcdate[$i]=$start->date;
It seems that this gives somme unexpected behavior (in this case), I tried using $calcdate[]=$start->format('Y-m-d H:i:s'); which gave the expected results ... Don't know why my script didn't worked with the date method. If anyone knows ..

I am trying to do looping but I can't

I am trying to make for loops using date function but I can't. In my case, I am trying to loop 2001-feb to 2009-jan and want to insert date but I can't. Can anyone help me? Here is my code:
for($start_year; $start_year<= $end_year; $start_year++)
{
for($start_month; $start_month<= $end_month; $start_month++)
{
$date_input = $start_year."-".$start_month."-27";
}
}
Looks like PHP.
for($start_year; $start_year<= $end_year; $start_year++)
You've not specified a starting value for $start_year, so unless you've defined that variable elsewhere, this is a syntax error. As well, since you're starting/ending on different months, you can't really use a loop for that without jumping through hoops. You'd probably be better off with something like this:
$date = strtotime("2001-02-01 00:00:00");
$end = strtotime("2009-01-01 00:00:00");
do {
echo date('Y-m', $date), "-27";
$date = strtotime("+1 month", $date);
} while ($date <= $end);
Note that strtotime is only one way of doing this. You could use the DateTime object with a 1-month DateInterval, but that's for PHP 5.3+ only.

Categories