I want to fetch next week data. My date is 2/10/2015 and today is friday. I want to fetch next week data that starts from Monday. I refered this link.
I am using codeigniter so what is the process to write the sql query in codeigniter?
First of you'll need to get the date of the next monday with
$next_monday = new DateTime('next monday');
Then get the end of the week (if you need it):
$date = $next_monday->format('Y-m-d').' 23:59:59'; //Get monday at 23:59
$end_week = strtotime("+7 day", $date); //Get sunday at 23:59
And then in your Codeigniter model, making use of Active Records:
public function nextWeekData($monday, $sunday){
$this->db->where("your_date_field >= '". $monday->format('Y-m-d H:i:s')."' AND your_date_field <= '". $sunday->format('Y-m-d H:i:s')."'");
$this->db->get('your_table');
return $this->db->result_array(); // If you want an array
// return $this->db->result(); // If you want StdClass
}
So the call from your controller should be:
$this->my_model->nextWeekData($next_monday, $end_week);
Just remove $end_week and the second clausule at the WHERE statement in the model if you dont need upper limit.
This should do it, i think. Code not tested. Important: Mind the quotes in the where.
Related
We need to determine "first week of the month". As far as I've read there's no ISO standard for this but I've encountered two definitions:
First week of the month is the week that contains 1st day of the month.
First week of the month is the first full week of that month.
In our application, we are frequently using the ISO week format which is like '2022-W09' that means (obviously) 9th week of 2022.
So, we can easily find first week of the year '2022-W01' and the dates it includes: from 2022-01-03 to 2022-01-09 (according to HTML5 input type week).
And this shows me that (even though I liked and implemented the first definition in the first place) we should accept the second definition because HTML follows that.
As a conclusion, I need an algorithm to find "first week of the month" which I accept to be "the first full week of that month" (2nd definition).
Hereby I put the code I use to find "the week that contains 1st day of the month" which is "first week of the month" in the 1st definition above. You may modify it to suggest a solution:
public function isFirstWeekOfMonth()
{
$carbon = Carbon::create()->setISODate(2022, 9);
$startOfWeekCarbon = $carbon->startOfWeek();
$endOfWeekCarbon = $carbon->endOfWeek();
$startOfMonthCarbon = $carbon->endOfWeek()->startOfMonth();
return $startOfMonthCarbon->betweenIncluded($startOfWeekCarbon, $endOfWeekCarbon);
}
Depending of what you consider a first day of the week, you can do it like this:
I will consider that you consider Monday as a first day of the week.
// Create a date (carbon)
$carbon = Carbon::create()->setISODate(2022, 9);
// Find the first Monday in the month for given date. For Tuesday use 2, Wednesday 3 ...
$firstMondayInTheMonth = $carbon->firstOfMonth(1); // This is also a start of that week
// Find the end of the week.
$endOfTheWeek = $firstMondayInTheMonth->endOfWeek();
In the image below you can see how it works in practice:
With that, you have a first Monday in the month - which means first start of the week, and using endOfWeek you can get Sunday of that week (end of the first week). Using betweenIncluded you can figure out if one date is between that Monday and Sunday of first week in that month.
I have updated my function according to the accepted answer:
public function isFirstWeekOfMonth()
{
$carbon = Carbon::create()->setISODate(2022, 10);
$startOfWeekDate = $carbon->startOfWeek()->format('Y-m-d');
$endOfWeekDate = $carbon->endOfWeek()->format('Y-m-d');
$firstMondayInMonth = $carbon->firstOfMonth(1);
return $firstMondayInMonth->betweenIncluded($startOfWeekDate, $endOfWeekDate);
}
And I have tested it, it is working as expected.
For this week (2022-W09), it's false:
For next week (2022-W10), it's true:
Note: I realized that I was using betweenIncluded() function wrongly, it is accepting dates as parameters, not Carbon objects.
=== FINAL ===
I think I have made the function its best which has the simplest algorithm:
"If the first Monday of the month is equal to first date of this week, then it is the first week of the month."
public function isFirstWeekOfMonth()
{
$currentWeekCarbon = Week::carbon($this->week);
$startOfWeekCarbon = $currentWeekCarbon->startOfWeek();
$firstMondayInMonthCarbon = $currentWeekCarbon->firstOfMonth(1);
return $startOfWeekCarbon->equalTo($firstMondayInMonthCarbon);
}
Again I have tested it, it is working as expected.
I am trying to create an attendance system that calculates tardies based on certain criteria. First off, each student member has a row dedicated to them in the spreadsheet. (Ie, student1's attendance is found on row 3, student2's attendance is found on row 4, etc.). Each student has personal information in the first few columns. Then each student has an attendance record for the meeting. All attendance information comes in pairs with a sign in time and a sign out time.
A student receives a tardy if they show up after 6:30 PM. They also receive a tardy if they are present for less than 2 hours. So I wrote a code to calculate the number of tardies.
/**
each student has one row dedicated to their attendance. Sign in and sign out are always in pairs. I will ensure that the range
begins with range[0][0] being the first sign in time.
#param range the row for the student's attendance
#return the total tardies for each student
**/
function calculateTardies(range){
var search = range[0].length;
var tardies = 0;//initially set to 0
for(k = 0; k<search; k+2){ //go through the entire row of the student's sign in and sign out times (k+2 because they always come in pairs)
var timeIn = new Date(range[0][k]); //sign in time will always be at a K value
var date = Utilities.formatDate(timeIn, "EST", "EEE"); //get the day of week that time stamp is
var timeOut = new Date(range[0][k+1]); //sign out time is to the right of the sign in time
if(date == "Tue" || date == "Wed" || date == "Thu"){ //they only need to be there for 2 hours Tues-Thurs
var checkHour = Number(Utilities.formatDate(timeIn, "EST", "HH")); //The hour student arrived
var checkMin = Number(Utilities.formatDate(timeIn, "EST", "mm")); //The minute student arrived
var outHour = Number(Utilities.formatDate(timeOut, "EST", "HH")); //hour student left
var outHour = Number(Utilities.formatDate(timeOut, "EST", "HH")); // min student left
//If the student wasn't present for at least 2 hours, add a tardy
if((checkHour+2)*60+checkMin < (outHour*60)+outMin){
tardies = tardies+1;
}
//if the student left before 6:30 PM, add a tardy
if((checkHour*60)+checkMin > 1830){ //11100 is 6:30 PM in minutes 6PM=> 18 hours * 60 min = 1080 minutes + 30 additional minutes
tardies = tardies+1;
}
}
}
return tardies;
}
To check if they are there for two hours I had to change the time stamps to minutes. I found that I couldn't simply compare the times as is. The same applies for why I changed the arrival time to minutes before comparing it to 6:30 PM.
I am running into an error that states exceeded maximum execution time (line 0). Any advice on how I can change the code or fix this error would be greatly appreciated.
I am running into an error that states exceeded maximum execution time
You have an endless loop that makes your code run until it exceeds maximum execution time
This endless loop is created by the definition
for(k = 0; k<search; k+2)
depending on what you want to do, the correct syntax is either
for(k = 0; k<search; k=k+2)
(if you want to increase k by 2 after each iteration) or
for(k = 0; k<search; k=k++)
if you want to increase k by 1 after each iteration.
I found that I couldn't simply compare the times as is.
Dates are proceeded in Apps Script the same way like in Javascript.
The documentation provides many useful methods and examples of how to wokr with dates.
In a nutshell:
If you want to calculate the difference between two timestamps - the easiest way might be to convert both dates to ms with getTime(), substract them and convert the difference back to hours (1 h = 1000*60*60 ms)
If you want to know the weekday of a date, you need to use getDay()
For working with dates it is recommendable that they are formatted as such in your spreadsheet, rather than manually converting them from numbers inside your script.
I'm creating a database that I want to use to schedule tasks for random 2-hour windows each day within a given date and time range. For instance, Task1 may run from 1 Jan to 12 Jan anytime between the hours of 5am and 5pm. Therefore, the database will schedule the task for a random 2-hour window (to start no earlier than 5am and stop no later than 5pm) on each of those days. It may throw out something like this for Task1:
Date Start_Time Stop_Time
01 Jan 06:32 08:32
02 Jan 14:24 16:24
03 Jan 08:05 10:05
04 Jan 12:17 14:17
05 Jan 11:23 13:23
06 Jan 12:53 14:53
07 Jan 09:11 11:11
08 Jan 05:27 05:27
09 Jan 12:46 14:46
In addition to the conditions for each Task (must be scheduled each day within a date range and within the given time range), no more than 2 tasks can overlap at any given point on any day, and no task can run into the next day (therefore they cannot start after 10pm).
So far, my database does this, albeit slowly, so I'm wanting to know if the method I'm using is the most efficient.
For tables, I have one (tblWindows) which basically just consists of a column called WindowStart populated with each minute of the day, starting at 00:00 and ending at 23:59. Literally, 1440 records -- one record for each minute of the day.
I have another table (tblTaskConfigs) where I have the configs for each task to be scheduled against. This is where I specify the start/stop dates and start/stop times for each Task to be scheduled.
Finally, my tblSchdTasks table keeps track of when tasks are scheduled.
Regarding the operation, it goes something like this:
Open tblTaskConfigs recordset. For each TaskConfig record:
1) Save the following into variables:
- StartDate
- StopDate
- StartTime
- StopTime
2) For each date the task is to be scheduled on:
A) Using DCount on tblSchdTasks, check if that task has already been scheduled for that date:
- Yes: Skip to the next date
- No:
I) Open a query recordset (qryAvailWin) that contains available windows for that date that fall within the TaskConfig's start/stop times (times from tblWindows in which there are no more than 1 task that overlaps those times).
II) Choose a random record from qryAvailWin to determine the start time of the Task to be scheduled.
III) Open a tblSchdTasks recordset and create a new record for the task and it's randomly-selected time for that day.
So, I'm opening up the tblTaskConfigs recordset, and looping through each record. For each of those records, for each day the Task is to be scheduled for, I'm opening up 2 more recordsets (qryAvailWin & tblSchdTasks) to check available times and to actually schedule the task.
For 1 task that lasts 56 days, this operation takes about 108-113 seconds. I suspect it's because it's opening and closing a total of 113 recordsets (1 + (56 x 2)). Additionally, qryAvailWin has three parameters (CurrDate, StartTime, and StopTime) that I need to set before each time it's opened so that it only shows available windows that are relevant to that date and that TaskConfig.
Can you think of a more efficient way of doing something like this?
Had some time to spare, so I coded my approach to the problem.
Since you're not giving me much to work with as to specifics, you will have to fill in a lot of blanks, such as variable names and WHERE criteria.
First, 2 helper functions for picking random numbers and dates:
Public Function RandomRange(Lower As Double, Upper As Double, Optional IncludeDecimals As Boolean = True) As Double
'Returns a random number between Lower and Upper, either with or without decimals
RandomRange = Lower + (Rnd() * (Upper - Lower + IIf(IncludeDecimals, 0, 1)))
If IncludeDecimals = True Then Exit Function
RandomRange = Int(RandomRange)
End Function
Public Function RandomTime(Lower As Date, Upper As Date) As Date
'Returns a random time between Lower and Upper
Dim randomTimeDbl As Double
randomTimeDbl = CDbl(Lower) + (Rnd() * CDbl(Upper - Lower))
RandomTime = CDate(randomTimeDbl)
End Function
Then, the actual logic to schedule tasks for an interval of days:
Public Function ScheduleTasksBetweenDays(StartDate As Date, EndDate As Date, TaskIdentifier As Variant)
'Open the scheduled tasks table
Dim rsSchdTasks As Recordset
Set rsSchdTasks = CurrentDb.OpenRecordset("SELECT * FROM tblSchdTasks SORT BY Date ASC, Start_Time ASC")
'Second recordset for tasks only on a specific date
Dim rsFiltered As Recordset
'Create a collection to save valid start and end dates
Dim startEndDates As Collection
'And create a collection for overlapping times
Dim overlappingTimes As Collection
'Create two arrays to save start-end date pairs
Dim startEndDatePair(2) As Date
Dim previousTaskStartEndTime(2) As Date
'Create an int to hold random values
Dim randomInt As Integer
'Make an iterator for a while loop, and one for the for loop
Dim dateIterator As Date
Dim i As Integer
dateIterator = StartDate
'Iterate through all the dates
While dateIterator < EndDate
'Set rsFiltered to all records of that date
rsSchdTasks.Filter = "Date = #" & Format(dateIterator, "yyyy\/mm\/dd") & "#"
'Open the filtered recordset
Set rsFiltered = rsSchdTasks.OpenRecordset()
'Use the already instantiated recordset instead of a DCount, if the task is already set, next iteration
rsFiltered.FindFirst "TaskIdentifier = " & TaskIdentifier
If Not rsFiltered.NoMatch Then GoTo NextDate
'Start at the first already set taks, iterate through them
rsFiltered.MoveFirst
'Clean up the overlappingTimes collection
Set overlappingTimes = New Collection
'Initialize the first task as the previous one
If Not rsFiltered.EOF Then
previousTaskStartEndTime(1) = rsFiltered.Fields("Start_Time")
previousTaskStartEndTime(2) = rsFiltered.Fields("End_Time")
rsFiltered.MoveNext
End If
Do While Not rsFiltered.EOF
'If the start time of the next task is less than the end time
If previousTaskStartEndTime(2) > rsFiltered.Fields("Start_Time") Then
'The overlapping segment is from end of previous to start of new
startEndDatePair(1) = rsFiltered.Fields("Start_Time")
startEndDatePair(2) = previousTaskStartEndTime(2)
'Add those that interval to the collection of invalid intervals
overlappingTimes.Add startEndDatePair
End If
previousTaskStartEndTime(1) = rsFiltered.Fields("Start_Time")
previousTaskStartEndTime(2) = rsFiltered.Fields("End_Time")
rsFiltered.MoveNext
Loop
'Now, we have a collection of all times that can't overlap with the task
'Lets set the next collection of possible start times
'First possible start time is 5 AM
startEndDatePair(1) = #5:00:00 AM#
'Open up a blank collection of possible valid intervals
Set startEndDates = New Collection
'Next step seems familliar, loop through the invalid times to calculate the valid ones
For i = 1 To overlappingTimes.Count
'If the start of the next task is more than 2 hours away than the possible start time, we can plan it before this task
If startEndDatePair(1) + #2:00:00 AM# < overlappingTimes(i)(1) Then
'Set the maximum start time to 2 hours before the next task
startEndDatePair(2) = overlappingTimes(i)(1) - #2:00:00 AM#
'Add it to the collection of possible times
startEndDates.Add startEndDatePair
End If
'Set the next possible valid interval to be behind this task
startEndDatePair(1) = overlappingTimes(i)(2)
Next i
'All unchanged since last edit here
'Check if we can put our task behind the last one, if so, last possible start time is 10 PM
If startEndDatePair(1) < #10:00:00 PM# Then
'Set it's maximum end time
startEndDatePair(2) = #10:00:00 PM#
startEndDates.Add startEndDatePair
End If
'Now, we have an array with all possible intervals where our task can start at
If startEndDates.Count = 0 Then
'Apparently, this day is already full and we can't plan the task. Do something adequate for that scenario
GoTo NextDate
End If
'pick a random interval from our intervals array
randomInt = RandomRange(1, startEndDates.Count, False)
'Assign our array to that interval
startEndDatePair(1) = startEndDates(randomInt)(1)
startEndDatePair(2) = startEndDates(randomInt)(1)
'update the schdTasks table
rsSchdTasks.Edit
rsSchdTasks.AddNew
rsSchdTasks.Fields("Date") = dateIterator
'Pick a random start time within our interval
rsSchdTasks.Fields("Start_Time") = RandomTime(startEndDatePair(1), startEndDatePair(2))
'End = 2 hours later
rsSchdTasks.Fields("End_Time") = rsSchdTasks.Fields("Start_Time") + #2:00:00 AM#
rsSchdTasks.Fields("TaskIdentifier") = TaskIdentifier
rsSchdTasks.Update
NextDate:
dateIterator = dateIterator + 1
Loop
End Function
As you may note, the improvements include:
You only open up tblSchdTasks once. Per day you filter the open table and put that into a new recordset
You no longer use DCount, but instead check the already opened table
Instead of just picking random times and checking if they are valid, you make a collection of all possible start and end intervals, then pick one of those intervals, then pick a timepoint within that interval
There is no longer any need for the (imho weird) tblWindows
You now include seconds in your start and end dates
You no longer need qryAvailWin, which was searching a giant table and probably taking up a lot of your time
You've gone from opening 113 recordsets and executing 56 DCounts (which are just as heavy as recordsets) to opening 1 recordset, and filtering and searching it 56 times
And a possible disadvantage:
If the intervals are really unequal in size (one is long, another is short) they both have an equal chance to be picked for the tasks. This isn't too hard to fix, but well, I've put in enough effort I think
I've searched for hours and thought it would be simple but still have no idea.
I'm using access 2010 and have a form to enter the start time of a task. The startTime field is text so that I can use a drop down to select full hours e.g. 11:00; 12:00; 13:00.
How can I set the default value to the next full hour?
If the time is now 12:32 then the default value should be 13:00; if the time is now 14:16 the default value should be 15:00
Edited:
Correct: =TimeSerial(Hour(time())-(Minute(time())>=1);0;0)
You can use CDate() to convert the startTime string to a Date/Time value. Then use DatePart() to get the hour. Give TimeSerial() the hour plus one, and zero for the minutes and seconds. Finally use Format() to convert the resulting Date/Time value back to a string.
Here is an Immediate window session which tests the function included below.
? NextHour("12:32")
13:00
? NextHour("07:00")
08:00
Public Function NextHour(ByVal pStartTime As String) As String
Dim dteStart As Date
Dim dteNext As Date
dteStart = CDate(pStartTime)
dteNext = TimeSerial(DatePart("h", dteStart) + 1, 0, 0)
NextHour = Format(dteNext, "hh:nn")
End Function
I have a form which activates a procedure via an "On form submit" trigger. At the end of this routine I want to insert the difference in time between the form's Timestamp and the current time at the end of the routine (the difference of which is only a matter of a few seconds).
I've tried many things so far, but the result I typically receive is NaN.
I thought that my best bet would be to construct the runtime elements (H,M,S) and similarly deconstruct the time elements from the entire Timestamp, and then perform a bit of math on that:
var rt_ts = Math.abs(run_time - ts_time);
(btw, I got that formula from somewhere on this site, but I'm obviously grasping at anything at this point. I just can't seem to find a thread where my particular issue is addressed)
I've always found that dealing with dates and time in Javascript is tricky business (ex: the quirk that "month" start at zero while "date" starts at 1. That's unnecessarily mind-bending).
Would anyone care to lead me out of my current "grasping" mindset and guide me towards something resembling a logical approach?
You can simply add this at the top of your onFormSubmit routine :
UserProperties.setProperty('start',new Date().getTime().toString())
and this at the end that will show you the duration in millisecs.
var duration = new Date().getTime()-Number(UserProperties.getProperty('start'))
EDIT following your comment :
the time stamp coming from an onFormSubmit event is the first element of the array returned by e.values see docs here
so I don't really understand what problem you have ??
something like this below should work
var duration = new Date().getTime() - new Date(e.values[0]).getTime();//in millisecs
the value being a string I pass it it 'new Date' to make it a date object again. You can easily check that using the logger like this :
Logger.log(new Date(e.values[0]));//
It will return a complete date value in the form Fri Mar 12 15:00:00 GMT+01:00 2013
But the values will most probably be the same as in my first suggestion since the TimeStamp is the moment when the function is triggered...
I have a function which can show the times in a ss with timestamps in column A. It will also add the time of the script itself to the first timestamp (in row 3) and show this in the Log.
Notice that the google spreadsheet timestamp has a resolution in seconds and the script timestamp in milliseconds. So if you only add, say, 300 milliseconds to a spreadsheet timestamp, it might not show any difference at all if posted back to a spreadsheet. The script below only takes about 40 milliseconds to run, so I have added a Utilities.sleep(0) where you can change the value 0 to above 1000 to show a difference.
function testTime(){
var start = new Date().getTime();
var values = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
for(var i = 2; i < values.length ; i++){
Logger.log(Utilities.formatDate(new Date(values[i][0]),Session.getTimeZone(),'d MMM yy hh:mm:ss' )); // this shows the date, in my case same as the ss timestamp.
Logger.log( new Date(values[i][0]).getTime() ); // this is the date in Milliseconds after 1 Jan 1970
}
Utilities.sleep(0); //you can vary this to see the effects
var endTime = new Date();
var msCumulative = (endTime.getTime() - start);
Logger.log(msCumulative);
var msTot = (msCumulative + new Date(values[2][0]).getTime());
Logger.log('script length in milliseconds ' + msTot );
var finalTime = Utilities.formatDate(new Date(msTot), Session.getTimeZone(), 'dd/MM/yyyy hh:mm:ss');
Logger.log ( finalTime); //Note that unless you change above to Utilities.sleep(1000) or greater number , this logged date/time is going to be identical to the first timestamp since the script runs so quickly, less than 1 second.
}