I asked a question yesterday in adding together datetime intervals and was pointed to this thread - How we can add two date intervals in PHP
This is great and makes sense. However, when I try to do what the submitted answer says in a foreach loop, I'm ending up with an incorrect result.
This is a function I have made that gets all the clock in times and out times of staff, they are stored in the db and are created using PHP's date(H:i:s).
My function gets all the in and out times of any given employee, and my reporting feature I'm working on needs to display the total amount of hours they have worked.
I tried to achieve this by converting the times to datetime objects and using ->diff to get the intervals and thus calculating that days hours, I am then trying use a foreach loop to add the intervals together thus giving me a sum total of the hours worked in any given date range.
The whole function together is this:
function getTotalHours($staff_id,$from_date,$to_date){
$sql = "SELECT * FROM oc_staff_times WHERE date BETWEEN '$from_date' AND '$to_date' AND staff_id = '$staff_id'";
$result = $this->conn->query($sql);
if ($result->num_rows > 0) {
while ($row = mysqli_fetch_assoc($result)) {
$data[] = $row;
}
$base_time = new DateTime('00:00');
$total = new DateTime('00:00');
foreach ($data as $time) {
$in = new DateTime($time['clock_in_time']);
$out = new DateTime($time['clock_out_time']);
$interval = $in->diff($out);
$base_time->add($interval);
}
return $total->diff($base_time)->format("%H:%I");
}
}
I was hoping to get a monthly total, however it seems I'm only getting one days total as my final result. Here is a screen shot of the UI (the total hours are crudely circled) this also shows the time stamps my function should be adding together.
You can do this in a single query instead. Use TIMEDIFF() to get the difference for each row, then convert those to seconds by using TIME_TO_SEC(), SUM() those up and put it back into time-format with SEC_TO_TIME() - all in MySQL!
SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(`clock_out_time`, `clock_in_time`))))
FROM `oc_staff_times`
WHERE `staff_id` = ?
AND `date` BETWEEN ? AND ?
Making your function with a prepared statement..
function getTotalHours($staff_id, $from_date, $to_date){
$sql = "SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(`clock_out_time`, `clock_in_time`))))
FROM `oc_staff_times`
WHERE `staff_id` = ?
AND `date` BETWEEN ? AND ?";
$stmt = $this->conn->prepare($sql);
$stmt->bind_param("sss", $staff_id, $from_date, $to_date);
$stmt->execute();
$stmt->bind_result($totalTime);
$stmt->fetch();
$stmt->close();
return $totalTime;
}
SQL fiddle showing the query in action http://sqlfiddle.com/#!9/525b83/7
The answer from Qirel offers a nice way to do this in SQL, however if you want to understand why your code didn't work:
$base_time = new DateTime('00:00'); does not create an interval, it's a date. It means that if you add 24 hours to it and ask only the time part, it will show '00:00' because you end up the day after.
One solution would have been to declare $base_time as an interval, for example like this:
$base_time = new DateInterval('PT0S');
And at the end output directly like this:
$base_time->format("%H:%I");
Related
I'm building a system where an user can register activities. However the activities registered can repeat over the course of the year.
In order to prevent having the need that the user has to fill in the form to create an activity multiple times for each different date, I had the idea to add a textbox and a dropdown to the form to allow the user to fill in a frequency. The user can fill in a number in the textbox (for example "2") and select a value from the dropdown (for example "week"). So from that selection the activity has to be added to the database for the next 2 weeks on the same day.
However I have no idea how to let PHP adjust the date and add exactly 7 days to the selected date and repeat the same insert query with the new date, for every week/month/year selected from the given frequency.
EDIT 1:
I've tried this so far:
while ($i> 0)
{
$query2 = $this->db->connection->prepare("INSERT INTO activity(Act_Startdate) values (?)");
$query2->bind_param("s", $Startdate);
$query2->execute();
$Dates = date('d-m-Y', strtotime($Startdate . '+ 1 days'));
$Startdate = date('d-m-Y', strtotime($Dates));
$i--;
}
The first date insertion works, but the second one results 0000-00-00.
Read more about :
Date Time in PHP.
Date Interval in PHP
$numberPostedByUser = $_POST['your_input_name_in_form'];
$currentDate = new \DateTime(); // Getting current date
$iterator = 1;
while ($iterator <= $numberPostedByUser) {
$currentDate->add(new \DateInterval('P1D')); // Adding interval of one day in current date
$startDate = $currentDate->format('Y-m-d H:i:s'); // converting that day in convenient format we required
$query2 = $this->db->connection->prepare("INSERT INTO activity(Act_Startdate) values (?)");
$query2->bind_param("s", $startDate);
$query2->execute();
$iterator++; // increasing iterator for next loop
}
Hope may this code will help you.
I am building a script to display some 24 hour charts. I am attempting to make 12 charts. One 24 hour (last hour) chart for each five minute data set i have collected. I am running accross an issue where my mysql command will not update the $hour_position. I've read many while loop inside while loop questions and have tried to construct a foreach alternative, and also tried to reset the query array, but none of this has worked. Any comments or links to another thread that can solve this problem would be appreciated.
Thanks in advance.
$hour_position = 00;
$htime = -1;
$date = date('Y-m-d H:i:s');
$date = strtotime($date);
$date = strtotime($htime." day", $date);
$date = date('Y-m-d H:i:s',$date);
while($hour_position < 60){
$price_history_qry = mysqli_query($con,"SELECT * FROM `dbTable` WHERE `server_time` > '$date' AND EXTRACT(MINUTE FROM `server_time`) like $hour_position ORDER BY `server_time` ASC");
while($result = mysqli_fetch_array($price_history_qry)){
//Create a couple of arrays to build a chart.
}
//Build chart here
echo $chart;
$hour_position = $hour_position +05;
}
Try putting $hour_position in quote like
' $hour_position '
or you can use
". $hour_position ."
Your query has a small mistake. The variable inside single quotes will not be evaluated as variable. Check this. you need to change the select query like below.
$price_history_qry = mysqli_query($con,"SELECT * FROM `dbTable` WHERE `server_time` > '".$date."' AND EXTRACT(MINUTE FROM `server_time`) like ".$hour_position." ORDER BY `server_time` ASC");
And i haven't find any update query in your code. As you said you are using the update query inside while loop. So first check whether the variable has the value and then check whether it entering to while loop like below.
$result = mysqli_fetch_array($price_history_qry)
var_dump($result);
while($result){
//Create a couple of arrays to build a chart.
var_dump("entered");
}
Try to use var_dump() function to debug.
Hope it helps you.
I want to use a chart on some of my data and generate the values based on selected dates (with a date picker). I've stolen most of the stuff on the web and might have only a simple questions.
Here is the Idiorm query:
if (isset($_GET['start']) AND isset($_GET['end'])) {
$start = $_GET['start'];
$end = $_GET['end'];
$data = array();
// Select the results with Idiorm
$results = ORM::for_table('tbl_data')
->where_gte('date', $start)
->where_lte('date', $end)
->order_by_desc('date')
->find_array();
// Build a new array with the data
foreach ($results as $key => $value) {
$data[$key]['label'] = $value['date'];
$data[$key]['value'] = $value['rev'];
}
echo json_encode($data);
}
The $start and $end are from my datepicker and in yyyy-mm-dd format. The only thing I don't know how to do is how to change the ->where_gte statement. As you can see it's querying the db for the field date. In my db I have three fields, year, month and day.
Is there a way to combing the three fields year, month and day into one expression i.e. maybe ->where_gte('year'&'month'&'day', $start)???
I tried searching and searching but maybe have the wrong keywords or to less knowledge.
Thanks in advance for any help!
Since you have three fields in the DB, you need three where_gte clauses:
...
->where_gte('year', substr($start, 0, 4) // or most suitable date_format
->where_gte('month', substr($start, 5, 2) // or most suitable date_format
...
Hope it helps.
You can manage date format using MySql DATE_FORMAT() Function. E. G.:
// Select the results with Idiorm
$results = ORM::for_table('tbl_data')
->where_gte('date', "DATE_FORMAT($start, '%Y-%m-%d')")
->where_lte('date', "DATE_FORMAT($end, '%Y-%m-%d')")
->order_by_desc('date')
->find_array();
In my project i need time intervals by 15 minutes in my database such as "06.00", "06:15"..
There is a time_id and time_interval column in my time table. I want to keep the time intervals as strings in my database and give everyone of them an id.
I wrote the query below:
mysql_query("INSERT INTO time(time_interval) VALUES('06:00'),('06:15'),('06:30') ...");
and i though there should be a easy way. I googled it a lot bu nothing seem to work. So how do i do this in a short way ?
You can use DateTime to get all times between 2 times:
$dt1 = new DateTime('06:00 UTC');
$dt2 = new DateTime('16:00 UTC');
$values = array();
while ($dt1 <= $dt2) {
$values[] = $dt1->format("('H:i')");
$dt1->modify('+15 minute');
}
And then you can use that array to build your query:
$sql = "INSERT INTO time(time_interval) VALUES " . implode(', ', $values);
print_r($sql);
Demo.
I have a function that is accepting the date and time, and number of occurrences of an episode. I'm using a while loop to try and insert and episode every week on the same day and time. For example if the episode is monday at 7PM, i want to insert in for every monday at 7PM for the number of occurrences given.
Here's my code and while loop:
$sEpsAirDate = strtotime($aVars['air_date'].' '.$aVars['air_time'].$aVars['air_ampm']);
$i = 1;
while ($i <= $aVars['repeat_count']) {
$sEpsAirDate = // How can I alter this variable to change the date to every week?
db_res(
"INSERT INTO `hm_episodes_main` SET
`show_id` = '{$aVars['show_id']}',
`title` = '{$sEpsTitle}.{$i}',
`season` = '{$aVars['eps_season']}',
`uri` = '{$sUri}.{$i}',
`desc` = '{$sEpsDesc}',
`air_date` = '{$sEpsAirDate}'
");
$i++
}
How would I alter the $sEpsAirDate variable to be entered accurately on every day of the week on the given time?
Use mktime():
$next_ep_timestamp = mktime ($hour,$min,$sec, $first_ep_month, $first_ep_day + 7 * $weekcount, $first_ep_year);
"Init" this by setting the respective variables for the date, month and year of the first episode, then you can create new dates for following weeks by adding increments of 7 to the day-parameter in mktime (like shown above).
Then format for output to SQL like this:
$datetime_str = date("Y-m-d H:i:s", $next_ep_timestamp);
//gives a date-str like '2011-10-16 12:59:01'
The first idea that comes to my mind is just adding the seconds in a week to the sEpsAirDate with every iteration in the loop:
$sEpsAirDate += 604800;
If you needed to preserve the first air date you could copy it out into a separate variable and then do something like this (change the LCV $i to start at 0):
$sEpsAirDate = $sEpsFirstAirDate+(604800*$i);
But this method has the potential to create problems with Daylight Savings Time... so it might be safer to break the date into year, month and day variables and then recreate the $sEpsAirDate with every loop iteration by adding ($i*7) to day. ... So something like (again change the LCV $i to start at 0):
$sEpsAirDate = mktime($sEpsAirDateHour, $sEpsAirDateMinute, 0, $sEpsAirDateMonth, $sEpsAirDateDay+($i*7), $sEpsAirDateYear);