A delivery counter which excludes sunday and holidays - javascript

I'm using a delivery Day counter to show my customers on which day they can expect their package.
But... there is a problem.
The delivery days should be (the day ordered + 2 days (before 12 o clock(germany)) if not 3 days)that's working like a charme. But I can't get my head aroung excluding sundays. At the moment the counter adds one day if it is sunday... But for example if it is saturday the counter doesn't add a day (for the nonDeliveryDate)
atm (after 12 o' clock):
17.09.2020 - delivery to Monday = right
18.09.2020 - delivery to Monday = wrong (should be Tuesday)
19.09.2020 - delivery to Tuesday = wrong (should be Wednesday)
20.09.2020 - delivery to Wednesday = right
I think the problem is that the counter only adds one day if "today" is sunday but not if one of the next 3 days is sunday... but i'm not really sure how to solve that.
That's my script:
<script type='text/javascript'>
jQuery(function($) {
// Current date/time
var now = new Date();
// Placeholder for delivery time
var deliveryDate;
// Amount of days to deliver
var deliveryDays = 2;
// Working hours (in UTC -1)
var workingHours = [0 , 9];
// Non-delivery days/dates
// Must match the format returned by .toString():
// Mon Sep 28 1998 14:36:22 GMT-0700 (Pacific Daylight Time)
var nonDelivery = [
"Sun",
"Dec 24",
"Dec 25",
"Dec 31",
"Jan 1"
];
// Create a regular expression
var rxp = new RegExp(nonDelivery.join("|"));
// addDay holds the amount of days to add to delivery date
var addDay = deliveryDays;
// Add an extra day if outside of working hours
var currentHour = now.getUTCHours();
if (currentHour < workingHours[0] ||
currentHour > workingHours[1]) {
addDay++;
}
// Create our delivery date
while (!deliveryDate) {
// Add day(s) to delivery date
now.setDate(
now.getDate() + addDay
);
deliveryDate = now;
if (rxp.test(deliveryDate)) {
addDay = 1;
deliveryDate = false;
}
}
// Format
var locale = "de-DE"; // Our locale
// var day = deliveryDate.toLocaleDateString(locale, { day: "numeric" });
var weekday = deliveryDate.toLocaleDateString(locale, { weekday: "long" });
$('#countdownDate').html( weekday + " " );
});
</script>
Hopefully someone can help me with that...
Thanks a lot!

Related

Moment convert day str into moment with only the day and time

I'm trying to convert the string 'Wed, 11:45 pm' into a proper datetime (preferably UTC). Is it possible to do without needing the month? The proper datetime would be the upcoming Wednesday. It's Monday(23rd) today, so Wednesday would be the 25th.
const time = 'Wed, 11:45 pm'
const datetime = moment(time).utc() // yields 2019-09-23T05:00:00Z (todays date)
I need it to yield 2019-09-25T22:25:58Z (two days, wednesday, from now)
I think your question has to be split to a few steps and your requirement is not very clear.
The steps I did here is
Split your input to 'Wed' and '11:45 pm'.
Use 'Wed' to calculate the coming Wednesday (If today is wednesday then coming wednesday would still be today or the next wednesday)
Set 11:45 to the hour and minute.
Change it to the format you prefer.
I saw your tag has cypress so I wrote a cypress test with the function above.
describe('Find the coming Wednesday', () => {
it('test',()=>{
cy.visit('https://www.google.com');
const time = "Wed, 11:45 pm";
var returnedDatetime = findComingDate(time);
const outputDatetime = Cypress.moment(returnedDatetime).utc().format();
console.log(outputDatetime);
})
})
function findComingDate(dayAndTime) {
//split your string
var dayAndTime = dayAndTime.split(',');
var day = dayAndTime[0];
var time = dayAndTime[1];
var parts = time.match(/(\d+):(\d+) (am|pm)/);
if (parts) {
var hours = parseInt(parts[1]),
minutes = parseInt(parts[2]),
tt = parts[3];
}
if (tt === 'pm' && hours < 12) hours += 12;
var days = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'];
var dayindex = days.indexOf(day) + 1;
if (dayindex === 0) {
throw ('You can only input 3 letters for the day name')
}
else {
var cd = new Date();
//use commented code below if today is tuesady and your input is tuesday and you want output is today.
cd.setDate(cd.getDate() + ((7-cd.getDay())%7+dayindex)%7);
//use commented code below if today is tuesady and your input is tuesday and you want output is next tuesday.
//cd.setDate(cd.getDate() + (7-cd.getDay())%7+dayindex)
//change the time
cd.setHours(hours,minutes,0,0);
return cd;
}
}
I tested it on 2019-9-24 with your input 'Wed, 11:45 pm' it returns UTC time
2019-09-24T11:45:00Z
Try
moment('Wed, 11:45 pm', 'ddd HH:mm a')

getDate returning the next day on current time

Is this due to the time zones settings on my laptop or is it something more complex?
Current time
var dateObj = new Date();
var month = dateObj.getUTCMonth() + 1; //months from 1-12
var day = dateObj.getUTCDate();
var year = dateObj.getUTCFullYear();
var week = 7;
console.log ('date ',dateObj,' day is ',day);
output
> date Mon Jan 14 2019 23:05:35 GMT-0500 (Eastern Standard Time) day is 15
edit: that the time that new Date() created (Mon Jan 14 2019 23:05:35 GMT-0500) is in fact the correct time I am after.
after considering the information I read in comments, it seems I need to subtract the hourly change ( - 5 ) to get the EST, which seems to be what I'm after.
it seems I need to subtract the hourly change ( - 5 ) to get the EST
Subtracting 5 is not a good idea, as it doesn't account for daylight savings.
I'd suggest using toLocaleString() to be safe.
var dateObj = new Date();
//Output as UTC
var utc = { timeZone: "UTC" };
console.log(dateObj.toLocaleString("en-US", utc));
//Output as EST
var est = { timeZone: "America/New_York" };
console.log(dateObj.toLocaleString("en-US", est));
You need to keep timezones consistent. Change this:
console.log ('date ',dateObj,' day is ',day);
To this:
console.log ('date ',dateObj.getUTCDate(),' day is ',day);
And it will work:
var dateObj = new Date();
var month = dateObj.getUTCMonth() + 1; //months from 1-12
var day = dateObj.getUTCDate();
var year = dateObj.getUTCFullYear();
var week = 7;
console.log('date ', dateObj.getUTCDate(), ' day is ', day);

DateTime calculation issue

I'm trying to create a countdown based on the lottery drawing times.
If the current date time is greater than the current weeks Wednesday then we display the current week Saturday's date time.
If the current date time is greater than the current weeks Saturday then we display the next Wednesday date time.
I don't want it to display for the last hour of that day.
I'm using moment and moment timezone.
var current = new Date(moment().tz('America/New_York').format('YYYY-MM-DDTHH:mm:ss'));
var wednesday = new Date().wednesday(); //if we are past the current Wednesday, it returns next weeks Wednesday
var wednesdayLimit = new Date(wednesday.getFullYear(), wednesday.getMonth(), wednesday.getDate(), 22, 59, 00);
var saturday = new Date().saturday();
var saturdayLimit = new Date(saturday.getFullYear(), saturday.getMonth(), saturday.getDate(), 22, 59, 00);
if (current > wednesdayLimit && current < saturdayLimit)
{
var temp = moment(saturdayLimit).format('YYYY-MM-DD HH:mm');
$('.countdown').data('date', temp);
$(".countdown").TimeCircles();
}
else if (current > saturdayLimit && current < wenesdayLimit)
{
var temp = moment(wednesdayLimit).format('YYYY-MM-DD HH:mm');
$('.countdown').data('date', temp);
$(".countdown").TimeCircles();
}
Maybe i'm over complicating it.
https://jsfiddle.net/1bLj4m2t/11/
UPDATE
Sorry, let me try to clarify. The countdown should not display between 22:59:01 - 23:59:59 on Wed or Sat. The last 1 hour and 1 minute of the day. This is why I created the *Limit vars and adjusted them to 22:59:00.
So to display the wednesdayLimit the current date time would need to be between
Thursdays 00:00:00 and Saturday 22:59:00
now to display saturdayLimit the current date time would need to be between
Sunday 00:00:00 and Wednesday 22:59:00
UPDATE 2
https://jsfiddle.net/1bLj4m2t/11/
Currently working but might be a cleaner/better way to do this?
I guess you just need to check which date is near to today? Is it Wednesday or Saturday? In other words check if Saturday is greater than Wednesday or vice versa. (Or find out which is minimum of the two)
Here is updated fiddle: https://jsfiddle.net/vnathalye/1bLj4m2t/6/
var current = new Date(moment().tz('America/New_York').format('YYYY-MM-DDTHH:mm:ss'));
var wednesday = new Date().wednesday();
var saturday = new Date().saturday();
$('.current').html(current);
$('.wednesday').html(wednesday);
$('.saturday').html(saturday);
var currentWeekday = moment(current).weekday();
var wednesdayWeekday = moment(wednesday).weekday();
var saturdayWeekday = moment(saturday).weekday();
var temp = (currentWeekday == wednesdayWeekday || currentWeekday == saturdayWeekday)? current : Math.min(wednesday, saturday);
$('.countdown').html(moment(temp).fromNow()); // use appropriate time of temp date
UPDATE: Added logic to check if current day is wednesday / saturday.
UPDATE 2: I've checked your updated fiddle and noticed that you are using momentjs & datejs. Do you really need 2 libraries? I'll stick to momentjs.
Looking at different values of current and the expected result that you have mentioned in your fiddle v11 I've updated my code # https://jsfiddle.net/vnathalye/1bLj4m2t/14/
//var current = moment('2016/01/17 08:00:00', 'YYYY/MM/DD HH:mm:ss'); //display Wed
//var current = moment('2016/01/20 00:00:00', 'YYYY/MM/DD HH:mm:ss'); //display Wed
//var current = moment('2016/01/20 22:59:00', 'YYYY/MM/DD HH:mm:ss'); //display Wed last hour
//var current = moment('2016/01/20 23:59:59', 'YYYY/MM/DD HH:mm:ss'); //display Wed last hour
//var current = moment('2016/01/21 00:00:00', 'YYYY/MM/DD HH:mm:ss'); //display Sat
//var current = moment('2016/01/23 00:00:00', 'YYYY/MM/DD HH:mm:ss'); //display Sat
var current = moment('2016/01/23 22:59:01', 'YYYY/MM/DD HH:mm:ss'); //display Sat last hour
var wednesday = moment(current).day(3); // sun=0 ... sat=6
var saturday = moment(current).day(6);
var currentWeekday = current.weekday();
var wednesdayWeekday = wednesday.weekday();
//var saturdayWeekday = moment(saturday).weekday();
var showWednesday = currentWeekday <= wednesdayWeekday;
var temp = showWednesday? wednesday : saturday;
temp = temp.hours(23).minutes(59).seconds(59).milliseconds(999);
$('.current').html(current.toDate());
$('.wednesday').html(wednesday.toDate());
$('.saturday').html(saturday.toDate());
$('.countdown').html((showWednesday? "Wed" : "Sat") +
(temp.diff(current, "minutes") <= 60 ? " last hour" : ""));
Note:
.day() function returns the day of current week (unlike wednesday()/saturday() that you are using). This allows me to simply compare weekday of current with weekday of wednesday to decide whether to use wednesday or saturday for further calculations
To check if its the last hour of temp(wednesday/saturday), you just check the difference is <= 60 minutes
I've used the date strings as you have used in your example and hence used the second param 'YYYY/MM/DD HH:mm:ss' while calling moment(). Ref: https://github.com/moment/moment/issues/1407 to know recommended ways of using moment()
While displaying the date I've used .toDate() but you can use .format()

exclude weekends in javascript date calculation

I have two sets of codes that work. Needed help combining them into one.
This code gets me the difference between two dates. works perfectly:
function test(){
var date1 = new Date(txtbox_1.value);
var date2 = new Date(txtbox_2.value);
var diff = (date2 - date1)/1000;
var diff = Math.abs(Math.floor(diff));
var days = Math.floor(diff/(24*60*60));
var leftSec = diff - days * 24*60*60;
var hrs = Math.floor(leftSec/(60*60));
var leftSec = leftSec - hrs * 60*60;
var min = Math.floor(leftSec/(60));
var leftSec = leftSec - min * 60;
txtbox_3.value = days + "." + hrs; }
source for the above code
The code below by #cyberfly appears to have the answer of excluding sat and sun which is what i needed. source. However, its in jquery and the above code is in JS. Therefore, needed help combining as i lacked that knowledge :(
<script type="text/javascript">
$("#startdate, #enddate").change(function() {
var d1 = $("#startdate").val();
var d2 = $("#enddate").val();
var minutes = 1000*60;
var hours = minutes*60;
var day = hours*24;
var startdate1 = getDateFromFormat(d1, "d-m-y");
var enddate1 = getDateFromFormat(d2, "d-m-y");
var days = calcBusinessDays(new Date(startdate1),new Date(enddate1));
if(days>0)
{ $("#noofdays").val(days);}
else
{ $("#noofdays").val(0);}
});
</script>
EDIT
Made an attempt at combining the codes. here is my sample. getting object expected error.
function test(){
var date1 = new Date(startdate.value);
var date2 = new Date(enddate.value);
var diff = (date2 - date1)/1000;
var diff = Math.abs(Math.floor(diff));
var days = Math.floor(diff/(24*60*60));
var leftSec = diff - days * 24*60*60;
var hrs = Math.floor(leftSec/(60*60));
var leftSec = leftSec - hrs * 60*60;
var min = Math.floor(leftSec/(60));
var leftSec = leftSec - min * 60;
var startdate1 = getDateFromFormat(startdate, "dd/mm/yyyy hh:mm");
var enddate1 = getDateFromFormat(enddate, "dd/mm/yyyy hh:mm");
days = calcBusinessDays(new Date(startdate1),new Date(enddate1));
noofdays.value = days + "." + hrs; }
start: <input type="text" id="startdate" name="startdate" value="02/03/2015 00:00">
end: <input type="text" id="enddate" name="enddate" value="02/03/2015 00:01">
<input type="text" id="noofdays" name="noofdays" value="">
When determining the number of days between two dates, there are lots of decisions to be made about what is a day. For example, the period 1 Feb to 2 Feb is generally one day, so 1 Feb to 1 Feb is zero days.
When adding the complexity of counting only business days, things get a lot tougher. E.g. Monday 2 Feb 2015 to Friday 6 February is 4 elapsed days (Monday to Tuesday is 1, Monday to Wednesday is 2, etc.), however the expression "Monday to Friday" is generally viewed as 5 business days and the duration Mon 2 Feb to Sat 7 Feb should also be 4 business days, but Sunday to Saturday should be 5.
So here's my algorithm:
Get the total number of whole days between the two dates
Divide by 7 to get the number of whole weeks
Multiply the number of weeks by two to get the number of weekend days
Subtract the number of weekend days from the whole to get business days
If the number of total days is not an even number of weeks, add the numbe of weeks * 7 to the start date to get a temp date
While the temp date is less than the end date:
if the temp date is not a Saturday or Sunday, add one the business days
add one to the temp date
That's it.
The stepping part at the end can probably be replaced by some other algorithm, but it will never loop for more than 6 days so it's a simple and reasonably efficient solution to the issue of uneven weeks.
Some consequences of the above:
Monday to Friday is 4 business days
Any day to the same day in a different week is an even number of weeks and therefore an even mutiple of 5, e.g. Monday 2 Feb to Monday 9 Feb and Sunday 1 Feb to Sunday 8 Feb are 5 business days
Friday 6 Feb to Sunday 7 Feb is zero business days
Friday 6 Feb to Monday 9 Feb is one business day
Sunday 8 Feb to: Sunday 15 Feb, Sat 14 Feb and Fri 13 Feb are all 5 business days
Here's the code:
// Expects start date to be before end date
// start and end are Date objects
function dateDifference(start, end) {
// Copy date objects so don't modify originals
var s = new Date(+start);
var e = new Date(+end);
// Set time to midday to avoid dalight saving and browser quirks
s.setHours(12,0,0,0);
e.setHours(12,0,0,0);
// Get the difference in whole days
var totalDays = Math.round((e - s) / 8.64e7);
// Get the difference in whole weeks
var wholeWeeks = totalDays / 7 | 0;
// Estimate business days as number of whole weeks * 5
var days = wholeWeeks * 5;
// If not even number of weeks, calc remaining weekend days
if (totalDays % 7) {
s.setDate(s.getDate() + wholeWeeks * 7);
while (s < e) {
s.setDate(s.getDate() + 1);
// If day isn't a Sunday or Saturday, add to business days
if (s.getDay() != 0 && s.getDay() != 6) {
++days;
}
}
}
return days;
}
I don't know how it compares to jfriend00's answer or the code you referenced, if you want the period to be inclusive, just add one if the start or end date are a business day.
Here's a simple function to calculate the number of business days between two date objects. As designed, it does not count the start day, but does count the end day so if you give it a date on a Tuesday of one week and a Tuesday of the next week, it will return 5 business days. This does not account for holidays, but does work properly across daylight savings changes.
function calcBusinessDays(start, end) {
// This makes no effort to account for holidays
// Counts end day, does not count start day
// make copies we can normalize without changing passed in objects
var start = new Date(start);
var end = new Date(end);
// initial total
var totalBusinessDays = 0;
// normalize both start and end to beginning of the day
start.setHours(0,0,0,0);
end.setHours(0,0,0,0);
var current = new Date(start);
current.setDate(current.getDate() + 1);
var day;
// loop through each day, checking
while (current <= end) {
day = current.getDay();
if (day >= 1 && day <= 5) {
++totalBusinessDays;
}
current.setDate(current.getDate() + 1);
}
return totalBusinessDays;
}
And, the jQuery + jQueryUI code for a demo:
// make both input fields into date pickers
$("#startDate, #endDate").datepicker();
// process click to calculate the difference between the two days
$("#calc").click(function(e) {
var diff = calcBusinessDays(
$("#startDate").datepicker("getDate"),
$("#endDate").datepicker("getDate")
);
$("#diff").html(diff);
});
And, here's a simple demo built with the date picker in jQueryUI: http://jsfiddle.net/jfriend00/z1txs10d/
const firstDate = new Date("December 30, 2020");
const secondDate = new Date("January 4, 2021");
const daysWithOutWeekEnd = [];
for (var currentDate = new Date(firstDate); currentDate <= secondDate; currentDate.setDate(currentDate.getDate() + 1)) {
// console.log(currentDate);
if (currentDate.getDay() != 0 && currentDate.getDay() != 6) {
daysWithOutWeekEnd.push(new Date(currentDate));
}
}
console.log(daysWithOutWeekEnd, daysWithOutWeekEnd.length);
#RobG has given an excellent algorithm to separate business days from weekends.
I think the only problem is if the starting days is a weekend, Saturday or Sunday, then the no of working days/weekends will one less.
Corrected code is below.
function dateDifference(start, end) {
// Copy date objects so don't modify originals
var s = new Date(start);
var e = new Date(end);
var addOneMoreDay = 0;
if( s.getDay() == 0 || s.getDay() == 6 ) {
addOneMoreDay = 1;
}
// Set time to midday to avoid dalight saving and browser quirks
s.setHours(12,0,0,0);
e.setHours(12,0,0,0);
// Get the difference in whole days
var totalDays = Math.round((e - s) / 8.64e7);
// Get the difference in whole weeks
var wholeWeeks = totalDays / 7 | 0;
// Estimate business days as number of whole weeks * 5
var days = wholeWeeks * 5;
// If not even number of weeks, calc remaining weekend days
if (totalDays % 7) {
s.setDate(s.getDate() + wholeWeeks * 7);
while (s < e) {
s.setDate(s.getDate() + 1);
// If day isn't a Sunday or Saturday, add to business days
if (s.getDay() != 0 && s.getDay() != 6) {
++days;
}
//s.setDate(s.getDate() + 1);
}
}
var weekEndDays = totalDays - days + addOneMoreDay;
return weekEndDays;
}
JSFiddle link is https://jsfiddle.net/ykxj4k09/2/
First Get the Number of Days in a month
totalDays(month, year) {
return new Date(year, month, 0).getDate();
}
Then Get No Of Working Days In A Month By removing Saturday and Sunday
totalWorkdays() {
var d = new Date(); // to know present date
var m = d.getMonth() + 1; // to know present month
var y = d.getFullYear(); // to knoow present year
var td = this.totalDays(m, y);// to get no of days in a month
for (var i = 1; i <= td; i++) {
var s = new Date(y, m - 1, i);
if (s.getDay() != 0 && s.getDay() != 6) {
this.workDays.push(s.getDate());// working days
}else {
this.totalWeekDays.push(s.getDate());//week days
}
}
this.totalWorkingDays = this.workDays.length;
}
I thought the above code snippets others shared are lengthy.
I am sharing a concise snippet that gives date after considering the total number of days specified. we can also customize dates other than Saturdays and Sundays.
function getBusinessDays(dateObj, days) {
for (var i = 0; i < days; i++) {
if (days > 0) {
switch (dateObj.getDay()) {
// 6 being Saturday and 0 being Sunday.
case 6, 0:
dateObj.setDate(dateObj.getDate() + 2)
break;
//5 = Friday.
case 5:
dateObj.setDate(dateObj.getDate() + 3)
break;
//handle Monday, Tuesday, Wednesday and Thursday!
default:
dateObj.setDate(dateObj.getDate() + 1)
//console.log(dateObj)
break;
}
}
}
return dateObj;
}
console.log(getBusinessDays(new Date(), 11))
//Mon Dec 20 2021 18:56:01 GMT+0530 (India Standard Time)

Moment.js - How To Detect Daylight Savings Time And Add One Day

I need to create Date Objects from strings of Date data for every hour of every day since the year 2000.
The strings look like this for every hour, in a Month/Day/Year Hour format...
"04/02/2000 01", "04/02/2000 02", "04/02/2000 03" ...all the way to... "04/02/2000 24"
Now, I have the following code, which works fine except for on days with Daylight Savings Time...
// Split At Space
var splitDate = "04/02/2000 24".split(/[ ]+/);
var hour = splitDate[1];
var day = splitDate[0];
// Split At Slashes
var dayArray = day.split("/");
if (hour === "24") {
// Months are zero-based, so subtract 1 from the month
date = new Date(Date.UTC( dayArray[2], parseInt(dayArray[0] - 1), dayArray[1], 0, 0, 0 ));
date.setDate(date.getDate() + 1);
} else {
// Months and Hours are zero-based, so subtract 1 from each
date = new Date(Date.UTC( dayArray[2], parseInt(dayArray[0] - 1), dayArray[1], hour, 0, 0 ));
};
On days with daylight savings time, like 04/02/2000 adding a day does not work if the hour is 24. Instead, it just returns Sun, 02 Apr 2000 23:00:00 GMT
With Moment.js, is it possible to detect a DST day and get this code to work correctly?
To detect DST, use the .isDST() method: http://momentjs.com/docs/#/query/is-daylight-saving-time/
moment([2011, 2, 12]).isDST(); // false, March 12 2011 is not DST
moment([2011, 2, 14]).isDST(); // true, March 14 2011 is DST
Using this test, you should be able to determine how to modify your program's behavior accordingly.
Here's how I made a little checker:
var curDst = dtdate.isDST()
var prevDst = moment(dtdate).clone().subtract(1, "day").isDST();
var nextDst = moment(dtdate).clone().add(1, "day").isDST();
var isDstChangeDate = (curDst !== nextDst) === true || (curDst === prevDst) !== true;

Categories