Subtract working days from a date using Javascript - javascript

I'd like to use a Javascript within my zapier.com-zap. Here is what I am trying to do for five consecutive days now:
I have a date (whatever custom format you need), need to subtract two working days from it and output it to DD-MM-YYYY using Javascript. Sounds really simple, but I don't get it to work.
I hope someone out there can help me with this! Thank you very much.
I forgot to mention an essential thing, sorry. If the result is a Sunday or Saturday I need the date of the last working day (Friday).

If you're willing to use external libraries, MomentJS is a really popular tool for parsing and modifying JavaScript dates and would make this really simple:
Example 1: Subtract 2 Days and Format
var date = new Date(),
formatted = moment(date).subtract(2, 'days').format('DD-MM-YYYY');
document.getElementById('date').innerHTML = date;
document.getElementById('example').innerHTML = formatted;
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.11.2/moment.min.js"></script>
This example takes today's date (<span id="date"></span>), subtracts 2 days from it,
and then displays it below in the desired format (DD-MM-YYYY):
<p id="example"></p>
Example 2: Subtract 2 Working Days and Format
If by working days you mean Monday to Friday, all you'd need to do here is determine whether the day held in your date variable was a Monday or Tuesday, then adjust the value passed in to MomentJS's subtract method accordingly. We can do this using MomentJS's get day of week function:
var date = new Date(),
formatted, daysToSubtract;
switch (moment(date).day()) {
// Sunday = 3 days
case 0:
daysToSubtract = 3;
break;
// Monday and Tuesday = 4 days
case 1:
case 2:
daysToSubtract = 4;
break;
// Subtract 2 days otherwise.
default:
daysToSubtract = 2;
break;
}
formatted = moment(date).subtract(daysToSubtract, 'days').format('DD-MM-YYYY');
document.getElementById('date').innerHTML = date;
document.getElementById('example').innerHTML = formatted;
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.11.2/moment.min.js"></script>
This example takes today's date (<span id="date"></span>), subtracts 2 working days (Monday to Friday) from it,
and then displays it below in the desired format (DD-MM-YYYY):
<p id="example"></p>

While I agree with #James Donnelly that momentjs is awesome, here is how you can achieve your task without using an extra library. I created this helper function to do exactly what you're asking. Just pass in your date and however many days you want to add/subtract to it (-2 in your case).
function addDaysToDate(date, days)
{
var result = new Date(date);
result.setDate(result.getDate() + days);
var dd = result.getDate();
var mm = result.getMonth() + 1; // January starts at 0.
var yyyy = result.getFullYear();
if (dd < 10)
{
dd = '0' + dd
}
if (mm < 10)
{
mm = '0' + mm
}
return dd + '/' + mm + '/' + yyyy;
}

Related

Javascript and setMonth behaving unexpectedly

I am doing datObj.setMonth(1), but the month is being set to March? Isn't 1 supposed to be February? I'm using Chrome 79.
Here's part of code meant to parse dates such as YYYY-MM-DD HH:MM:SS (because safari can't do that natively)
var date = "2020-02-02 23:59:00"
if (typeof date == 'string')
{
var dateParts = date.split(/[:-\s]+/);
if (dateParts.length == 6)
{
dateObj = new Date();
dateObj.setYear(dateParts[0]);
var m = dateParts[1] - 1;
console.log('m= ' + m);
dateObj.setMonth(m);
console.log('after setmonth, date= ' + dateObj);
dateObj.setDate(dateParts[2]);
dateObj.setHours(dateParts[3]);
dateObj.setMinutes(dateParts[4]);
dateObj.setSeconds(dateParts[5]);
}
}
console.log(dateObj);
alert(dateObj);
Your problem, as you figured, is that you're setting the month while the day is still 30. While you could work around that by using setFullYear and pass year, month and day at once, you really should just construct the whole Date object with the right values in the first place:
dateObj = new Date(dateParts[0], dateParts[1]-1, dateParts[2], dateParts[3], dateParts[4], dateParts[5]);
or rather using UTC as the timezone:
dateObj = new Date(Date.UTC(dateParts[0], dateParts[1]-1, dateParts[2], dateParts[3], dateParts[4], dateParts[5]));
Just figured this out before I submitted. Today is January 30th, 2020. I can't change the month to February, because there is no February 30th. So, the code breaks either on the 29th or the 30th day of the month.
In JavaScript, it is advisable to do
dateObj.setMonth(monthNum -1, dayNum)
to set the day and month at the same time to avoid this problem

