Through my searching I've found the following simple logic works really well for ensuring two time ranges don't overlap.
(StartA <= EndB) and (EndA >= StartB)
But it starts to get cumbersome (with my current approach) if I need to use many time ranges. Lots of If statements and such.
So what is a better approach? I've thought about filling arrays corresponding to 15 minute intervals of 'time' and running a check if those array places are 'occupied' when a new time range is added.
This will be using javascript, so I don't know if arrays are the most appropriate/lightweight however.
A straightforward way would be to store the dates in an array, sort it by start date, then check if the dates overlap. Here's a sample:
var dates = [];
var addDate = function(start, end){
dates.push({start: start, end: end});
};
var datesOverlap = function(){
var i;
dates.sort(function(a, b){ return a.start-b.start;});
for(i=0; i<dates.length-1; i++){
if(dates[i].end >= dates[i+1].start){
return true; // dates overlap
}
}
return false; // no dates overlap
};
Add all the dates you want to check with the addDate function. Then you'd call the datesOverlap function to check if any dates overlap.
Related
I'm trying to make a function to set some contents on a cell of a spreadsheet from a data set by user through a prompt.
There are some parts working well and some problems
To put in context, we have a spreadsheet with a "calendar" as follows: every cell in the A:A range is a day of the school year, starting from September/1 in A1, September/2 in A2, and so. In the B column we have for now the holidays, vacation period and other. There are many "stable" days in a school year, such as Christmas day: every year is the same day and month (only changes year). Besides this, there are some days every school (almost in Spain) choose to get a little break.
First, we set function, input range (A column to compare) and output range (B columne, where we want to write new content). (the var year is given as an argument of the function, but is set here for testing)
function setSpecialHolidays() {
var year = 2017;
I had to make a parseInt for this data, because when given as an argument detects it as a string and doesn't work well. But now is ok.
var yearNumber = parseInt(year);
var sheet = SpreadsheetApp.getActive().getSheetByName("Calendar"+year);
var inputRange = sheet.getRange('A1:A'+sheet.getLastRow()).getValues();
var outputRange = sheet.getRange('B1:B'+sheet.getLastRow());
Here start a loop where we can input different days. Every day I set in the prompt the script has to set it in a cell corresponding the date and the content of the A column
I set this ButtonSet before the loop because I need it to start the while, as it will be still working until the user clicks "No" button.
var specialHoliday = ui.alert('Click «Yes» to set a special holidays', ui.ButtonSet.YES_NO);
while (specialHoliday == ui.Button.YES) {
var dayPointer = ui.prompt('Please enter the special holiday date (DD/MM)');
var specialHolidayDate = dayPointer.getResponseText();
var specialHolidayDateParts = specialHolidayDate.split("/");
var date = new Date();
date.setMonth(specialHolidayDateParts[1] - 1, specialHolidayDateParts[0]);
date.setHours(0, 0, 0, 0);
As the school year comprend two different natural years, to make possible Date compare, we need to ensure that if the month is from September to December is the current year, but if the month is from January to July or so is the *current year + 1", this is, the next year. Because of that I make this conditional. This is working well too. I've made some tests and ui.alert to be ensured and detects well the year, if current or next.
if (specialHolidayDateParts[1] <= 8) {
date.setYear(yearNumber + 1);
} else if (specialHolidayDateParts[1] > 8) {
date.setYear(yearNumber);
}
Here is were doesn't work. Once we have set correctly the input date we can start compare it with all values in the inputRange. Then, look every A column cell and, when find a coincidence set in the outputRange the string.
I think there's probably a better solution to this problem, maybe doesn't making a loop, but this is a proccess I've followed before in other functions of this script and that's well for now. This specific date setting is the last step of our program (for now), but I'm
for (var i = 0; i < inputRange.length; i++) {
var dateCompare = new Date(inputRange[i][0]);
if (dateCompare == date) {
outputRange[i][0].setValue("Holiday: special holiday");
}
}
Finally, if user wants to set another day, ButtonSet allows it. When users finish click "NO" instead of yes and everything stops. That's working too.
var specialHoliday = ui.alert('Do you want to set a new special holiday?', ui.ButtonSet.YES_NO);
}
Well, thanks in advance for help.
(Posted on behalf of the OP).
I've made some tries and finally I've found the correct way to do what I want, to set a value in a cell next to a cell that have a date I've compared from a user input date. There was a mistake in the statement:
In a range I can't setValues (but I was trying...)
Is needed to use the .getTime() method on compare the date values
Here is the (I think!) corrected code for the for loop:
for (var i = 0; i < inputRange.length; i++) {
var dateCompare = new Date(inputRange[i][0]);
if (dateCompare.getTime() == date.getTime()) {
outputRange[i][0] = "Holiday: special holiday";
}
}
I finally understood the problem in outputRange: as a range, I can't setValues, because is not a cell, then, I've to assign the value as is. What I'm not sure to get is why I need the .getTime() after every compared value. But it works!
I started learning to code just a couple days ago, and I'm almost finished with my first program. However, I have ran into a problem now at the end, and I can't seem to figure out what's wrong myself.
The program is supposed to help me sort a bunch of dates by week day and time of day. The dates are written "YYMMDD-" and then the time of the day (only hour), e.g. "170109-06".
I have all the dates I want to sort in an array (time), and the following function and loop are supposed to delete all the dates that's not matching a specific year.
Variable clarification:
time - array consisting of dates and time (all the same months but different years. ( e.g. ["161102-03", "151127-11"]
yearDate - the first 4 numbers of the dates that's going to stay in the array.
function checkDate (date) {
var yearMonth = date.slice(0, 4);
var index = time.indexOf(date)
if (yearMonth != yearDate) {
time.splice(index, index + 1);
}
else {
}
}
for (var i = 0; i <= time.length; i++) {
checkDate(time[i]);
}
This code seems to work occasionally, but sometimes a few strings from the array stay there when they're supposed to be deleted, so there's clearly something wrong with the code.
I hope that you'll be able to understand what I mean. I do realize that this post ended up kind of wooly.
Standard mistake. You are deleting items from array while iterating over it. Every time an item is deleted, incrementing the iterator will jump you over the next element, adjacent to the deleted.
Go backwards:
for (var i = time.length - 1; i >= 0; i--) {
checkDate(time[i]);
}
I'm in the process of coding an application that does the following:
Generates a random number with 4 digits.
Changes it once per calendar day.
Won't change that full day. Only once in a day.
I tried:
function my_doubt()
{
var place = document.getElementById("my_div")
place.innerHTML=Math.floor((Math.random()*100)+1);
}
I'm getting a random number with Math.random(). However, I'm rather clueless about how to generate a different number for each day. What are some common approaches for tackling this problem?
Note: It doesn't have to be really random. A pseudo - random number is also OK.
You need to seed the random number generator with a number derived from the current date, for example "20130927" for today.
You haven't been clear about your requirements, so I don't know how random you need (do you have requirements for how uniform of a distribution you need?).
This will generate a random looking 4 digit number which may be good enough for your requirements, but if you perform an analysis you'll find the number isn't actually very random:
function rand_from_seed(x, iterations){
iterations = iterations || 100;
for(var i = 0; i < iterations; i++)
x = (x ^ (x << 1) ^ (x >> 1)) % 10000;
return x;
}
var random = rand_from_seed(~~((new Date)/86400000)); // Seed with the epoch day.
Now that your question is a bit more reasonable, clear and nicer in tone. I can give you a way to get the same result on the client-side. However as others mentioned, to maintain consistency, you probably want to maintain the number on the server to ensure consistency.
var oneDayInMs = 1000*60*60*24;
var currentTimeInMs = new Date().getTime(); // UTC time
var timeInDays = Math.floor(currentTimeInMs / oneDayInMs);
var numberForToday = timeInDays % 9999;
console.log(numberForToday);
// zero-filling of numbers less than four digits might be optional for you
// zero-filled value will be a string to maintain its leading 0s
var fourDigitNumber = numberForToday.toString();
while(fourDigitNumber.length < 4)
{
fourDigitNumber = 0+fourDigitNumber;
}
console.log(fourDigitNumber);
// remember that this number rotates every and is unique for 10000 days
1)create a random number in javascript
2)store in cookie that will expire after one day
3)get value from cookie, if it does not exist goto 1
I have two dates in JavaScript, start and finish, parsed by Moment.js. What would be the most efficient way to swap them if start is posterior to finish without having to create a third date? Typically, the dates would be parameters of a function like this one:
function getDates(start, finish) {
var start_date = moment(new Date(start));
var finish_date = moment(new Date(finish));
if (start_date.diff(finish_date) > 0) {
// Swap code goes here...
}
}
The reason why one might want to swap dates is because some functions are defined in such a way that the same result is returned even if the dates are swapped, yet the function needs to know which date is the earlier one. For example, YEARFRAC in Microsoft Excel works that way. You can see my implementation of that function here for an example of a sub-optimal date swapping.
Thanks in advance for your help!
What would be the most efficient way to swap them if start is posterior to finish
With a third variable. For fun, you could use a destructuring assignment to prevent that work syntactically around that, but this will hardly make a performance difference.
without having to create a third date?
That's the point of using a variable. With the binary operator way you mentioned you would need to cast the Date object to an integer, apply the operation, and then create two new Date objects from the integers.
If your constraint against having an additional Date should be interpreted as not having another variable at all, then I have a solution based on this person's brilliant idea for inline variable swapping:
function getDates(start, finish) {
var start_date = new Date(2013, 0, 5);
var finish_date = new Date(2013, 0, 4);
start_date = start_date.getTime();
finish_date = finish_date.getTime();
start_date = -(finish_date = (start_date += finish_date) - finish_date) + start_date;
start_date = new Date(start_date);
finish_date = new Date(finish_date);
alert(start_date);
alert(finish_date);
}
I'm not sure to have understood what you need but, if you pass the timestamp to start and finish, with something like this:
start_date = start > finish ? finish : start;
finish_date = start > finish ? start : finish;
you swap the values without the third temporary variable. Then you can create the moment objects and work with them. For example:
function dateDiff( start, finish, measure ){
var start_date = start > finish ? finish : start,
finish_date = start > finish ? start : finish;
return moment(finish_date).diff(moment(start_date), measure);
}
dateDiff( new Date(2013,1,21), new Date(2013,1,28), 'days' ) // 7
dateDiff( new Date(2013,1,28), new Date(2013,1,21), 'days' ) // 7
If you need only to know the positive difference you can even do:
date_diff = (start < finish ? finish : start) - (start < finish ? start : finish);
EDIT:
However, it's possible to test that even with ternary operators the performance is lower than the classic if..else statement.
Hope this might be of some help.
We are trying to create a random number generator to create serial numbers for products on a virtual assembly line.
We got the random numbers to generate, however since they are serial numbers we don't want it to create duplicates.
Is there a way that it can go back and check to see if the number generated has already been generated, and then to tell it that if it is a duplicate to generate a new number, and to repeat this process until it has a "unique" number.
The point of a serial number is that they're NOT random. Serial, by definition, means that something is arranged in a series. Why not just use an incrementing number?
The easiest way to fix this problem is to avoid it. Use something that is monotonically increasing (like time) to form part of your serial number. To that you can prepend some fixed value that identifies the line or something.
So your serial number format could be NNNNYYYYMMDDHHMMSS, where NNNN is a 4-digit line number and YYYY is the 4 digit year, MM is a 2 digit month, ...
If you can produce multiple things per second per line, then add date components until you get to the point where only one per unit time is possible -- or simply add the count of items produced this day to the YYYYMMDD component (e.g., NNNNYYYYMMDDCCCCCC).
With a truly random number you would have to store the entire collection and review it for each number. Obviously this would mean that your generation would become slower and slower the larger the number of keys you generate (since it would have to retry more and more often and compare to a larger dataset).
This is entirely why truly random numbers just are never used for this purpose. For serial numbers the standard is always to just do a sequential number - is there any real real for them to be random?
Unique IDs are NEVER random - GUIDs and the like are based on the system time and (most often) MAC address. They're globally unique because of the algorithm used and the machine specifics - not because of the size of the value or any level of randomness.
Personally I would do everything I could to either use a sequential value (perhaps with a unique prefix if you have multiple channels) or, better, use a real GUID for your purpose.
is this what you are looking for?
var rArray;
function fillArray (range)
{
rArray = new Array ();
for(var x = 0; x < range; x++)
rArray [x] = x;
}
function randomND (range)
{
if (rArray == null || rArray.length < 1)
fillArray (range);
var pos = Math.floor(Math.random()*rArray.length);
var ran = rArray [pos];
for(var x = pos; x < rArray.length; x++)
rArray [x] = rArray [x+1];
var tempArray = new Array (rArray.length-1)
for(var x = 0; x < tempArray.length; x++)
tempArray [x] = rArray [x];
rArray = tempArray;
return ran;
}