Creating date list from start_date & end_date input - javascript

I'm trying to create a range of dates that can be parsed by daily or weekly granularity and have hit a roadblock. I have a function that allows you to enter a start month,start year, end month, end year, and granularity and returns the date range according to the granularity.
I am able to run this successfully for daily granularity, but when running for weekly granularity, every new month restarts at 1. Looking at the below example:
2015-11-01 2015-11-08 2015-11-15 2015-11-22 2015-11-29 2015-12-01 2015-12-08 2015-12-15 2015-12-22 2015-12-29 2016-01-01 2016-01-08
I would like it to appear as:
2015-11-01 2015-11-08 2015-11-15 2015-11-22 2015-11-29 2015-12-06 2015-12-13 2015-12-20 2015-12-27 2016-01-03
I understand why this is happening - at the end of each for loop the variable "d" is force set to 1. I tried to add additional if statements after the "dates.push(y+"-"+m+"-"+d)" but I know that is really inefficient coding. I added the snippit of what I tried below:
if monthday(m,y) – d < 7 {
d = monthday(m,y) –d
if m = 12 {
m = 1
y = y+1
else {
m = m+1
}
}
The functions used are copied below.
Any insight into how I could do this would be much appreciated!
/// Function to decide how many days in a month
function monthday (month,year) {
var months31 = [1,3,5,7,8,10,12]
var months30 = [4,6,9,11]
var leapyear = [2016,2020,2024,2028,2032] /// if this code is still being used in 2036 I'll eat my hat
if (months31.indexOf(month) >=0){
var result = 31}
else if (months30.indexOf(month) >=0){
var result = 30}
else if (month==2 && leapyear.indexOf(year) >=0){
var result = 29}
else if (month==2 && year != 2016){
var result = 28}
return result
}
////Date Range - calculates # of days/weeks between 2 date ranges
function dateRange (start_month,start_year,end_month,end_year,granularity) {
var dates = [];
var d0 = [start_year,start_month];
var d1 = [end_year,end_month];
switch (granularity) {
case "Daily":
for (var y = d0[0]; y <= d1[0]; y++) {
if ((y == d0[0]) && (d0[0] != d1[0])) { // if year=start_year && year != end year ... start from start_month and loop up to month 12
for (var m = d0[1]; m <= 12; m++) {
for (var d =1;d <= monthday(m,y); d++) {
dates.push(y+"-"+m+"-"+d)
}
}
}
if ((y != d0[0]) && (y!= d1[0])) { // if year != start_year && year != end year .... start from month 1 to month 12 - this would 2015 data in pulling Dec 2014 - April 2016
for (var m = 1; m <= 12; m++) {
for (var d =1;d <= monthday(m,y); d++) {
dates.push(y+"-"+m+"-"+d)
}
}
}
if ((y != d0[0]) && (y == d1[0])) { // if year !=start_year && year = end_year .... start from month 1 up until end_month
for (var m = 1; m <= d1[1]; m++) {
for (var d =1;d <= monthday(m,y); d++) {
dates.push(y+"-"+m+"-"+d)
}
}
}
if ((y == d0[0]) && (y == d1[0])) { /// if year=start_year && year = end_year .... start from start_month to end_month
for (var m = d0[1]; m <= d1[1]; m++) {
for (var d =1;d <= monthday(m,y); d++) {
dates.push(y+"-"+m+"-"+d)
}
}
}
}
break;
case "Weekly":
for (var y = d0[0]; y <= d1[0]; y++) {
if ((y == d0[0]) && (d0[0] != d1[0])) { // if year=start_year && year != end year ... start from start_month and loop up to month 12
for (var m = d0[1]; m <= 12; m++) {
for (var d =1;d <= monthday(m,y); d+=7) {
dates.push(y+"-"+m+"-"+d)
}
}
}
if ((y != d0[0]) && (y!= d1[0])) { // if year != start_year && year != end year .... start from month 1 to month 12 - this would 2015 data in pulling Dec 2014 - April 2016
for (var m = 1; m <= 12; m++) {
for (var d =1;d <= monthday(m,y); d+=7) {
dates.push(y+"-"+m+"-"+d)
}
}
}
if ((y != d0[0]) && (y == d1[0])) { // if year !=start_year && year = end_year .... start from month 1 up until end_month
for (var m = 1; m <= d1[1]; m++) {
for (var d =1;d <= monthday(m,y); d+=7) {
dates.push(y+"-"+m+"-"+d)
}
}
}
if ((y == d0[0]) && (y == d1[0])) { /// if year=start_year && year = end_year .... start from start_month to end_month
for (var m = d0[1]; m <= d1[1]; m++) {
for (var d =1;d <= monthday(m,y); d+=7) {
dates.push(y+"-"+m+"-"+d)
}
}
}
}
break;
}
return dates
}

You don't need to control the month length, let Date object do it for you.
function formatDate(date) {
return date.getFullYear() + '-' + ('0' + (date.getMonth() + 1)).substr(-2) + '-' + ('0' + date.getDate()).substr(-2);
}
function dateRange (start_month,start_year,end_month,end_year,granularity) {
var date = new Date(start_year + '-' + start_month + '-01');
var endDate = new Date(end_year + '-' + end_month + '-01');
var arr = [];
while(date < endDate) {
arr.push(formatDate(date));
switch (granularity) {
case 'Daily':
date.setDate(date.getDate() + 1); // date++
break;
case 'Weekly':
date.setDate(date.getDate() + 7); // week++
break;
case 'Monthly':
date.setMonth(date.getMonth() + 1);
break;
// ...
}
}
return arr;
}
Is it something you were looking for?

Related

Javascript array provide all days/months between two date ranges

I'm trying to create a function that will accept three input variables (start date, end date, granularity) and will output an array with all dates in between. The output will be either daily or monthly granularity based on the input. For example, if I'm looking at Jan 2015 - Feb 2015:
Monthly will be [2015-01, 2015-02]
Daily will be [2015-01-01, 2015-01-02, 2015-01-03, ....,2015-02-27, 2015-02-28]
I've coded something based off some other posts and logically it seems like it should work to me, but for some reason when looking at daily granularity every month returns with 31 days. The below script only looks at the daily granularity (monthly will be easier to do) - can someone take a look and see what I'm doing wrong, and if there is a more efficient way to do this?
Input format for dates are "yyyy-mm"
I realize this is probably a rookie mistake, but at least I'll learn :)
Thanks
function dateRange2 (startDate,endDate,granularity) {
var dates = [];
var d0 = startDate.split('-');
var d1 = endDate.split('-');
var months31 = [1,3,5,7,8,10,12];
var months30 = [4,6,9,11];
for (var y = d0[0]; y <= d1[0]; y++) {
for (var m = d0[1]; m <= d1[1]; m++) {
if (m in months31) {
for (var d =1;d <=31; d++) {
dates.push(y+"-"+m+"-"+d);
}
} ///// Issue seems to be here - not switching over to next clause
else if (m in months30) {
for (var d =1; d <=30; d++) {
dates.push(y+"-"+m+"-"+d);
}
} else if (m=2 && y=2016) {
for (var d =1; d <=29; d++) {
dates.push(y+"-"+m+"-"+d);
}
} else if (m=2 && y!=2016) {
for (var d =1; d <=28; d++) {
dates.push(y+"-"+m+"-"+d);
}
}
}
}
return dates;
}
instead of in operator, use indexOf as below:
if (months31.indexOf(m) >= 0){
}
else if (months30.index(m) >= 0){
}
in operator will return whether a given value is a property of object or not:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in
Others have shown how to fix your code. To answer "more efficient" is difficult since you haven't provided criteria for that. But if you want robust code with separation of concerns, consider separate functions to parse date strings, format the dates and to calculate the ranges.
There are many small libraries for parsing and formatting dates that are handy if you have many different formats to accommodate, but if not then the following simple functions should suit.
If the documentation and comments are sufficient, please ask and I'll provide updates.
/* Parse date string in ISO 8601 format as local
** #param {string} s - Date string like 2016-04-01
** #returns {Date} If date is invalid, returns an invalid Date
*/
function parseISODate(s) {
var b = s.split(/\D/);
var d = new Date(b[0], b[1]? b[1] - 1 : 0, b[2] || 1);
return d && d.getMonth() == b[1] - 1? d : new Date(NaN);
}
/* Return an ISO 8601 formatted date string based on local time
** Only works for positive years (i.e. doesn't do -ve year)
** #param {Date} date - date object to create date string from
** #returns {string} dates string in yyyy-mm-dd format or default from
** Date.prototype.toString (i.e. "Invalid Date")
*/
function toISODate(date) {
return date.getDate()? ('000' + date.getFullYear()).slice(-4) + '-' +
('0' + (date.getMonth() + 1)).slice(-2) + '-' +
('0' + date.getDate()).slice(-2) : date.toString();
}
/* Generate an array of ISO 8601 formatted date strings for a
** range of dates inclusive of start and end. Either monthly
** or daily intervals (default is daily).
** #param {string} fromDate - start date in ISO 8601 format
** #param {string} toDate - end date in ISO 8601 format
** #param {boolean} monthly - return monthly intervals
** #returns {Array} of date strings. If either fromDate or
** toDate are invalid, returns undefined.
*/
function genDatesInRange(fromDate, toDate, monthly) {
var s = parseISODate(fromDate);
var e = parseISODate(toDate);
var dates = [];
// Check that dates are valid
if (!s.getDate() || !e.getDate()) return;
// If monthly, set start to 1st of start month and e to 1st of end month
if (monthly) {
s.setDate(1);
e.setDate(1);
}
while (s <= e) {
dates.push(monthly? toISODate(s).substr(0,7) : toISODate(s));
if (monthly) {
s.setMonth(s.getMonth() + 1);
} else {
s.setDate(s.getDate() + 1);
}
}
return dates;
}
// Daily
console.log(genDatesInRange('2015-05-23','2015-06-03')); // Daily
console.log(genDatesInRange('2015-09-03','2016-03-13', true)); // Monthly
Figured it out after some trial and error - it may not be the prettiest code but it does the job... ideally I'd have added each commented line as part of a separate function.
I also noticed that each case works using four "if" arguments without requiring "else if".
function dateRangetest (start_month,start_year,end_month,end_year,granularity) {
var dates = [];
var d0 = [start_year,start_month];
var d1 = [end_year,end_month];
// var d0 = [2014,6] FOR TESTING
// var d1 = [2016,4]
switch (granularity) {
case "Daily":
for (var y = d0[0]; y <= d1[0]; y++) {
if ((y == d0[0]) && (d0[0] != d1[0])) { // if year=start_year && year != end year ... start from start_month and loop up to month 12
for (var m = d0[1]; m <= 12; m++) {
for (var d =1;d <= monthday(m,y); d++) {
dates.push(y+"-"+m+"-"+d)
}
}
}
if ((y != d0[0]) && (y!= d1[0])) { // if year != start_year && year != end year .... start from month 1 to month 12 - this would 2015 data in pulling Dec 2014 - April 2016
for (var m = 1; m <= 12; m++) {
for (var d =1;d <= monthday(m,y); d++) {
dates.push(y+"-"+m+"-"+d)
}
}
}
if ((y != d0[0]) && (y == d1[0])) { // if year !=start_year && year = end_year .... start from month 1 up until end_month
for (var m = 1; m <= d1[1]; m++) {
for (var d =1;d <= monthday(m,y); d++) {
dates.push(y+"-"+m+"-"+d)
}
}
}
if ((y == d0[0]) && (y == d1[0])) { /// if year=start_year && year = end_year .... start from start_month to end_month
for (var m = d0[1]; m <= d1[1]; m++) {
for (var d =1;d <= monthday(m,y); d++) {
dates.push(y+"-"+m+"-"+d)
}
}
}
}
break;
case "Monthly":
for (var y = d0[0]; y <= d1[0]; y++) {
if ((y == d0[0]) && (d0[0] != d1[0])) { // if year=start_year && year != end year ... start from start_month and loop up to month 12
for (var m = d0[1]; m <= 12; m++) {
dates.push(y+"-"+m)
}
}
if ((y != d0[0]) && (y!= d1[0])) { // if year != start_year && year != end year .... start from month 1 to month 12 - this would 2015 data in pulling Dec 2014 - April 2016
for (var m = 1; m <= 12; m++) {
dates.push(y+"-"+m)
}
}
if ((y != d0[0]) && (y == d1[0])) { // if year !=start_year && year = end_year .... start from month 1 up until end_month
for (var m = 1; m <= d1[1]; m++) {
dates.push(y+"-"+m)
}
}
if ((y == d0[0]) && (y == d1[0])) { /// if year=start_year && year = end_year .... start from start_month to end_month
for (var m = d0[1]; m <= d1[1]; m++) {
dates.push(y+"-"+m)
}
}
}
}
return dates
}
/// Function for Day Date Range
function monthday (month,year) {
var months31 = [1,3,5,7,8,10,12]
var months30 = [4,6,9,11]
var leapyear = [2016,2020,2024,2028,2032]
if (months31.indexOf(month) >=0){
var result = 31}
else if (months30.indexOf(month) >=0){
var result = 30}
else if (month==2 && leapyear.indexOf(year) >=0){
var result = 29}
else if (month==2 && year != 2016){
var result = 28}
return result
}

Java Datestring, how to create long Day of the Week format?

This is a script that counts a desired number of business days from the present time. It works very well. I would like it to render the result as a long word day of the week, as in Monday July 06 2015, for example. The current result is Mon Jul 06 2015
I am a hacking monkey, so a dumbed-down response would not be an insult!
Number.prototype.mod = function(n) {
return ((this % n) + n) % n;
}
Date.prototype.addBusDays = function(dd) {
var wks = Math.floor(dd / 5);
var dys = dd.mod(5);
var dy = this.getDay();
if (dy === 6 && dd > -1) {
if (dys === 0) {
dys -= 2;
dy += 2;
}
dys++;
dy -= 6;
}
if (dy === 0 && dd < 1) {
if (dys === 0) {
dys += 2;
dy -= 2;
}
dys--;
dy += 6;
}
if (dy + dys > 5) dys += 2;
if (dy + dys < 1) dys -= 2;
this.setDate(this.getDate() + wks * 7 + dys);
}
var today = new Date();
today.addBusDays(1);
document.getElementById('dtt').innerHTML = today.toDateString();
Usage: We use it in a full sentence:
Your package will arrive on or before <span id="dtt"></span>.
Just create an array of month/day names like so:
var days = ["Sunday","Monday",...];
var months = ["January", "February", ...];
And then
function formatDate(date) {
var day = date.getDate();
if(day < 10) {
day = "0" + day;
}
return days[date.getDay()] + " " + months[date.getMonth()] + " " + day + " " + date.getFullYear();
}
console.log(formatDate(new Date()));
http://jsfiddle.net/1xe39uut/2/

Output all dates of a year

I would like to list all dates and hour of a year with format mmddhh
Q1: Why I got "undefined" before the output? How can I fix it?
var m, d, h, month, day, hour, output;
for (m = 1; m <= 12; m++) {
month = addZero(m).toString();
for (d = 1; d <= 31; d++) {
day = addZero(d).toString();
for (h = 1; h <= 24; h++) {
hour = addZero(h).toString();
output += month + day + hour + "<br>";
}
}
}
document.getElementById("result").innerHTML = output;
function addZero(z) {
var z
if (z < 10)
return "0" + z;
else
return z;
}
<p id="result"></p>
Q2: I tried looping d 31 times using if (m = "01" || "03" || "05" || "07" || "08" || "10" || "12") else looping 30 times. However it is fail, how can I do that?
var m, d, h, month, day, hour, output;
for (m = 1; m <= 12; m++) {
month = addZero(m).toString();
if (m = "01" || "03" || "05" || "07" || "08" || "10" || "12") {
for (d = 1; d <= 31; d++) {
day = addZero(d).toString();
for (h = 1; h <= 24; h++) {
hour = addZero(h).toString();
output += month + day + hour + "<br>";
}
}
} else {
for (d = 1; d <= 30; d++) {
day = addZero(d).toString();
for (h = 1; h <= 24; h++) {
hour = addZero(h).toString();
output += month + day + hour + "<br>";
}
}
}
}
document.getElementById("result").innerHTML = output;
function addZero(z) {
var z
if (z < 10)
return "0" + z;
else
return z;
}
<p id="result"></p>
You have declared a variable called output, but it is not initialized with a value, so its value is undefined.
Then when you say output += month + day + hour + "<br>"; it is really output = undefined + month + day + hour + "<br>";, thus you are getting an undefined at the beginning of the output
var m, d, h, month, day, hour, output = "";
for (m = 1; m <= 12; m++) {
month = addZero(m).toString();
for (d = 1; d <= 31; d++) {
day = addZero(d).toString();
for (h = 1; h <= 24; h++) {
hour = addZero(h).toString();
output += month + day + hour + "<br>";
}
}
}
document.getElementById("result").innerHTML = output;
function addZero(z) {
var z
if (z < 10)
return "0" + z;
else
return z;
}
<p id="result"></p>

Find the number of business days between two dates in Microsoft Dynamics CRM 2011

All, I am trying to use javascript to setValue a integer into a field based on the dates in a start and end field. I'm not even sure what the correct syntax for finding the day of the week with CRM javascript. Here is my code so far.
function netbdays_change() {
var startday = Xrm.Page.getAttribute("new_quotestart").getValue();
var endday = Xrm.Page.getAttribute("new_quoteend").getValue();
cycletime = endday - startday;
Xrm.Page.getAttribute("new_setcycletime").setValue(cycletime);
}
Try this:
function netbdays_change() {
var startday = Xrm.Page.getAttribute("new_quotestart").getValue().getDay();
var endday = Xrm.Page.getAttribute("new_quoteend").getValue().getDay();
cycletime = endday - startday;
Xrm.Page.getAttribute("new_setcycletime").setValue(cycletime);
}
getDay() returns a 0 based representation of the day of the week.
http://www.w3schools.com/jsref/jsref_getday.asp
If you want to calculate the number of days between 2 dates, try this:
function netbdays_change() {
var startday = Xrm.Page.getAttribute("new_quotestart").getValue();
var endday = Xrm.Page.getAttribute("new_quoteend").getValue();
cycletime = Math.abs(endday - startday)
Xrm.Page.getAttribute("new_setcycletime").setValue(cycletime / 86400000);
}
I finally figured out the solution: Feel Free to use everyone. :)
function netbdays_change() {
var startdays = Xrm.Page.getAttribute("new_dateqaassigned").getValue();
var enddays = Xrm.Page.getAttribute("new_quotecomplete").getValue();
var cycletime = Math.abs(enddays - startdays) / 86400000; // This first part now works
startday = Xrm.Page.getAttribute("new_dateqaassigned").getValue().getDay();
endday = Xrm.Page.getAttribute("new_quotecomplete").getValue().getDay();
var x = startday; // day of the week
var y = 0; // number of business days for output
var z = 0; // augment up to the total number of days
while (x <= 7 && z <= cycletime) {
if (x > 0 && x < 6) {
y++;
}
x++;
z++;
}
x = 0;
while (x <= 7 && z <= cycletime) {
if (x > 0 && x < 6) {
y++;
}
x++;
z++;
if (x == 6) {
x = 0;
}
}
Xrm.Page.getAttribute("new_quotetotalcycletime").setValue(y);
}
Here's my code:
function GetBusinessDays(startDate, endDate)
{
if (startDate != null && endDate != null)
{
var cycletime = (Math.abs(endDate - startDate) / 86400000) + 1;
var startday = startDate.getDay();
var x = startday; // day of the week
var y = 0; // number of business days for output
var z = 0; // augment up to the total number of days
while (z < cycletime) {
if (x > 0 && x < 6)
{
y++;
}
x++;
z++;
if (x > 6)
{
x = 0;
}
}
return y;
}
return null;
}

