How to create split second DateInterval in PHP?
For example:
0.123456 sec
?
interval_spec of DateInterval::__construct
does not have F nor f similarly to DateInterval::format that supports split seconds.
Relative format listing of DateInterval::createFromDateString also does not mention any fraction of a sec.
But the DateInterval class properties listing shows:
f
Number of microseconds, as a fraction of a second.
I was able to get DateInterval with a split second by using the DateTime::diff of two DateTimes with a split seconds
example:
$formatStr = 'Y-m-d H:i:s.u';
$dateTimeStr = '2000-01-01 00:00:00.0';
$timeZone = new \DateTimeZone('UTC');
$timerDateTimeStart = \DateTimeImmutable::createFromFormat($formatStr, $dateTimeStr, $timeZone);
$formatStr = 'Y-m-d H:i:s.u';
$dateTimeStr = '2000-01-01 00:00:00.123456';
$timeZone = new \DateTimeZone('UTC');
$timerDateTimeEnd = \DateTimeImmutable::createFromFormat($formatStr, $dateTimeStr, $timeZone);
$timerDiff = $timerDateTimeStart->diff($timerDateTimeEnd);
$intervalStr = $timerDiff->format('%Y-%M-%D %H:%I:%S.%f');
echo 'Interval (yyyy-mm-dd hh:mm:ss.sfract): ' . $intervalStr;
gives:
Interval (yyyy-mm-dd hh:mm:ss.sfract): 00-00-00 00:00:00.123456
since DateTime supports the split second time_format in its constructor and DateTime::createFromFormat understands
u Microseconds (up to six digits) Example: 45, 654321
BTW: don't you think that u in case of working with the DateTime and F or f in case of DateInterval has a potential for making your day a little bit less boring?
One of my workaround could be to create two DateTime with a split second precision and then diff to get the DateInterval with the same split second precision but I would like to get the same result with just the DateInterval.
Do you know how to create DateInterval having 0.123456 sec by using just the DateInterval?
Solution based on the accepted answer:
$dateInterval = DateInterval::createFromDateString("1 day, 2 hours, 3 minutes, 1 second, 123456 microsecond");
$intervalStr = $dateInterval->format('%D %H:%I:%S.%F');
echo 'Interval (dd hh:mm:ss.sfract): ' . $intervalStr . PHP_EOL;
gives:
Interval (dd hh:mm:ss.sfract): 01 02:03:01.123456
There is a way to do this using DateInterval::createFromDateString:
$di = DateInterval::createFromDateString('123456 microseconds');
var_dump($di);
Output:
object(DateInterval)#1 (16) {
["y"]=>
int(0)
["m"]=>
int(0)
["d"]=>
int(0)
["h"]=>
int(0)
["i"]=>
int(0)
["s"]=>
int(0)
["f"]=>
float(0.123456)
["weekday"]=>
int(0)
["weekday_behavior"]=>
int(0)
["first_last_day_of"]=>
int(0)
["invert"]=>
int(0)
["days"]=>
bool(false)
["special_type"]=>
int(0)
["special_amount"]=>
int(0)
["have_weekday_relative"]=>
int(0)
["have_special_relative"]=>
int(0)
}
Demo on 3v4l.org
From the manual:
time
A date with relative parts. Specifically, the relative formats supported by the parser used for strtotime() and DateTime will be used to construct the DateInterval.
Related
I was trying to find the number of months between two dates using date_diff() in PHP. As we all know the number of months between 2019-03-01 and 2020-01-31 is 11 months, but the following code return 10 months.
$date1=date_create("2019-03-01");
$date2=date_create("2020-01-31");
$diff=date_diff($date1,$date2);
echo $diff->format("%m months");
Output
10 months
Why this code return 1 month less?
If you need the difference in months from the beginning of the first day to the end of the last day at midnight, you can also set the end date to midnight (24h !) or add a day.
<?php
$dateStart = date_create("2019-03-01");
$dateEnd = date_create("2020-01-31");
//set Time to midnight or add a day
$dateEnd->setTime(24,0,0);
$diff = date_diff($dateStart,$dateEnd);
echo $diff->format("%m months");
//11 months
try self.
The difference is 10 months and 30 days, which is what date_diff() returns:
object(DateInterval)#3 (16) {
["y"]=>
int(0)
["m"]=>
int(10)
["d"]=>
int(30)
["h"]=>
int(0)
["i"]=>
int(0)
["s"]=>
int(0)
["f"]=>
float(0)
["weekday"]=>
int(0)
["weekday_behavior"]=>
int(0)
["first_last_day_of"]=>
int(0)
["invert"]=>
int(0)
["days"]=>
int(336)
["special_type"]=>
int(0)
["special_amount"]=>
int(0)
["have_weekday_relative"]=>
int(0)
["have_special_relative"]=>
int(0)
}
ETA as #showdev commented above.
This question already has answers here:
How to calculate the difference between two dates using PHP?
(34 answers)
Closed 5 years ago.
I have this php code to calculate number of days between current date and specific date.
<?php
$query = mysql_query("SELECT * FROM library_users LEFT JOIN students ON library_users.student_id = students.student_id LEFT JOIN books ON library_users.book_id = books.book_id WHERE library_users.student_id <> ''")or die(mysql_error());
while($library_users = mysql_fetch_array($query))
{
$datefrom = date('d-m-Y');
$dateto = $library_users['return_date'];
$datefrom = DateTime::createFromFormat('d-m-Y', $datefrom);
$dateto = DateTime::createFromFormat('d-m-Y', $dateto);
$date_dur = $datefrom->diff($dateto);
$days = $date_dur->format('%d');
}
For now the current date is 27-06-2017; when I input tomorrow's date which is 28-06-2017 I'm getting 1 day which is fine, but when I input 27-07-2017(next month) it is giving me 0 days. How can I solve this?
The problem is that you are using the %d format to get the days, but this will give you the difference in days of a month.
Use %a instead:
$days = $date_dur->format('%a');
http://php.net/manual/en/dateinterval.format.php
a ==> Total number of days as a result of a DateTime::diff()
It works as designed.
DateTime::diff() returns an object of type DateInterval.
A DateInterval object stores the interval in years and subdivisions (months, days, hours, minutes and seconds). You tell it to format() itself using the format "%d".
The %d format specifier means the number of days; not the absolute number of days in the interval but only the days of the last incomplete month.
The format to display the total number of days is "%a":
$days = $date_dur->format('%a');
dumping your object between 27-06-2017 and 27-07-2017 give me this:
object(DateInterval)#4 (15) { ["y"]=> int(0) ["m"]=> int(1) ["d"]=> int(1) ["h"]=> int(0) ["i"]=> int(0) ["s"]=> int(0) ["weekday"]=> int(0) ["weekday_behavior"]=> int(0) ["first_last_day_of"]=> int(0) ["invert"]=> int(0) ["days"]=> int(31) ["special_type"]=> int(0) ["special_amount"]=> int(0) ["have_weekday_relative"]=> int(0) ["have_special_relative"]=> int(0) }
so your are right : it gives you 0 days but 1 month (["m"]=> int(1))
You must use:
$date_dur->days
to get the real days number.
regards.
The goal is to diff two dates.
I have a DateTime object stored in my db table under timestamp column. I use Doctrine to retrieve the date, Once retrieved the date from my db it looked like this by var_dump;
array(1) {
[0]=>
array(1) {
["timestamp"]=>
object(DateTime)#321 (3) {
["date"]=>
string(26) "2016-08-03 11:03:36.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/London"
}
}
}
the retrieved object was assigned to a $result variable now to get to the DateTime object I did this $result[0][timestamp].
To retrieve the actual data i did this $date1 = $result->format('Y-m-d H:i:s'); according to this documentation
So now that i have retrieved the date a row was inserted into my db I need another date as of current time.
i.e:
$date1 = $result->format('Y-m-d H:i:s');
$date2 = new DateTime();
$test = $date1->diff($date2);
diff according to this documentation
this gives me this error:
Error: Call to a member function diff() on a non-object
Any idea why i get this error message looks like am doing things the right way according to the docks. Maybe there is another way do diff two dates OPP way.
UPDATE:
Ok so yes it is true if I use $date1 = $result->format('Y-m-d H:i:s'); its no longer a object its a stiring.
So now my code looks like this:
$test = $result->diff(new DateTime());
var_dump($test);
it returns DateInterval object but what do i make out of it:
object(DateInterval)#317 (15) {
["y"]=>
int(0)
["m"]=>
int(0)
["d"]=>
int(0)
["h"]=>
int(1)
["i"]=>
int(27)
["s"]=>
int(5)
["weekday"]=>
int(0)
["weekday_behavior"]=>
int(0)
["first_last_day_of"]=>
int(0)
["invert"]=>
int(0)
["days"]=>
int(0)
["special_type"]=>
int(0)
["special_amount"]=>
int(0)
What i need if Date1 diff to Date2 is > than 30 mins I want to take some actions.
It is because method format returns string, but not object. Try to use:
$test = $result->diff(new DateTime());
$date1 = $result->format('Y-m-d H:i:s');
$date1 is now a string which doesn't have a format() method.
Try this instead:-
$date1 = $result->format('Y-m-d H:i:s');
$date2 = new DateTime();
$test = $result->diff($date2);
After you do $date1 = $result->format('Y-m-d H:i:s');. $date1 is no more a DateTime object, rather a string representation of date and time.
Hence skip this line. Don't format, and then check for difference. That will give you a DateTimeInterval object.
For anyone who doesn't know what diff() does, it compares two dates and returns the difference -- but unlikely other subtraction methods, diff() never returns a negative value. It doesn't matter if the first date is larger or smaller than the second date.
Now, if that is not a concern for this case, the next step is to access the necessary values in the DateInterval object.
$diff=(array)$date1->diff($date2); // calculate the difference and cast as an array
$labels=array("y"=>"year","m"=>"month","d"=>"day","h"=>"hour","i"=>"minute");
// filter the $diff array to only include the desired elements and loop
foreach(array_intersect_key($diff,$labels) as $k=>$v){
if(($k!="i" && $v>0) || $v>30){
// $labels[$k] = $v > 30 minutes, take some action
}
}
How can I tell if a variable that contains a stampdate like this “2015-05-12 15:32:53” is less or more than an hour comparing it with current timestamp? Is there any good function in PHP that I can use to compare with this time format?
I have this code:
$date = date('Y-m-d h:i:s a', time()); //Current time e.g. "“2015-05-12 13:32:53”
$timetocomp; //Contains “2015-05-12 15:32:53”
My question is how I can compare them to know if 2 hours have passed or not.
Try DateTime
$timetocomp = "2015-06-27 09:10:53"; // its 2015-05-28 08:5x:xx now
$dateTimeToCompare = DateTime::createFromFormat('Y-m-d H:i:s', $timetocomp);
var_dump($dateTimeToCompare);
$dateTimeNoW = new DateTime();
$diff = $dateTimeToCompare->diff($dateTimeNoW);
if($diff->h >= 1 or $diff->d > 0 or $diff->m > 0 or $diff->y > 0) {
echo "difference of at least 1 hour";
} else {
echo "difference less than 1 hour";
}
Edit: My mistake was that I assumed $diff would contain the difference for each size, but its seperated as var_dump($diff) showed.
object(DateInterval)#3 (15) {
["y"]=> int(0)
["m"]=> int(0)
["d"]=> int(30)
["h"]=> int(0)
["i"]=> int(15)
["s"]=> int(13)
["weekday"]=> int(0)
["weekday_behavior"]=> int(0)
["first_last_day_of"]=> int(0)
["invert"]=> int(1)
["days"]=> int(30)
["special_type"]=> int(0)
["special_amount"]=> int(0)
["have_weekday_relative"]=> int(0)
["have_special_relative"]=> int(0)
}
So I updated the If-clause to also chck the days, months and years.
If you are trying to check weather string contains that format or not, try using regular expression and then try figure out the actual date and comparing.
I have a string in this format: 2013-07-31T19:20:30.45-07:00 and I want to parse it so that I can, for example, say what day of the week it is. But I'm struggling to cope with the timezone offset. If I do date_parse("2013-07-31T19:20:30.45-07:00") then I end up with something like this:
array(15) {
["year"]=> int(2013)
["month"]=> int(7)
["day"]=> int(31)
["hour"]=> int(19)
["minute"]=> int(20)
["second"]=> int(30)
["fraction"]=> float(0.45)
["warning_count"]=> int(0)
["warnings"]=> array(0) { }
["error_count"]=> int(0)
["errors"]=> array(0) { }
["is_localtime"]=> bool(true)
["zone_type"]=> int(1)
["zone"]=> int(420)
["is_dst"]=> bool(false)
}
It's done something with the timezone, but what do I do with 420 if I want to, for example, show information about the timezone?
In case it matters, I have previously set my default timezone using date_default_timezone_set('UTC').
UPDATE: If the string has a positive timezone, eg 2013-07-31T19:20:30.45+07:00 then the last part of the date_parse() output is:
["is_localtime"]=> bool(true)
["zone_type"]=> int(1)
["zone"]=> int(-420)
["is_dst"]=> bool(false)
}
420 is zone in minutes.
420/60 = 7
I want to parse it so that I can, for example, say what day of the
week it is.
If you want to know what day of the week it is, you have many options. For example you can use date and mktime-functions:
$parsed = date_parse("2013-07-31T19:20:30.45-07:00");
$unix_timestamp = mktime($parsed['hour'], 0, 0, $parsed['month'], $parsed['day'], $parsed['year'], (int)$parsed['is_dst']);
echo date('l', $unix_timestamp);
So you want to show the information about timezone? You can get the time zone name by using timezone_name_from_abbr function:
$name = timezone_name_from_abbr("", -1*$parsed['zone']*60, false); // NB: Offset in seconds!
var_dump($name);
$timezone = new DateTimezone($name);
var_dump($timezone);
2013-07-31T19:20:30.45-07:00
^ y-m-d ^ time ^ timezone offset
I'm guessing the timezone is -7 hours from UTC.
Keep in mind that some countries have half-hour timezones, or even minute timezones. This is probably why you get the timezone in minutes.