moment.js thinks that 2013-12-31 is week 1, not week 53

The moment.js library is awesome, and I use it almost all the time, but I recently ran into something interesting. I'm trying to plot data by week of the year, and one of the data points was 2013-12-31, moment.js tells me this is week 1? Is there a better way to handle this? either with 53, null, -1, or something?
moment('2013-12-31').week()
(returns) 1
I thought maybe using isoWeek or format would get around this, but they all return the same value of 1, despite the documentation saying it goes to 53.
moment('2013-12-31').isoWeek()
(returns) 1
+moment('2013-12-31').format('w')
(returns) 1
Anyone have any ideas on this? (short of making a test whether the week computed has a min/max date that covers the date value I passed it)
It is because the week from the 30th december 2013 is considered to be the 1st week of 2014 as you may see on this page epoch converter
And according to momentjs documentation:
The week with January 1st in it is the first week of the year.
I had a problem at my work where we used .format('YYYY WW') for some comparison logic.
That doesn't really make sense, as you should probably use .format('gggg WW') in such cases.
moment('2013-12-31').format('YYYY w'); // Returns 2013 1
moment('2013-12-31').format('gggg w'); // Returns 2014 1
https://momentjs.com/docs/#/displaying/format/
This is expected behavior. According to the ISO 8601 standard, 2013 is not a year with 53 weeks.
The long years, with 53 weeks in them, can be described by any of the following equivalent definitions:
any year starting on Thursday (dominical letter D or DC) and any leap year starting on Wednesday (ED)
any year ending on Thursday (D, ED) and any leap year ending on Friday (DC)
years in which 1 January and 31 December (in common years) or either (in leap years) are Thursdays
(source)
2013 started and ended on a Tuesday so therefore it is not a "long year" and 2013-12-31 is considered part of the first week of 2014.
If you want that week to be the 53rd, you'll have to write custom code for it as the ISO standard won't agree with you!
Moment.js docs aren't that straightforward with this I had to move from WW-YYYY to WW-GGGG
moment(2019-12-30T00:20:53.380Z).format(WW-YYYY) // Gave me 01-2019 incorrectly
moment(2019-12-30T00:20:53.380Z).format(WW-GGGG) // Gave me 01-2020 correctly
Findings
If your doing locale weeks, use ww & gggg
If your doing ISO weeks, use WW & GGGG
A mix of w/W & Y is incorrect usage
I had the same problem with the calculation of the week number, starting from the date of Sunday.
Finally I was able to solve the problem by calculating the week number starting not from Sunday but from Monday.
moment(date).isoWeekday(1).week()
Better right a custom method which will convert date into week and that can be customized easily.
//value : (MMM DD YYYY format)
function getEpiWeek(value) {
Date.prototype.getWeek = function () {
var target = new Date(this.valueOf());
// ISO week date weeks start on monday, so correct the day number
var dayNr = (this.getDay() + 7) % 7;
// Set the target to the thursday of this week so the
// target date is in the right year
target.setDate(target.getDate() - dayNr + 3);
// ISO 8601 states that week 1 is the week with january 4th in it
var jan4 = new Date(target.getFullYear(), 0, 4);
// Number of days between target date and january 4th
var dayDiff = (target - jan4) / 86400000;
if (new Date(target.getFullYear(), 0, 1).getDay() < 4) {
return 1 + Math.ceil(dayDiff / 7);
}
else { // jan 4th is on the next week (so next week is week 1)
return Math.ceil(dayDiff / 7);
}
};
var weekNumber = new Date(value).getWeek()
var year = getYear(value, weekNumber);
return weekNumber + ' ' + year;
}
function getYear(value, weekNumber) {
var year = parseInt(value.split(' ')[2]);
if (value.split(' ')[0] == 'Jan') {
if (weekNumber > 40) {
year = year - 1;
}
}
if (value.split(' ')[0] == 'Dec') {
if (weekNumber < 2) {
year = year + 1;
}
}
return year.toString();
}
Personally solved my ordering issue using :
if(d.month()==0) {
week = d.week();
}else{
week=d.isoWeek();
}

