I am trying to make a function that grabs all the days that have events that are in a database for a certain user. For instance if there were two events on Jan 23, 2013 it would add Jan 23, 2013 to the array. I got it to work so it adds all the days (without adding the same day twice) but now I want to be able to say how many dates are on each day. So on Jan 23, 2013 it would say they have two events in that day.
I hope this makes sense... I have some code for further aid.
PHP Function (grabbing each day that has events)
//gets upcoming days that have events for a user
public function get_upcoming_days_with_events() {
$return_array = array();
$date_in=null;
$user_id = $this->session->userdata('id');
$query =$this->db->select()->from('events')->where('user_id', $user_id)->get();
foreach ($query->result_array() as $event => $row) {
$date = strtotime($row['date_due']);
if (sizeof($return_array) != 0) {
foreach ($return_array as $date_in_array => $row) {
$d = $row['full_date'];
if (date('Y-m-d', $date) == $d) {
//date is already in array
//increment the number of assignments on this day
$row['number_of_assignments'] += 1;
$date_in = true;
} else{
$date_in = false;
}
}
}
if ($date_in == false) {
$return_array[] = array(
'day' => date('d', $date),
'month' => date('m', $date),
'full_date' => date('Y-m-d', $date),
'number_of_assignments' => 1
);
}
}
return $return_array;
}
So with this I want to be able to increment $return_array['number_of_assignments'] if my function notices that a certain day has more than one event.
Let me know if you need any more info...
Thanks! :)
We can save the info in return_array by index of date, if the date info have not been set into return_array, we make an empty info. Each time, we simply increase number_of_assignments.
public function get_upcoming_days_with_events()
{
$return_array = array();
$user_id = $this->session->userdata('id');
$query =$this->db->select()->from('events')->where('user_id', $user_id)->get();
foreach ($query->result_array() as $event => $row)
{
$date = strtotime($row['date_due']);
$date_key = date('Y-m-d', $date);
if (!isset($return_array[$date_key]))
{
$new_item = array(
'day' => date('d', $date),
'month' => date('m', $date),
'full_date' => $date_key,
'number_of_assignments' => 0,
);
$return_array[$date_key] = $new_item;
}
$return_array[$date_key]['number_of_assignments']++;
}
$return_array = array_values($return_array);
return $return_array;
}
Function: array_count_values() can help you with this, it gives total number of occurance of a value in an array.
For example:
$a = array("apple", "banana", "apple");
var_dump(array_count_values($a));
Will output
array(
[apple] => 2,
[banana] => 1
);
So instead of trying to filter out duplicate events, add them all on the array and then use array_count_values() at last to know their occurenses.
Related
how to save the results of the date difference to be saved to the database ?
public function save(){
$item = $this->input->post('item');
$date_in = $this->input->post('date_in'); //date in
$date_out = $this->input->post('date_out'); // date out
$hasil = $date_in->diff($date_out);
//echo $hasil->format('%a'); I will save these results to the database
$data_insert = array(
'item' => $item,
'date_in' => $date_in,
'date_out' => $date_out,
'selisih' => $hasil
);
//url save
}
String don't have method diff, diff is the method of DateTime, you need to change string to DateTime.
And it will return DateInterval object, you can get the total days by format('%a') and insert to database;
$hasil = (new DateTime($date_in))->diff(new DateTime($date_out));
$hasil = $hasil->format('%a');
$data_insert = array(
'item' => $item,
'date_in' => $date_in,
'date_out' => $date_out,
'selisih' => $hasil
);
$this->db->insert('mytable', $data_insert);
If you want to get difference you can get it with Carbon easily using diffInDays Example code for you :
$first = \Carbon\Carbon::createFromFormat('Y-m-d H:s:i', $date_in);
$second = \Carbon\Carbon::createFromFormat('Y-m-d H:s:i', $date_out);
$diff_in_days = $second->diffInDays($first);
Or get it without Carbon :
$first = new DateTime($date_in);
$second = new DateTime($date_out);
$interval = $first->diff($second);
Is there any solutions out there, that make it possible to search in a query.
Example:
I've this simple query:
$this->db->where('start >=',time());
$this->db->where('end <=',strtotime("+1 month"));
$result = $this->db->get('bookings');
What I then want it to be able to make a search that looks like my query above, but which doesn't search in the database, but in the $result results.
So it should be possible to do something like:
$where = array(
'start >=' => time(),
'end <=' => strtotime("+1 day")
);
$get_result_info_by_search = $this->Search_model->get_stored_results($result, $where);
Hope it make sense.
The goal is to reduce the number of calls to the database, because my interval is always the same (I loop through a date range and make the same call for instance 31 times (if 31 days)
This can be done quite easily by looping through the rows and testing 'start' and 'end' values.
/**
* #param CI_DB_result instance $result
* #param array $where with two keys, 'start' and 'end', containing timestamp values, ie.
* $where = ['start' => time(), 'end' => strtotime("+1 month"));
* #return mixed An array of db row objects or NULL if nothing matches
*/
public function get_stored_results($result, $where)
{
$rows = $result->result();
foreach ($rows as $row)
{
if($row->start >= $where['start'] && $row->end <= $where['end'])
{
$matches[] = $row;
}
}
return isset($matches) ? $matches : NULL;
}
If you would rather get back an array of row arrays
public function get_stored_results($result, $where)
{
$rows = $result->result_array();
foreach ($rows as $row)
{
if($row['start'] >= $where['start'] && $row['end'] <= $where['end'])
{
$matches[] = $row;
}
}
return isset($matches) ? $matches : NULL;
}
Might be it will help you
In your controller
$get_result_info_by_search = $this->Search_model->get_stored_results('start','end',$starttime,$endtime);
In your Search Model
function get_stored_results($where1,$where2,$value1,$value2)
`{
Might be it will work for you in your model try to add this code
function get_stored_results($where)
{
foreach($where as $key => $value)
{
$this->db->where($key,$value);
}
$result = $this->db->get('bookings');
}
I want to compare time from db with current time. strtotime for storing time in db is working fine. but when i use strtotime to get current time it is not giving me exact time. i checked that from an online website. here is my code:
This part store time in db:
public function Add($data)
{
foreach ($data['check'] as $key => $value) {
foreach ($value['in'] as $k => $v) {
if(!empty($value['in'][$k])) {
$allocate = array(
'check_in' => strtotime(date('h:i A', strtotime($value['in'][$k]))),
'check_out' =>strtotime(date('h:i A', strtotime($value['out'][$k]))),
//'check_in' => strtotime($value['in'][$k]),
//'check_out' =>strtotime($value['out'][$k]),
'Days_id' => $key,
'User_id' => $data['Users']
);
$this->db->insert('assgin_days',$allocate);
}
}
}
}
This part compare time from db with current time:
public function checkuserlogin()
{
$string = exec('getmac');
$mac = substr($string, 0, 17);
$day_of_week = date('N');
date_default_timezone_set("Asia/Karachi");
$time = strtotime(date('h:i A'));
$timee = date('h:i A');
$id=$this->user_model->userInfo("id");
$data=$this->db->query("SELECT admin.first_name, days.d_name FROM assgin_days INNER JOIN admin ON admin.id= assgin_days.User_id inner join days ON days.D_id= assgin_days.Days_id where assgin_days.User_id = $id and assgin_days.Days_id =$day_of_week and assgin_days.check_in =<$time and assgin_days.check_out >=$time and assgin_days.is_delete=0")->result_array();
}
need to use date('G:i', strtotime($value['in'][$k])), instead of date('H:i', strtotime($value['in'][$k])), it will change the date into 24 hrs formats then it can easily store and comparable.
public function Add($data){
foreach ($data['check'] as $key => $value) {
foreach ($value['in'] as $k => $v) {
if(!empty($value['in'][$k]))
{
$allocate = array(
'check_in' => date('G:i', strtotime($value['in'][$k])),
'check_out' =>date('G:i', strtotime($value['out'][$k])),
'Days_id' => $key,
'User_id' => $data['Users']);
$this->db->insert('assgin_days',$allocate);
}
}
}
}
I have a separate set of functions that grabs a "Date" and a "Time" from my application and puts the date into as a key, and the time as a multi-dimensional value.
For example purposes:
$alldatetimes = array(
'date1' => array('13:00','14:30','14:30','14:30','15:00'),
'date2' => array('09:00','10:00','10:30','10:30','12:00')
);
foreach ($alldatetimes as $date => $times) {
echo '<h1>This Exports:</h1>';
echo '<h2>'.$date.'</h2><br>';
foreach ($times as $time) {
echo $time.'<br>';
}
}
This exports:
date1
13:00
14:30
14:30
14:30
15:00
date2
09:00
10:00
10:30
10:30
12:00
I'm trying to control if the time is put into the array so only one value each is in the array (I don't want 3 instances of 14:30 for that date).
Based on other posts here I tried to build something like this to identify if the value was there, but I can't figure out how to tie it all together:
function searchForId($id, $array) {
foreach ($array as $date => $times) {
foreach ($times as $time) {
if ($time === $id) {
return $time;
}
}
}
return null;
}
Any ideas?
Update: Here is how the array is initially being created - this probably can be more efficient:
while ($schedule_q -> have_posts() ) : $schedule_q->the_post();
$alldatetimes [get_the_date()][] = get_the_time();
endwhile;
You can add a array_unique() call over each sub-array before you loop over your results to ensure it's all unique:
foreach ($alldatetimes as &$row) {
$row = array_unique($row);
}
Output:
<h1>This Exports:</h1>
<h2>date1</h2><br>
13:00<br>
14:30<br>
15:00<br>
<h1>This Exports:</h1>
<h2>date2</h2><br>
09:00<br>
10:00<br>
10:30<br>
12:00<br>
It is not shown in your question, but how about modifying your function that builds the date/time array to use the times as keys instead of values? Using something like
$alldatetimes[$date][$time]++
in that function would give you an array with one value for each time that would be the number of occurrences of that date/time combination, like this:
$alldatetimes = array(
'date1' => array('13:00' => 1,'14:30' => 3,'15:00' => 1),
'date2' => array('09:00' => 1,'10:00' => 1,'10:30' => 2,'12:00' => 1)
);
Then you could change your code that prints them out to use the key.
foreach ($times as $time => $count) {
echo $time.'<br>';
}
You can write a recursive function
function in_array_r($needle, $haystack, $strict = false) {
foreach ($haystack as $item) {
if (($strict ? $item === $needle : $item == $needle) || (is_array($item) && in_array_r($needle, $item, $strict))) {
return true;
}
}
return false;
}
This post almost answered this question for me, but I have a specific need and didn't find what I sought there. This lies right outside my experience; couldn't quite wrap my head around it, so all I really need is a point in the right direction.
Let's say I have an array as follows:
array(5) {
[0]=> "2013-02-18 05:14:54"
[1]=> "2013-02-12 01:44:03"
[2]=> "2013-02-05 16:25:07"
[3]=> "2013-01-29 02:00:15"
[4]=> "2013-01-27 18:33:45"
}
I would like to have a way to provide a date ("2013-02-04 14:11:16", for instance), and have a function determine the closest match to this in the array (which would be "2013-02-05 16:25:07" in this case).
I'd appreciate any tips. Thanks! :)
I may not have the best naming conventions, but here goes.
I calculate the intervals between the array of dates and the given date. I then do a sort, to find the "smallest" difference.
$dates = array
(
'0'=> "2013-02-18 05:14:54",
'1'=> "2013-02-12 01:44:03",
'2'=> "2013-02-05 16:25:07",
'3'=> "2013-01-29 02:00:15",
'4'=> "2013-01-27 18:33:45"
);
function find_closest($array, $date)
{
//$count = 0;
foreach($array as $day)
{
//$interval[$count] = abs(strtotime($date) - strtotime($day));
$interval[] = abs(strtotime($date) - strtotime($day));
//$count++;
}
asort($interval);
$closest = key($interval);
echo $array[$closest];
}
find_closest($dates, "2013-02-18 05:14:55");
If I understand your question perfectly then this will solve your problem.
Tested Code
<?php
$dates = array
(
'0' => "2013-02-18 05:14:54",
'1' => "2013-02-12 01:44:03",
'2' => "2013-02-05 16:25:07",
'3' => "2013-01-29 02:00:15",
'4' => "2013-01-27 18:33:45"
);
function closest($dates, $findate)
{
$newDates = array();
foreach($dates as $date)
{
$newDates[] = strtotime($date);
}
echo "<pre>";
print_r($newDates);
echo "</pre>";
sort($newDates);
foreach ($newDates as $a)
{
if ($a >= strtotime($findate))
return $a;
}
return end($newDates);
}
$values = closest($dates, date('2013-02-04 14:11:16'));
echo date('Y-m-d h:i:s', $values);
?>
Suppose your array is bigger and that you have dates over the period 2009-10-01 to 2019-10-01. Lets now compare two approach: a. looping-array approach vs b. sorting-indexing-array approach.
<?php
$period = new DatePeriod(
new DateTime('2009-10-01 00:00:00'),
new DateInterval('P3D'),
new DateTime('2019-10-01 00:00:00')
);
foreach($period as $date){
$dates[] = $date->format('Y-m-d');
};
$today = '2019-08-18 13:00:15';
function custom_sort($array){
sort($array);
return $array;
}
function nearest_date_key($array, $today){
//push today to the array, sort the array,
//find the nearest day value of the sorted array and return key
array_push($array, $today);
$sorted_dates = custom_sort($array);
$find_today_key = array_search($today, $sorted_dates);
$nearest_date = array_slice($sorted_dates, $find_today_key + 1, 1);
return array_search($nearest_date[0], $array);
}
function find_closest($array, $today)
{
//$count = 0;
foreach($array as $day)
{
//$interval[$count] = abs(strtotime($date) - strtotime($day));
$interval[] = abs(strtotime($today) - strtotime($day));
//$count++;
}
asort($interval);
$closest = key($interval);
return $closest;
}
$start = microtime(true);
$result_a = nearest_date_key($dates, $today);
$time_elapsed_secs_a = microtime(true) - $start;
$start = microtime(true);
$result_b = find_closest($dates, $today);
$time_elapsed_secs_b = microtime(true) - $start;
?>
Printing the results gives (http://phptester.net/)
result time_elapsed
loop approach (a) 1203 0.00630
sorting index approach (b) 1203 0.00062
Which is a huge time elapsed gain. We divided by ten the waiting time
Just try this:
$date = array(
[0]=> "2013-02-18 05:14:54"
[1]=> "2013-02-12 01:44:03"
[2]=> "2013-02-05 16:25:07"
[3]=> "2013-01-29 02:00:15"
[4]=> "2013-01-27 18:33:45");
$baseDate = date_create('2009-10-11');
$count = count($date);
for($loop=0;$count>$loop;$loop++) {
$datetime = date_create($date[$loop]);
$interval = date_diff($baseDate, $datetime);
$newDate[$interval->format('%s')] = $date[$loop];
}
ksort($newDate);
foreach($newDate as $key=>$value) {
echo $value;
break;
}
Your first element will the the closest match date.
Note: Please test it before you use.
This post helped me think of a solution to my similar problem, so am dropping it here.
Given an array of dates, I needed to find the closest date, before or equal, to last Sunday.
Here's what I did without using any custom functions:
$all_dates = [
'20210328',
'20210321',
'20210314',
'20210307',
];
$last_sunday = date( 'Ymd', strtotime( date( 'Ymd' ) . 'last sunday')); //20210321
$latest_date_index;
foreach( $all_dates as $index => $date ) {
$date_obj = date_create_from_format( 'Ymd', $date );
$last_sunday_obj = date_create_from_format( 'Ymd', $last_sunday );
if ( $date_obj <= $last_sunday_obj ) {
$latest_date_index = $index;
break;
}
}
echo "latest date from array: $all_dates[$latest_date_index]";
echo "array of all past dates from array: " . var_dump(array_slice($all_dates, $latest_date_index));
this way also you can get sorted datetime array
function order_date_time($date_times=array(),$compare=null,$action=1){
$interval=0;
$order_date_time=array();
if(empty($date_times)){
return array();
}
foreach ($date_times as $date_time) {
$interval = strtotime($compare)-strtotime($date_time);
$order_date_time[$interval]=$date_time;
}
if(empty($compare)){
krsort($order_date_time);
return isset($order_date_time) && !empty($order_date_time)?array_values($order_date_time):array();
}else{
$order_date_time=array_values($order_date_time);
$compare_index=array_search($compare,$order_date_time);
return $order_date_time[$compare_index+$action]??$order_date_time[$compare_index];
}
}
//input
$array=array
(
2022-02-23 19:58:00
2022-03-02 18:00:00
2022-02-09 18:00:00
)
$close_dat_time=order_date_time($array,'2022-02-23 19:58:00')
// output
2022-02-09 18:00:00