add/subtract business days in Javascript

I need a Date.prototype.addBusDays function
that'll take an integer as the number of working days to add to the date.
However, there are two considerations: 1. Weekends, 2. Holidays (which I imagine would be a preset array to compare against. If beginning date and end date contain 3 holidays, then you push out the end date by 3)
I have come across some scripts online, one dilemma I can think of is, lets say you address all the weekends first, then you do the holidays, what if you +1 day (due to holiday), and your end date is pushed into a weekends again...<
Any ideas?
Thanks!
EDIT:
This is a part of a scheduling tool I am developing, which mean the dates will be tied to tasks which are linked together. Adding 1 day to a task, will trigger a recalculation of everything tied to it, potentially all dates in the database.
Datageek's solution helped me but I needed to augment it. This still doesn't do holidays but does do working days with the option of including Sat and/or Sun, and does support adding negative days:-
function AddWorkingDays(datStartDate, lngNumberOfWorkingDays, blnIncSat, blnIncSun) {
var intWorkingDays = 5;
var intNonWorkingDays = 2;
var intStartDay = datStartDate.getDay(); // 0=Sunday ... 6=Saturday
var intOffset;
var intModifier = 0;
if (blnIncSat) { intWorkingDays++; intNonWorkingDays--; }
if (blnIncSun) { intWorkingDays++; intNonWorkingDays--; }
var newDate = new Date(datStartDate)
if (lngNumberOfWorkingDays >= 0) {
// Moving Forward
if (!blnIncSat && blnIncSun) {
intOffset = intStartDay;
} else {
intOffset = intStartDay - 1;
}
// Special start Saturday rule for 5 day week
if (intStartDay == 6 && !blnIncSat && !blnIncSun) {
intOffset -= 6;
intModifier = 1;
}
} else {
// Moving Backward
if (blnIncSat && !blnIncSun) {
intOffset = intStartDay - 6;
} else {
intOffset = intStartDay - 5;
}
// Special start Sunday rule for 5 day week
if (intStartDay == 0 && !blnIncSat && !blnIncSun) {
intOffset++;
intModifier = 1;
}
}
// ~~ is used to achieve integer division for both positive and negative numbers
newDate.setTime(datStartDate.getTime() + (new Number((~~((lngNumberOfWorkingDays + intOffset) / intWorkingDays) * intNonWorkingDays) + lngNumberOfWorkingDays + intModifier)*86400000));
return newDate;
}
Have a look at the following implementation. Sourced from about.com
addWeekdays = function(date, dd) {
var wks = Math.floor(dd/5);
var dys = dd.mod(5);
var dy = this.getDay();
if (dy === 6 && dys > -1) {
if (dys === 0) {dys-=2; dy+=2;}
dys++; dy -= 6;
}
if (dy === 0 && dys < 1) {
if (dys === 0) {dys+=2; dy-=2;}
dys--; dy += 6;
}
if (dy + dys > 5) dys += 2;
if (dy + dys < 1) dys -= 2;
date.setDate(date.getDate()+wks*7+dys);
}
var date = new Date();
addWeekdays(date, 9);
(Updated) I've put this algorithm through its paces and it seems stable, though it does use recursion for holiday processing:
holidays = [new Date("2/13/2019"), new Date("2/19/2019")];
function addWorkdays(workdays, startDate) {
//Make adjustments if the start date is on a weekend
let dayOfWeek = startDate.getDay();
let adjustedWorkdays = Math.abs(workdays);
if (0 == dayOfWeek || 6 == dayOfWeek) {
adjustedWorkdays += (Math.abs((dayOfWeek % 5) + Math.sign(workdays)) % 2) + 1;
dayOfWeek = (dayOfWeek - 6) * -1;
}
let endDate = new Date(startDate);
endDate.setDate(endDate.getDate() + (((Math.floor(((workdays >= 0 ? dayOfWeek - 1 : 6 - dayOfWeek) + adjustedWorkdays) / 5) * 2) + adjustedWorkdays) * (workdays < 0 ? -1 : 1)));
//If we cross holidays, recompute our end date accordingly
let numHolidays = holidays.reduce(function(total, holiday) { return (holiday >= Math.min(startDate, endDate) && holiday <= Math.max(startDate, endDate)) ? total + 1 : total; }, 0);
if (numHolidays > 0) {
endDate.setDate(endDate.getDate() + Math.sign(workdays));
return addWorkdays((numHolidays - 1) * Math.sign(workdays), endDate);
} else return endDate;
}
I expanded on khellendros74's answer for a project of mine that needed to disable Sundays and mailing holidays in the datepicker and return two dates on press of a button: three business days (i.e. non-holiday and non-Sunday) after the date picked in the datepicker (a field with an id of "calendar") and six business days after the date picked in the datepicker and then put those two results into a couple of disabled input fields (handDelivered and mailed). The button press calls the function calculateDates. Here is that code:
var disabledDates = ['11/11/2015', '11/26/2015', '12/25/2015', '01/01/2016','01/18/2016', '02/15/2016','05/30/2016', '07/04/2016','09/05/2016','10/10/2016','11/11/2016','11/24/2016', '12/26/2016','01/02/2017','01/16/2017', '02/20/2017','05/29/2017', '07/04/2017','09/04/2017','10/09/2017','11/10/2017','11/23/2017', '12/25/2017','01/01/2018','01/15/2018', '02/19/2018','05/28/2018', '07/04/2018','09/03/2018','10/08/2018','11/12/2018','11/22/2018', '12/25/2018','01/01/2019','01/21/2019', '02/18/2019','05/27/2019', '07/04/2019','09/02/2019','10/14/2019','11/11/2019','11/28/2019', '12/25/2019','01/01/2020','01/20/2020', '02/17/2020','05/25/2020', '07/03/2020','09/07/2020','10/11/2020','11/26/2020','11/26/2020', '12/25/2020'];
$(function(){
$('#calendar').datepicker({
dateFormat: 'mm/dd/yy',
beforeShowDay: editDays
});
function editDays(date) {
for (var i = 0; i < disabledDates.length; i++) {
if (new Date(disabledDates[i]).toString() == date.toString() || date.getDay() == 0) {
return [false];
}
}
return [true];
}
});
function calculateDates()
{
if( !$('#calendar').val()){
alert("Please enter a date.");
document.getElementById('calendar').focus();
return false;
}
var dayThreeAdd = 0;
var daySixAdd = 0;
for (var i = 0; i < disabledDates.length; i++) {
var oneDays = AddWorkingDays($('#calendar').val(),1,true,false);
var twoDays = AddWorkingDays($('#calendar').val(),2,true,false);
var threeDays = AddWorkingDays($('#calendar').val(),3,true,false);
var fourDays = AddWorkingDays($('#calendar').val(),4,true,false);
var fiveDays = AddWorkingDays($('#calendar').val(),5,true,false);
var sixDays = AddWorkingDays($('#calendar').val(),6,true,false);
if (new Date(disabledDates[i]).toString() == oneDays.toString()) {
dayThreeAdd++;
daySixAdd++;
}
if (new Date(disabledDates[i]).toString() == twoDays.toString()) {
dayThreeAdd++;
daySixAdd++;
}
if (new Date(disabledDates[i]).toString() == threeDays.toString()) {
dayThreeAdd++;
daySixAdd++;
}
if (new Date(disabledDates[i]).toString() == fourDays.toString()) {
daySixAdd++;
}
if (new Date(disabledDates[i]).toString() == fiveDays.toString()) {
daySixAdd++;
}
if (new Date(disabledDates[i]).toString() == sixDays.toString()) {
daySixAdd++;
}
}
var threeDays = AddWorkingDays($('#calendar').val(),(3 + dayThreeAdd),true,false);
var sixDays = AddWorkingDays($('#calendar').val(),(6 + daySixAdd),true,false);
$('#handDelivered').val((threeDays.getMonth()+1) + '/' + threeDays.getDate() + '/' + (threeDays.getYear()+1900));
$('#mailed').val((sixDays.getMonth()+1) + '/' + sixDays.getDate() + '/' + (sixDays.getYear()+1900));
}
function AddWorkingDays(datStartDate, lngNumberOfWorkingDays, blnIncSat, blnIncSun) {
datStartDate = new Date(datStartDate);
var intWorkingDays = 5;
var intNonWorkingDays = 2;
var intStartDay = datStartDate.getDay(); // 0=Sunday ... 6=Saturday
var intOffset;
var intModifier = 0;
if (blnIncSat) { intWorkingDays++; intNonWorkingDays--; }
if (blnIncSun) { intWorkingDays++; intNonWorkingDays--; }
var newDate = new Date(datStartDate)
if (lngNumberOfWorkingDays >= 0) {
// Moving Forward
if (!blnIncSat && blnIncSun) {
intOffset = intStartDay;
} else {
intOffset = intStartDay - 1;
}
// Special start Saturday rule for 5 day week
if (intStartDay == 6 && !blnIncSat && !blnIncSun) {
intOffset -= 6;
intModifier = 1;
}
} else {
// Moving Backward
if (blnIncSat && !blnIncSun) {
intOffset = intStartDay - 6;
} else {
intOffset = intStartDay - 5;
}
// Special start Sunday rule for 5 day week
if (intStartDay == 0 && !blnIncSat && !blnIncSun) {
intOffset++;
intModifier = 1;
}
}
// ~~ is used to achieve integer division for both positive and negative numbers
newDate.setTime(datStartDate.getTime() + (new Number((~~((lngNumberOfWorkingDays + intOffset) / intWorkingDays) * intNonWorkingDays) + lngNumberOfWorkingDays + intModifier)*86400000));
return newDate;
}
Simple solution to solve the whole problem; you can just loop through the days to skip weekdays and holidays:
Date.prototype.holidays = {
// fill in common holidays
all: [
'0101', // Jan 01
'1225' // Dec 25
],
2016: [
// add year specific holidays
'0104' // Jan 04 2016
],
2017: [
// And so on for other years.
]
};
Date.prototype.addWorkingDays = function(days) {
while (days > 0) {
this.setDate(this.getDate() + 1);
if (!this.isHoliday()) days--;
}
return this;
};
Date.prototype.substractWorkingDays = function(days) {
while (days > 0) {
this.setDate(this.getDate() - 1);
if (!this.isHoliday()) days--;
}
return this;
};
Date.prototype.isHoliday = function() {
function zeroPad(n) {
n |= 0;
return (n < 10 ? '0' : '') + n;
}
// if weekend return true from here it self;
if (this.getDay() == 0 || this.getDay() == 6) {
return true;
}
var day = zeroPad(this.getMonth() + 1) + zeroPad(this.getDate());
// if date is present in the holiday list return true;
return !!~this.holidays.all.indexOf(day) ||
(this.holidays[this.getFullYear()] ?
!!~this.holidays[this.getFullYear()].indexOf(day) : false);
};
// Uasage
var date = new Date('2015-12-31');
date.addWorkingDays(10);
alert(date.toDateString()); // Mon Jan 18 2016
date.substractWorkingDays(10);
alert(date.toDateString()) // Thu Dec 31 2015
This only takes weekends into account and not holidays, but it's a start...
function mod(x, y) {
// https://stackoverflow.com/a/4467559/2173455
return ((x % y) + y) % y;
}
function calculateDateDiff(date, diff) {
let returnDate = new Date(date.getTime());
let daysLeftToAdd = Math.abs(diff);
let weekendDays = 0;
let weekDay = returnDate.getDay();
while(daysLeftToAdd >= 0) {
if(weekDay == 0 || weekDay == 6) {
weekendDays++;
}
else {
daysLeftToAdd--;
}
weekDay = mod(diff > 0 ? weekDay + 1 : weekDay - 1, 7);
}
returnDate.setDate(diff > 0 ?
returnDate.getDate() + diff + weekendDays :
returnDate.getDate() + diff - weekendDays
);
return returnDate;
}

Categories