JS time calculation - How many times a date has occurred between two dates

I really need some assistance with a time calculation in JS.
Put basically I need to calculate how many times a day of a month has occurred between two dates.
For Example -
A date of 15th of the month between 1st February 2014 to 14 May 2014 would be 3
A date of 15th of the month between 1st February 2014 to 16 May 2014 would be 4
I've looked at moment Jquery library but it estimates that a month is 30 days so I wouldn't be exact and take into consideration leap years - months with 28 days etc..
It really needs to be exact because its for a chargeable event calculation. The dates can spare many years so could lead to in-accuries because of the 30 day thing.
Any help would be appreciated
There are probably a million ways to do this... here's a brute force way:
// add a "addDays() method to Date"
Date.prototype.addDays = function(days)
{
var dat = new Date(this.valueOf());
dat.setDate(dat.getDate() + days);
return dat;
}
// provide two dates and a day ordinal you want to count between the two
function numOrdinalsBetweenDts(Date1, Date2, theOrdinal) {
var temp;
if(Date2 < Date1) { // put dates in the right order (lesser first)
temp = Date1;
Date1 = Date2;
Date2 = temp;
}
var workDate = Date1;
var ctr = 0;
while(workDate < Date2) { // iterate through the calendar until we're past the end
if(workDate.getDate() == theOrdinal) // if we match the ordinal, count it
ctr++;
workDate = workDate.addDays(1); // move the calendar forward a day
}
return ctr;
}
var result = numOrdinalsBetweenDts(new Date("July 21, 1901"), new Date("July 21, 2014"), 2);
console.log(result);
alert(result);
There is a slightly counter-intuitive behavior in the Javascript Date constructor where if you create a new Date with the day set to 0, it will assume the last day of the month. You can the use the following function get the number of days in a month:
function daysInMonth(month, year) {
return new Date(year, month, 0).getDate();
}
The Javascript date object is leap-year aware, so you can use this function reliably.
You then just need to count the number of months between the start and end date and check each one to make sure the day number is actually present in the month. You can short-circuit this check if the day is less than or equal to 28.

the closest Sunday before given date with JavaScript

