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.
Related
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');
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');
?>
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'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.
I have a date value stored in a variable. I need to extract the time part of the value in to a separate variable and then add/subtract time from it.
The date variable is set with date('YmdHis'), giving (for example) 20110805124000 for August 5th 2011, 12:40:00
From the value 20110805124000 (which is stored in the variable $fulltime), I need to store the time only in the format 12:40 (so ignoring the year, month, day and seconds and adding the colon between the hour and minute) in a variable called $shorttime. I then need to add a number of hours to that time (so for example +3 hours would change the value in the $shorttime variable to 15:40). The number of hours I need to add is stored in a variable called $addtime, and this value could be a negative number.
Is this easily doable? Could anyone help?
Thanks :)
$time = '2013-01-22 10:45:45';
echo $time = date("H:i:s",strtotime($time));
It will give the time 10:45:45 from datetime.
<?PHP
$addhours = 3;
$date = DateTime::createFromFormat('YmdHis', '20110805124000');
$shorttime = $date->format("H:i");
$newdate = $date->add(DateInterval::createFromDateString($addhours . "hours"));
$newtime = $newdate->format("H:i");
echo $shorttime . "<br />";
echo $newtime . "<br />";
?>
for your reference:
http://www.php.net/manual/en/datetime.createfromformat.php
http://www.php.net/manual/en/dateinterval.createfromdatestring.php
hello the way I usually do it is like this, maybe it's a bit long but it works for me...
$DateIn = new DateTime($In);
$DateOut = new DateTime($Out);
$HourOut = new DateTime($H_Out);
$FechaEntrada = $DateIn->format('d-m-Y');
$FechaSalida = $DateOut->format('d-m-Y');
$HoraSalida = $HourOut->format('H:i a');
the guide I used was the PHP one DateTime::format()