This seems like a fairly simple question, but I'm having trouble with it!
In my database, I have two fields that have times in them. Let's say one field, named clockin, reads "2:29:39 pm," and another field, named clockout, reads "2:29:39 pm."
Then I have two other fields, one titled "breakin" which reads 2:28:37 pm and breakout which reads "2:28:55 pm".
I want to subtract breakout from break in to get the difference, and then take that number and subtract it from the difference between clockin and clockout.
How can I do this? Here's what I've tried:
$clockout = new DateTime($row['clockout']);
$clockin = new DateTime($row['clockin']);
$diff = $clockout->diff($clockin);
$on_the_clock = sprintf('%d hours, %d minutes, %d seconds', $diff->h, $diff->i, $diff->s);
$breakin = new DateTime($row['breakin']);
$breakout = new DateTime($row['breakout']);
$diff2 = $breakout->diff($breakin);
$break = sprintf('%d hours, %d minutes, %d seconds', $diff2->h, $diff2->i, $diff2->s);
That gives me two differences, but then I don't know how to subtract one from the other.
Thanks for any help!
Judging by your existing code I'm assuming your running PHP > 5.3 with the DateTime class.
In which case check out DateTime->sub(). You can use it to subtract the DateInterval returned from the break from clock out. Then do the difference between clock in and clock out. That would give you the total time worked.
I've used strtotime() for such problems. It produces pure number values in the form of the Unix timestamp. I'm not experienced with DateTime() but I prefer Unix timestamps since it represents number of seconds and can be converted back into a string or user-friendly format using date() if necessary.
I find storing Unix timestamps in the database is easier to manipulate as well. A user-friendly format isn't necessary until it needs to be displayed to the user.
[http://php.net/manual/en/function.strtotime.php][1]
Related
Given an arbitrary timestamp (e.g. 2019-02-26 10:30:00) I would like to find the next occurrence of an arbitrary time.
For example, the next occurrence of 12:00:00 will be 2019-02-26 12:00:00 but the next occurrence of 09:00:00 will be the next day at 2019-02-27 09:00:00. The results could be Carbon or Datetime objects. The test time will just be a string as shown.
Is there a way to calculate this in native PHP or PHP Carbon without conditionally boxing in time periods. An obvious way would be to see if the time being tested is past the check time for today, and if it is, taking the result as the check time plus 24 hours (the next day). That feels to me like too much chopping and joining of dates and times, so is there a way to calculate it by considering time to be a simple linear line?
All times will be in a single timezone, with DST. Note: the arbitrary datetimes and check times will stay clear of DST changeovers i.e. 01:00 to 02:00 so hopefully they will not be an issue to take into account.
Short answer is no for PHP (partial answer, I'm no specialist of Carbon but from quick look it's also no, but you can create a macro from following code).
However, with a ternary condition the one-liner is simple enough IMHO (replace the second DateTime($str) with DateTime() if you want to compare with current date and time, and change the >= by > if you want next day when time compared is exactly the same):
$str = '2019-02-26 10:30:00';
$date1 = ( ($a = (new DateTime($str))->setTime(12,00)) >= (new DateTime($str)) ) ? $a : $a->modify('+1 day');
$date2 = ( ($a = (new DateTime($str))->setTime(9,00)) >= (new DateTime($str)) ) ? $a : $a->modify('+1 day');
echo $date1->format('Y-m-d H:i:s'); //2019-02-26 12:00:00
echo $date2->format('Y-m-d H:i:s'); //2019-02-27 09:00:00
quick note: what you gave us is not a timestamp, but a formatted date.
Here is what I am using now through Carbon, which appears to give me the correct results:
$dateTime = Carbon::parse('2019-03-30 17:34:50', 'Europe/London');
$testTime = '16:00:00';
list ($hour, $minute, $second) = explode(':', $testTime);
$nextTimeOccurrence = $dateTime
->copy() // Carbon 1 only
->hour($hour)->minute($minute)->second($second);
if ($dateTime->gt($nextTimeOccurrence)) {
$nextTimeOccurrence = $nextTimeOccurrence->addDay();
}
// $nextTimeOccurrence is the next occurrence of $testTime after $dateTime
The splitting of the time seems clumsy, but might be the best way? The approach is:
Create a timestamp with the test time on the same day as the timestamp I'm checking. This will be the timestamp I am looking for.
If the timestamp I'm checking is after the timestamp created in the previous step, then add a day to it.
I've tested this around DST, and happily Carbon/Datetime keeps the same time when adding a day over a DST period, where a day there would be 25 hours or 23 hours, depending on which way it goes.
I still think there is a more "linear time" way to do this, but this seems simple and robust. Thanks go to #michael-stokoe here at the office for my lead on this.
I am getting some data from some api and I am getting time in following formats/
PT127M
PT95M
which means 127 minutes and 95 minutes respectively.I want to get 127 from this with default functions.Right now I am using shortcut like below
$duration = "PT127M";
$duration = preg_replace("/[^0-9]/","",$duration);
Some one tell me what kind of format is this and if there is any php function available to retrieve the minutes from it.
You can get minutes like this:
$duration = 'PT127M';
$di = new DateInterval($duration);
$minutes = $di->format('%i');
More info here: http://php.net/manual/en/class.dateinterval.php
It might be related to ISO 8601 Duration date format:
To resolve ambiguity, "P1M" is a one-month duration and "PT1M" is a one-minute duration (note the time designator, T, that precedes the time value). The smallest value used may also have a decimal fraction, as in "P0.5Y" to indicate half a year. This decimal fraction may be specified with either a comma or a full stop, as in "P0,5Y" or "P0.5Y". The standard does not prohibit date and time values in a duration representation from exceeding their "carry over points" except as noted below. Thus, "PT36H" could be used as well as "P1DT12H" for representing the same duration. But keep in mind that "PT36H" is not the same as "P1DT12H" when switching from or to Daylight saving time.
You can use DateInterval to parse in PHP:
Here are some simple examples. Two days is P2D. Two seconds is PT2S. Six years and five minutes is P6YT5M.
With this information you can parse your $duration object with this code:
$duration = 'PT127M';
$duration = new DateInterval($duration); // Create a DateInteval Object
echo $duration->format('%i'); // Print minutes from DateInterval Object
I only have basic PHP knowledge and I'm using PHP+Mysql and trying to check the difference in days between 2 dates; the 1st date is formatted by myself in the script as a string:
$f_entrega=$_POST['year1']."-".$_POST['month1']."-".$_POST['day1'];
The second date ($f_dock) which is the one causing the issue is taken from the mysql database which column is in DATE format. To compare the dates I do the following:
if(!empty($_POST["id"])){
$f_entrega=$_POST['f_entrega_a']."-".$_POST['f_entrega_m']."-".$_POST['f_entrega_d'];
$f_entr=$f_entrega;
$mysqli=conectar();
$resultado = $mysqli->query("SELECT id,f_dock FROM pt");
$row = $resultado->fetch_assoc();
for ($i=0;$i<count($ids);$i++){
do{
if ($ids[$i]==$row["id"]){
$f_dock=$row["f_dock"];
break;
}
} while ($row = $resultado->fetch_assoc());
$error=0;
var_dump($f_dock);
$f_dock=strtotime($f_dock);
$f_dock=date('Ymd',$f_dock);
$f_entrega=$f_entr;
$f_entrega=strtotime($f_entrega);
$f_entrega=date('Ymd',$f_entrega);
$f_dock=DateTime::createFromFormat('Ymd',$f_dock);
$f_entrega=DateTime::createFromFormat('Ymd',$f_entrega);
$dias_vendor=date_diff($f_dock,$f_entrega);
$tat=$dias_vendor->format('%R%a');
Sometimes it works correctly, but other times I get Warning: strtotime() expects parameter 1 to be string, object given in [first line] and $tat is not correctly calculated and has strange values.
I've tried different solutions like $f_dock=(string)$f_dock before but finally the convertion always fails in some cases. Thanks in advance for any tip.
The error that you are getting is because the string you are entering is not a valid string for the strtotime() function to convert.
For instance 2015-08-31 will convert just fine, as will today, tomorrow or +7 days.
For more specific help you will need to tell us what the value of $f_dock is (as Marcos says in his comment, var_dump($f_dock) will get you this).
However, on to the solution:
$date1 = strtotime($f_dock); //timestamp in seconds
$date2 = strtotime($f_entrega); //same for the second date
$difference = $date1 - $date2; //difference in seconds between the dates
$days = floor($difference/86400);
86400 is the number of seconds in a day, so find out how many seconds difference there is, then see how many days worth of seconds are in there and use floor() to round the number down. Job done.
With PHP, I am trying to convert a bunch of numbers into a a readable format, the thing is, I have no idea how/what format these are in or can be parsed in using the date() or time() functions in php. there are two of these as well.
(they're built from a total time spent online and time since last log-on)
onlinetime : 1544946 = 2w 3d 21h 9m
lastonline : 1397087222 = 1h 32m
does anyone know the way to get the two different times from the two different timestamps?
If you have a Unix timestamp, take a look at Convert timestamp to readable date/time PHP. The PHP documentation is here: http://php.net/manual/en/function.date.php.
For the online time, you could do modulo arithmetic to figure out the values for each, and then just make a string out of the result. Someone may have a nicer suggestion for this though.
I think John is right, the first is the number of seconds in the timespan listed. And the second certainly looks like a unix timestamp to me. So here's how you can get what you want from these sets of numbers:
1) For the first number, simply divide the number by the seconds in a given time span and use floor():
$timeElapsed = 154496; // in this case
$weeksElapsed = floor($timeElapsed / 604800);
$remainder = $timeElapsed % 604800;
$daysElapsed = floor($remainder / 86400);
etc...
2) For the second number, you can do the same thing by first getting the current timestamp and then subtracting the given timestamp from it:
$lastOnline = 1397087222; // again, in this case
$currentTimestamp = time();
$elapsedSinceLastLogin = $currentTimestamp - $lastonline;
$weeksSinceLastLogin = floor($elapsedSinceLastLogin / 604800);
etc...
I need to compare two dates to show an edit link if it is within 5 mins after the post was made, in PHP. If more than 5 minutes have passed, don't show anything.
$answer_post_date = get_the_time("Y-m-d");
$current_date = date("Y-m-d");
$formated_current_date = strtotime($answer_post_date);
$formated_answer_post_date = strtotime($current_date);
At this point I have two values:
1274414400 ($formated_current_date)
1276056000 ($formated_answer_post_date)
I am not sure what to do next to check if the current date/time is > 5 mins from the answer post date.
Any suggestions would be great.
All I really need the answer to be is a Boolean (yes/no) and if yes, display the minuets left to show the link to edit.
You're only handling dates, how are you supposed to know if the difference is 5 minutes?
Anyway, I'd say the majority of the PHP code that uses the default PHP functions is at least somewhat broken. The problem is you, despite a unix timestamp storing the correct point in time something happens, it does not store timezone information. See here.
So, forget using only date and strtotime. Use the datetime extension.
Store in the database the Unix timestamp and the timezone (by timezone I mean e.g. Europe/Lisbon). Then:
$tz = new DateTimeZone($timezone);
$answer_post_date = new DateTime("$timestamp");
$answer_post_date->setTimeZone($tz);
$current_date = new DateTime("now", $tz);
$diff = $current_date->diff($answer_post_date);
if ($diff->format("a") > 0 ||
$diff->format("h") > 0 ||
$diff->format("m") >= 5) {
//more than 5 minutes have passed
}
Of course, for comparing dates, you can always compare the timestamps.
My understanding of what you need to do:
$delta = ($formated_current_date - $formated_answer_post_date) / 60; // in minutes
if ($delta < 5) {
// show $delta
}
EDIT: Like others pointed out, this alone will not fix all of the issues at hand. As I see it, the smallest change to your current code would be to use a date format with higher granularity - such as "Y-m-d H:i:s". This being enough, like others pointed out, is contingent on the post's date being in the same timezone as your system.
I don't see the need to do a round-trip to a string format and back, regardless of how efficient or reliable it is.
date() will default to calling time() which you can call directly and get the current time in seconds as a Unix epoch timestamp (which is what you're trying to end up with in $formated_answer_post_date). You need to look in the WordPress docs to find the equivalent based on the post's value.
Then you can do a simple comparison of seconds. 5 minutes is 300 seconds.
You will still need to check that the code can assume the timezones of both values will be the same.