For general information, and more code in various languages, see my Calendar Weeks and Week Number Calculation.
The last X-day (X in Mon..Sat) can always be treated as the zeroth X-day of the following month.
Operations using setDate() do not change the civil time, unless the missing hour in Spring is met.
To set a Date Object to the start or end of the current week, where Day is any of Mon=1..Sun=7 (or 0) ; i.e. to go back or forward by 0 to 6 days :-
One may need to set the Time part, e.g. by setHours(0,0,0,0).
For the next or previous X-day of a Date Object D :-
Test those. For the next-but-N X-day, include a term 7*N in the addition.
For the nearest X-day of a Date Object D :-
To get the N'th X-day of a given year and month,
For the last X-day of a month, one can use the Zeroth X-day of the following month, by just incrementing the second argument of the constructor.
For the first X-day of the current month, the following looks about right. The number 90+X controls the day-of-week sought, and must include enough multiples of 7 that the argument of %7 cannot be negative. In 90+X the second digit is the ISO DoW number, Mon=1..Sun=7; and the first, being 9, is memorable.
In these, the X-day of the Date Object is not changed.
One can add 28 days, test, and maybe move on; or add 35 days, test, and maybe move back; the move can use if or while; these choices affect only initial convergence.
To step Date Object D as the first X-day of a month, add 35 days to D, and if the day-of-month is greater than 7 then go back a week.
The code will always give the first X-day of the next month.
For the 2nd, 3rd, or 4th X-day, step the first X-day, and offset the result by 1, 2, or 3 weeks. Events don't get scheduled for the 5th X-day of a month.
To step Date Object D as the last X-day of a month, determine the number of the following month, add 35 days to D, and if the month is wrong then go back a week.
Note that, started before the last X-day, the code will move towards it.
To step Date Object D as the last X-day of a month, add 35 days to D, and if the day-of-month is wrong then go back a week.
Note that, started before the last X-day, the code will move towards it, differently.
For the last-but-one X-day, step the last X-day, and offset the result by a week.
A Date Object, D, can be changed to the nearest weekday by W = D.getDay() if (W==0) D.setDate(D.getDate()+1) if (W==6) D.setDate(D.getDate()-1) or by W = D.getDay() D.setDate(D.getDate() + (W==0) - (W==6) ) or by D.setDate(D.getDate() + [1,0,0,0,0,0,-1][D.getDay()])
A Date Object, D, can be reduced to Friday by W = D.getDay() if (W==0) D.setDate(D.getDate()-2) if (W==6) D.setDate(D.getDate()-1) or by W = D.getDay() D.setDate(D.getDate() - (W==0) - (W%6==0) ) or by D.setDate(D.getDate() - [2,0,0,0,0,0,1][D.getDay()]) or by while (D.getDay()%6==0) D.setDate(D.getDate()-1)
Forward from weekend to Monday should now be obvious enough.
Weeks, by International Standard ISO 8601, are Monday-Sunday, days 1-7. A week belongs to the calendar year in which most of it lies, which is that containing its Thursday. A year has 52 or 53 complete weeks, numbered from 1. A function converting between YMD and YWD must in each case also return the Year, since that may differ.
For more general information, see in my Calendar Weeks and Week Number Calculation, which contains some more code, including Year-Week-Day to/from CJD.
For adding Week Number methods to the Date Object, see 8: Enhancing the Object.
This should be simplest. For dates before 1970, add a sufficient multiple of 7 to d+3 or to the result of the division. For non-standard numbering, adjust the first 1 and/or the 3.
Note that only Sunday has a different number.
Now in Week Number Calculation.
For counting in Weekdays, here taking the Weekdays as being Mon-Fri, subtract absolute weekday counts (see source). These should start with an arbitrary early Monday being Weekday 0; 1969-12-29 seems suitable. But see also in Date and Day Count.
* Using GMT Dates ! *
Weekdays Difference is now just the difference in UTCWeekDayCount; Weekdays Ahead requires UTCCDW, the inverse function to UTCWeekDayCount.
* Using Local Dates ! THIS SECTION NEWER *
In this code, the Dates supplied should have no time component (up to a few hours may be OK).
Weekdays Difference is now just the difference in LclWeekDayCount; Weekdays Ahead requires LclCDW, the inverse function to LclWeekDayCount.
Functions for counting a specified Day-of-Week, which also serve to count weeks themselves :-
* GMT Dates ! *
* Using Local Dates ! THIS SECTION NEWER *
The counts for the different days of the week can be said to have a common origin, Sunday 1969-12-28.
In the general case, one may need to work in terms of the civil working days in supplier's time, which may differ from that of the customer's system; for Auckland-Vancouver trade the difference may be important. One may want to add setHours(0,0,0,0) to these.
For Web use, consider very carefully all effects of time zone and summer time differences, etc. Working Days will usually be those of the supplier.
The initial Date should be moved ahead to the start of the working day; for this, one can probably ignore Summer Time, and work as if the supplier has a fixed offset from GMT. The code should know the supplier's Time Zone.
In user's civil days :-
For a UK Weekday, Mon..Fri, we need getDay()%6!=0 . Some others have different weekdays.
For a day to be a UK Working Day, it must be in Mon..Fri, and not a Holiday. Some others have different working days.
Here, "ten clear days" means a part-day, ten days, and perhaps a part-day. It disregards the initial day.
Some of these routines step a Date, day-by-day. If one must cover a large span of time, a better method should be sought.
Always test these carefully, especially for end-effects.
This works in Browser Local Time, adds new functions to Date Objects, seems about OK.
For arithmetic with Working Hours, Minutes, etc., use the same approach as above; create a function to return the count of units since a suitable arbitrary datum.