I need to know the date for last Sunday for given date in php & javascript
Let's have a function give_me_last_Sunday
give_me_last_Sunday('20110517') is 20110515
give_me_last_Sunday('20110604') is 20110529
The full backup is done on Sundays = weekly. If I want to restore daily backup I need full (weekly) and daily backup. I need to copy backup files before restoring to temp directory so I restoring daily backup I need to know what weekly backup file I need to copy along the daily file.
My thought was to get Julian representation (or something similar) for the given date and then subtract 1 and check if it is Sunday ... Not sure if this is the best idea and how to convert given date into something I can subtract.
Based on Thomas' effort, and provided the input string is exactly the format you specified, then:
function lastSunday(d) {
var d = d.replace(/(^\d{4})(\d{2})(\d{2}$)/,'$1/$2/$3');
d = new Date(d);
d.setDate(d.getDate() - d.getDay());
return d;
}
Edit
If I were to write that now, I'd not depend on the Date object parsing the string but do it myself:
function lastSunday(s) {
var d = new Date(s.substring(0,4), s.substring(4,6) - 1, s.substring(6));
d.setDate(d.getDate() - d.getDay());
return d;
}
While the format yyyy/mm/dd is parsed correctly by all browsers I've tested, I think it's more robust to stick to basic methods. Particularly when they are likely more efficient.
Ok so this is for JavaScript only. You have an input that you need to extract the month, date, and year from. The following is just partly an answer then on how to get the date:
<script type="text/javascript">
var myDate=new Date();
myDate.setFullYear(2011,4,16)
var a = myDate.getDate();
var t = myDate.getDay();
var r = a - t;
document.write("The date last Sunday was " + r);
</script>
So the setFullYear function sets the myDate to the date specified where the first four digits is the year, the next are is the month (0= Jan, 1= Feb.,...). The last one is the actually date. Then the above code gives you the date of the Sunday before that. I am guessing that you can add more code to get the month (use getMonth() method). Here are a few links that might be helpful
http://www.w3schools.com/js/js_obj_date.asp
http://www.w3schools.com/jsref/jsref_setFullYear.asp
http://www.w3schools.com/jsref/jsref_getMonth.asp
(You can probably find the other functions that you need)
I hope this helps a bit even though it is not a complete answer.
Yup and strtotime has been ported to JS for eg http://phpjs.org/functions/strtotime:554 here.
final code (big thanks to #Thomas & #Rob)
function lastSunday(d) {
var d = d.replace(/(^\d{4})(\d{2})(\d{2}$)/,'$1/$2/$3');
d = new Date(d);
d.setDate(d.getDate() - d.getDay());
year = d.getFullYear()+'';
month = d.getMonth()+1+'';
day = d.getDate()+'';
if ( month.length == 1 ) month = "0" + month; // Add leading zeros to month and date if required
if ( day.length == 1 ) day = "0" + day;
return year+month+day;
}

Subtracting date from an input field

I would like to have an input field with a button next to it.
On the input field I will enter a date like this:
2011-07-08
And when I hit the button it should read the time that has been entered on the input field and subtract it with 3 months and one day.
Is this possible?
Thanks in advance
Yes. First you read the date and you convert to a date object
var dateString = document.getElementById('id of your field').value,
date = new Date(dateString);
then you subtract 91 days and output the result
date.setDate(date.getDate() - 91);
alert(date.toString());
Here I assume for simplicity that you actually want 91 days and not 3 months and one day. If you want three months and one day you will do
date.setMonth(date.getMonth() - 3);
date.setDate(date.getDate() - 1);
alert(date.toString());
The Date object will take care of overflows, leap years and everything.
If you want to write it to same field, taking care of zeroes, you can do
function assureTwoDigits(number) {
if (number > 9) {
return '-' + number;
}
else {
return '-0' + number;
}
}
and change the last line to
document.getElementById('id of your field').value = date.getFullYear() + assureToDigits(date.getMonth()) + assureTwoDigits(date.getDate());
You can use Date objects (see here):
extract year, moth and day from the string (using a regular expression or splitting by '-')
buid a new Date object with that data
subtract the date interval
build the string back
The simplest way would be to split it into an array, then use a couple of if/else statements:
var date = (whatever you're pulling the date in as).split('-');
if (date[1] > 3)
date[1] = date[1] - 3;
else
date[0] = date[0] - 1;
var dateOverflow = date[1]-3;
date[1] = 12 - dateOverflow;
And then the same for the days.
Yes, it's possible and it's the most clean if you can do it without some arcane regex magic. Start by converting the date to a Date object:
// this will get you a date object from the string:
var myDate = new Date("2011-07-08");
// subtract 3 months and 1 day
myDate.setMonth(myDate.getMonth()-3);
myDate.setDay(myDate.getMonth(), myDate.getDay()-1);
// And now you have the day and it will be correct according to the number of days in a month etc
alert(myDate);

Categories

Resources