I have a MySQL table titled 'my_cal' with a column titled 'start_time' for particular events in the calendar.
The way items are added to the database, there are no overlapping events.
There also may not be an event for a particular day/time either, in this case we leave it blank or put a blank value.
My problem lies in the fact that running 00:01AM to 23:59PM for each day sequentially would be easy, but I want to get the data as:
Mon 00:00, Tues 00:00, Wed 00:00, etc, etc
Mon 01:00, Tues 01:00, Wed 01:00, etc, etc
Mon 02:00, Tues 02:00, Wed 02:00, etc, etc
This is to build a table with 25 Rows (24 hours of the day + 1 for title), and 8 columns (7 days of the week + 1 hourly title)
Here is an example of how the calendar should look as far as HTML Table structure goes:
http://www.wmnf.org/programs/grid
I have made an attempt at getting this to work,
Running through the MySQL results, and saving them as
$data[$hour_of_the_day][$day_of_the_week]
I would then have recursive while() loops for each hour, and then each day,
$hour=0;
while($hour > 24)
{
$day=0;
while($day > 8)
{
if(isset($data[$hour][$day]))
{ echo "event"; }
$day++;
}
hour++;
}
I believe this may get me by, but it does not seem very elegant.
I also wanted the time the calendar started to be 6:00AM, and not 12:00AM.
I wanted the first day listed to be today - 3 (to center the calendar on today)
I.e:
$calendar_begin_day = date("j", mktime()) - 3;
I am looking for any way to make this easier, as I want it to run as efficient as possible due to large hit count.
Thanks
When you retrieve your results, I think you can use the ORDER BY clause and date functions on your to order them by hour and then by day and not the other way round. This way you can iterate on results and avoid storing your data in a php array.
Related
I do need a calculation script for my project which would be calculating 4 things in minutes for me.
Total assigned minutes in working hours for weekdays (Between 08.30 - 17.30)
Total assigned minutes in out of working hours for weekdays (Except 08.30 - 17.30)
Total assigned minutes in working hours for weekends (Between 08.30 - 17.30)
Total assigned minutes in out of working hours for weekends (Except 08.30 - 17.30)
Basically, I am creating and using a schedule Google Calendar actually but doesnt matter, I just have start-end datetime objects in my hand for the employees on a calendar and assigning datetime ranges to employees to make them responsible for answering the customer calls in a certain time range which also could last a week, a few hours, a few minutes or a few days. The thing here is those date ranges are pretty flexible.
I've tried looping over the unix timestamp, creating a DateTime object per loop and check those 4 things but that would have been too much memory&cpu usage as I locked my computer a few times. I would be able to loop over hours in day if the events could only last a day at maximum but they are very flexible so I need a strong algorithm here.
For example a schedule would look like below:
Start(DateTime Object) => 2022-01-27 00:00:00
End(DateTime Object) => 2022-01-29 13:30:00
The function should take those two objects as an argument and should create an output like in the picture I ve shared below. Should be similiar to this:
function createReport(DateTime $employeeWorkStart, DateTime $employeeWorkEnd) : array {
...
return [
'weekday_in-working-hours' => XXX,
'weekday_out-working-hours' => XXX,
'weekend_in-working-hours' => XXX,
'weekday_out-working-hours' => XXX,
]
}
So I need to create a monthly-basis report which shows how many minutes I've assigned for each employee in the schedule.
My working hours are between 08.30 - 17.30, saturday & sunday is considered as weekend.
Example Report Output
So, not able to provide an actual code-answer right now. But how I would approach it is the following:
Get the amount of days between the two dates, subtract weekends. Also subtract one day if the $employeeWorkEnd is the current day (today) and if you want to have extra precision. I found this gist that gives you the working days (weekends and holidays excluded): https://gist.github.com/quawn/8503445
Multiply this by 9 (working hours) and then by 60 to get the total minutes. This is the total time worked.
If you wanted the extra precision in step 1, now just take the difference in minutes between 09:30 and the current time (date_diff can provide this). Add this difference to the total you had so far.
Execute this procedure for every employee you have. The above procedure will not do any loops, I believe it should be possible to do it just by subtraction and multiplication (if you want to exclude holidays using the code in the gist, this will introduce a small loop assuming low amount of holidays).
Your example output shows hours but your description shows minutes. The above story will give you minutes but it's just as easy to get the hours (or milliseconds for that matter).
I am trying to write a php solution to calculate the planned end time considering the target in business hours.
It shouldn't consider some days (retrieved from setting saved in db) such as holidays.
Also business hours are retrieved from db (morning_from (8:30am), morning_to (1:00pm), evening_from (2:30pm), evening_to (6:30pm)).
I want to develop this script because I want that my page shows the remaining time for technical resolution of an opened ticket every day.
For example:
customer having contract with 10 working hours SLA opens a ticket
today (friday) 31/01/2020 16:00:00, considering that in the
noBusinessDays = array("saturday", "sunday") and businessHours set as mentioned before(8:30-13:00/14:30-18:30), the result will have to
be monday 3/02/2020 17:30:00.
Code example:
$noBusinessDays = array("saturday", "sunday");
$businessHours = array("morning_from" => "8:30", "morning_to" => "13:00", "evening_from" => "14:30", "evening_to" => "18:30");
$SLA = "10"; //hours
$ticketDate = new DateTime();
$ticketDate->setTimestamp(strtotime("31/01/2020 16:00:00"));
// I don't know how to use my arrays to say in this calculation how to use them
$maximumLimit = $ticketDate->add(new DateInterval("PT" . $SLA ."H"));
Thank you in advance.
You may use the following function
// intersection of 2 time intervals
// input - Unix timestamps (start,end)
// output - intersection in seconds
function time_union($b_1,$e_1,$b_2,$e_2)
{
return max(0,$e_1-$b_1 - max(0,$e_1-$e_2) - max(0,$b_2-$b_1));
}
You will start with an empty time interval [X, Y) where X is the timestamp of the ticket creation and Y initially is equal to X.
Then you start adding days to Y - one by one. Each time you expand the time interval to contain another day - you use the above function to check how much of the SLA hours are covered (i.e. overlapping) with the working hours in the day you have just added. If the day is marked as a holiday - you simple skip it and continue with the next date.
If you find out that SLA hours are partially covered with either the morning or evening business hours - you should simply subtract the extra hours.
In the end Y will be equal to the timestamp that you want to show in your application.
I think I'd break down the problem into pieces. After calculating the total number of days in the interval, first dispose of the trivial case that it's all happening in one week.
begin by calculating the number of "whole weeks." Each "whole week" is five business days. Subtract the corresponding interval of time and proceed. Now, look at the day-of-the-week of the start-date: each day adds a certain number of days. Then the day-of-week of the end date, likewise. You can then consider hour-of-the-day as needed.
Holidays are a simple table: if the day falls within the range, subtract one day.
Now ... having said all of that, the very first thing that I would do is to search GitHub and SourceForge! Because I am extremely sure that somebody out there has already done this. :-D
"Actum Ne Agas: Do Not Do A Thing Already Done."
Im trying to figure out the most efficient way of calculating statistics using data from MySQL database with dates.
Currently, I use the following syntax
Example:
SELECT sum(Precipitation) from DataTable GROUP BY YEAR(Datetime)
This works perfectly fine, I get the total rainfall for each year. However, now I would like to implement the option to set the beginning of the rain season. In some places, the rain season might begin for example in September. In such case I would need the same calculation, i.e. also grouped by "years", but always since Sep to Aug.
I was thinking about how to do this and the only way I can think of would be somehow calculating the monthly sums and the using PHP try to add them up. But the problem is that that would probably be much slower given there is lots of data and the original script uses just this one line above.
Is there any more efficient way of then getting something like
2014 - xyz inches, 2015 - xyz inches, but where the 2014 would correspond for example to season 2014/2015 etc.
The data in the table is like this: column 1 is always the Datetime and then the actual value, data in 5 minute intervals. I need to maintain the table structure, so I cannot create a different table where the values would be organized differently.
Use this query:
SELECT SUM(Precipitation)
FROM DataTable
GROUP BY YEAR(DATE_SUB(Datetime, INTERVAL 8 MONTH))
This query shifts every date backwards by 8 months, with the result that September 1, 2016 would appear to be the first day of 2016, and August, 2016, would appear to be the last month of 2015.
i'm pretty new to programming and can't seem to figure out my mistake here.
I have a calendar setup, every time a user changes a day I make a new row. This way all changes are logged (again new, id imagine there is a better way.) each row has some displayed information but its primary differentiated by a month a day and a year. IE 1 31 2013 .
I need to get the most recent unique row for each day of the month. So if I run a query for 1/31/2013, I need to return only the most recently created row WHERE month= '1' AND etc.
I'm using..
SELECT t.* FROM(SELECT * FROM calendar a
WHERE NOT EXISTS(SELECT * FROM calendar b
WHERE b.day = a.day AND b.lastaltered > a.lastaltered)) t
WHERE t.month = '12' AND t.year = '2013'
From PHP, if that matters.
Now it works fine if a user makes changes slowly. But I found if someone is quick with it like entering multiple days which end up having a very close time stamp ("lastaltered") it doesn't return that row with my current query. I tested this by modifying the time stamp to a later date and it then returned normally. I hope that explains my problem well enough. I'm still not clear as to why altering the time stamp caused the row to return.
Thank you for your time!
- Jer
Ah ... managing time in a database that doesn't understand what time is (and none of them do).
Go here, read the first book - it explains the intricacies of time and the difficulties of using one data type (DateTime) to represent different concepts:
A fixed instant: 10:15am 4 December 2013 UTC
A recurring instant: 10:15am every day, every Tuesday or the last Monday of a month
An instant defined from an anchor: 2 hours from now
A floating interval: 2 hours
An anchored interval: 2 hours from 10:15am to 12:15pm 4 December 2013 UTC
An instant that does not exist: 2:30 am Sunday 5 October 2014 Australian Eastern Daylight Time
An instant that happens twice 1 hour apart: 2:30am Sunday 6 April 2014 Australian Eastern Daylight Time
... and you get the idea.
The cleanest way to handle your problem is to have a ValidFrom and ValidTo DateTime field, when the user creates the row the ValidFrom is set to now and the ValidTo is set to NULL and a trigger executes that sets all the old entries with a NULL ValidTo to now. This will give a complete audit trail and you can get the current entry by querying for the one with the NULL ValidTo.
Let's say I have a datetime, June 16 2011 at 7:00. I want to be able to check at, say, August 5 2011 at 7:00 and be able to tell that it is exactly a multiple of 1 day since the first date, whereas 7:01 would not count, since it is not an exact multiple.
Another test set: Let's say we have June 16 2011 at 7:00, and I want to check if a particular minute is within an interval of exactly 2 hours since then. So 9:00, 11:00, 13:00, etc. would count, but 9:30 and 10:00 would not. And this could continue for days and months - September 1 at 7:00 would still count as within every 2 hours. (And no, at the moment I don't know how I'm going to handle DST :D)
I thought about it for a moment and couldn't think of anything already existing in PHP or MySQL to do this easily but hell, it could, so I wanted to throw this up and ask before I start reinventing the wheel.
This is on PHP 5.1, sadly.
select *
from test
where datetimefield > '2011-06-16 07:00:00'
and
mod(timestampdiff(second,'2011-06-16 07:00:00',datetimefield),7200) = 0
This example will give you all the records greater than '2011-06-16 07:00:00' where the field is exactly a multiple of 2 hours.
Easiest would be to convert the date/time values into a unix timestamp and then simply do some subtraction/division:
2011-06-16 07:00:00 -> 1308229200
2011-08-05 07:00:00 -> 1312549200
2011-08-05 07:00:01 -> 1312549201
1312549200 - 1308229200 = 4320000 / 86400 = 50 (days)
1312549201 - 1308229200 = 4320001 / 86400 = 50.0000115...
So in other words:
if (($end_timestamp - $start_timestamp) % 864000)) == 0) {
... even multiple ...
}
Same would hold for the day/week comparisons. For months, this'll be out the window, since months aren't nice even figures to deal with.
MySQL Date functions:
http://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html
You can use TIME() to get just the time part of a date. If the time parts are the same it is an exact multiple.
For the two hour thing, one way to do it would be to get the minute/seconds part of the date, make sure those are equal, then make sure that the hour parts of the dates are both even or both odd. For more complicated integer (e.g. 5) hour multiples, you can "fake" doing a mod by dividing the hour parts and checking if the result is an int.
You can compare two DateTime objects via diff() method. Result is a DateInterval object - you can check the exact number of days/hours/minutes between two dates.
It's useless to write your own algorithms if you can use built-in functionality.