Get week number of the month from date (weeks starting on Mondays) - javascript

I have to find week number of the month from given date using JavaScript. Week start is Monday.
I have tried the code below but not getting accurate result.
function getWeekNumber(date) {
var monthStartDate = new Date(new Date().getFullYear(), new Date().getMonth(), 1);
monthStartDate = new Date(monthStartDate);
var day = monthStartDate.getDay();
date = new Date(date);
var date = date.getDate();
let weekNumber = Math.ceil((date + (day)) / 7);
return (weekNumber == 0) ? 1 : weekNumber;
}
var week = getWeekNumber('2020-04-04');
console.log(week);

Try this one
function getWeek(date) {
let monthStart = new Date(date);
monthStart.setDate(0);
let offset = (monthStart.getDay() + 1) % 7 - 1; // -1 is for a week starting on Monday
return Math.ceil((date.getDate() + offset) / 7);
}
getWeek(new Date(2019, 2, 14))

You could find the week number of the month for weeks starting on Monday (in line with the ISO week date system) by rolling the input date back to the previous Monday and then dividing the Monday date by 7 and rounding up to determine which week of the month the date falls in.
This approach will properly handle dates at the beginning of a month which actually fall in the last week of the previous month. For instance, 2020-04-04 is a Saturday in the week starting on 2020-03-30 (Monday), so it should return week 5 since it is part of the 5th week of March (and not part of the 1st week of April which starts on 2020-04-06, the first Monday in April).
For example (the split bit at the beginning is just to parse the date string rather than relying on new Date() to parse the string since that is not recommended due to browser inconsistencies):
const monthWeek = (s) => {
const [y, m, d] = s.split('-'); // parse date string
const date = new Date(y, m - 1, d); // create date object
date.setDate(d - ((date.getDay() + 6) % 7)); // adjust date to previous Monday
return Math.ceil(date.getDate() / 7); // return week number of the month
};
console.log(monthWeek('2020-04-04'));
// 5
console.log(monthWeek('2020-04-07'));
// 1

Related

How to determine if a Date is next week in Javascript?

What is a quick way to determine if a certain date:
is next week
is last week
is this week
etc
I am open to using Date, Moment, Date-fns, or Dayjs if any of those have a built-in method.
As of now, I am thinking of using getDay() and comparing if the date is not too far ahead and not too near to today.
Thanks,
This example is assuming you're defining "next week" as "7-14 days in the future", but you could tweak this answer to do whatever you want. This answer is intended to help understand how to perform this sort of operation on javascript Dates, not just this operation specifically.
Option 1: Determine how many days are between the target date and the current date by subtracting the current date from the target date
// store current date as "today"
var today = new Date();
// store 8 days from today as "later"
later = new Date();
later.setDate(later.getDate() + 8);
// Determine how many days are between the two dates by subtracting "today" from "later" and converting milliseconds to days
days = (later - today) / (1000 * 3600 * 24);
// Is "later" 7-14 days away?
console.log(days > 7 && days < 14); // true
Option 2: Store the start and end date and compare those to our target date
// store 8 days from today as "later"
later = new Date();
later.setDate(later.getDate() + 8);
// Store the start date
start = new Date();
start.setDate(start.getDate() + 7);
// Store the end date
end = new Date();
end.setDate(end.getDate() + 14);
// is "later" between the start and end date?
console.log(later > start && later < end); // true
One algorithm is to take both dates back to the start of the week, then get the number of weeks between the two, e.g.
// Get start of week (previous or current Monday)
function getWeekStart(d = new Date()) {
return new Date(d.getFullYear(), d.getMonth(), d.getDate() - (d.getDay() || 7) + 1);
}
// Get relative weeks difference
function getRelativeWeek(d = new Date()) {
let thisWeek = getWeekStart();
let targetWeek = getWeekStart(d);
let diffWeeks = Math.round((targetWeek - thisWeek) / (8.64e7*7));
// Convert to words
switch (true) {
case (diffWeeks < -1):
return Math.abs(diffWeeks) + ' weeks ago';
case (diffWeeks == -1):
return 'last week';
case (diffWeeks == 0):
return 'this week';
case (diffWeeks == 1):
return 'next week';
case (diffWeeks > 1):
return diffWeeks + ' weeks away';
default :
return 'dunno';
}
}
// Examples
let d = new Date();
// Current week
[new Date(+d - 25*8.64e7),
new Date(+d - 7*8.64e7),
d,
new Date(+d + 7*8.64e7),
new Date(+d + 25*8.64e7),
new Date(NaN)
].forEach(d => console.log(
d.toDateString() + ': ' + getRelativeWeek(d)
));
Note that 8.64e7*7 is approximately the number of milliseconds in a week. It may be ±3.6e6 depending on whether the week has a daylight saving boundary or not, which will cause a non–integer result after division. Rounding fixes that.

Given a date, how can I get the previous Monday in UTC format regardless of time zone?

I am given a unix timestamp like this: 1655402413 and am needing to find find the midnight of the Monday (in UTC/GMT format) of the same week, regardless of what day it is or what time zone. I then need to represent that Monday as a unix timestamp and return it. The function I have is as follows:
function findMonday(unixTimeStamp) {
let startDate = new Date(unixTimeStamp);
let startDay = startDate.getDay();
let diff = startDate.getDate() - startDay + (startDay === 0 ? -6 : 1);
let monday = new Date(startDate.setDate(diff));
monday.setHours(0, 0, 0, 0);
monday = new Date(monday).valueOf();
return monday;
}
That function almost works, but there are two problems, both related to the fact that the Date seems to always work with the user's current timezone:
If given a timestamp that evaluates to midnight on a Monday in UTC/GMT format, depending on the time zone of the user, it returns the Monday of the previous week (because startDate evaluates to the Sunday before the Monday), which is not good.
The monday that is returned is in local time, not UTC/GMT time.
This is driving me absolutely insane. Working with dates in JavaScript is a nightmare, and I would appreciate any direction you can give me.
Multiply the unix timestamp by 1000, and use the UTC methods like getUTCDate instead of getDate, setUTCHours instead of setHours etc..
Of course to return as unix time, just divide by 1000.
eg.
function findMonday(unixTimeStamp) {
let startDate = new Date(unixTimeStamp * 1000);
let startDay = startDate.getUTCDay();
let diff = startDate.getUTCDate() - startDay + (startDay === 0 ? -6 : 1);
let monday = new Date(startDate.setUTCDate(diff));
monday.setUTCHours(0, 0, 0, 0);
monday = new Date(monday).valueOf();
return monday;
}
const monday = findMonday(1655402413);
const unixMonday = Math.trunc(monday / 1000);
console.log('The Date: ' + new Date(monday).toISOString());
console.log('Unix time: ' + unixMonday);
As for Keith's answer but a little more concise. It returns seconds, not milliseconds. ;-)
// Given UNIX timestamp, return similar timestamp for
// previous UTC Monday at 00:00:00
let getLastUTCMonday = ts => {
let d = new Date(ts * 1e3);
d.setUTCDate(d.getUTCDate() - (d.getUTCDay() || 7) + 1);
return d.setUTCHours(0,0,0,0) / 1e3 | 0;
};
let ts = 1655402413;
let tsPriorMonday = getLastUTCMonday(ts)
console.log(
`Start date : ${new Date(ts*1e3).toUTCString()}\n` +
`Prior Monday: ${new Date(tsPriorMonday * 1e3).toUTCString()}`
);
In ECMA-262, offsets from the epoch (in milliseconds) are called "time values". A timestamp is anything that represents a time or date, so a time value is a timestamp. ;-)
Given that ECMAScript UTC days are always exactly 8.64e7 milliseconds long, you can work out the previous UTC Monday from today by some simple arithmetic.
The ECMAScript epoch was Thursday, 1 Jan 1970 00:00:00, so you can:
Subtract 4 UTC days worth of milliseconds (34.56e7) from the date to align with Monday instead of Thursday
Get the remainder of dividing that value by the number of milliseconds in 7 UTC days (7 * 8.64e7 or 60.48e7)
Subtract the remainder from the current date, which will return the previous Monday and also remove the time component
The above algorithm only works for dates after the epoch. Dates before then have time values are negative so add 3 days before getting the remainder, then subtract the remainder + 7 days (i.e. date - remainder - 7 days).
The following just does the post–epoch calculation:
let getPreviousUTCMonday = date => {
let weekRem = (date - 34.56e7) % 60.48e7;
return date - weekRem;
}
let d = new Date();
for (let i=0; i<12; i++) {
console.log(`${d.toUTCString()}\n` +
`${new Date(getPreviousUTCMonday(d)).toUTCString()}`);
d.setDate(d.getDate() + 1);
}

Get the past week 7 day period from a given date in Javascript

I am trying to get the date range of the past Wednesday to past Tuesday(7 days) from today's date.
Say the current date is 2022-05-01(May 1st), I am expecting the result to be the past Tuesday(end date) to Past Wednesday (start date = Past Tuesday -7 days)
i.e 20 April 2022 to 26 April 2022
function getStartAndEndDates () {
var now = new Date('2022-05-01'); //May 1st 2022
var day = now.getDay();
var diff = (day <= 2) ? (7 - 2 + day ) : (day - 2);
var PastTuesday = new Date();
var PastWednesday = new Date(PastTuesday.setDate(now.getDate() - diff));
console.log('End date is', PastTuesday.toISOString());
PastWednesday.setDate(PastTuesday.getDate() - 6);
console.log('Start Date is',PastWednesday.toISOString());
return[PastWednesday,PastTuesday];
}
Output obtained is:
End date is 2022-03-27T19:25:35.726Z //here month is set to March
Start Date is 2022-03-21T19:25:35.726Z
Expected Result is
End date is 2022-04-26T19:25:35.726Z // month is supposed to be April
Start Date is 2022-04-20T19:25:35.726Z
How can I change the code to get the expected result?
You should do something like
function getLastWeek(date) {
var today = new Date(date);
var lastWeek = new Date(today.getFullYear(), today.getMonth(), today.getDate() - 7);
return lastWeek;
}
// Your DATE
date = '2022-05-01'
//
var lastWeek = getLastWeek(date);
var lastWeekMonth = lastWeek.getMonth() + 1;
var lastWeekDay = lastWeek.getDate();
var lastWeekYear = lastWeek.getFullYear();
var lastWeekDisplay = lastWeekMonth + "/" + lastWeekDay + "/" + lastWeekYear;
console.log(lastWeekDisplay);
In your code:
var now = new Date('2022-05-01'); //May 1st 2022
Dates in the format YYYY-MM-DD are parsed as UTC, so the above will create a date object representing 2022-05-01T00:00:00Z.
var day = now.getDay();
This will return the local day number. For users with a zero or positive offset, it will return 0 (Sunday) but for users with a negative offset, it will return 6 (Saturday) because their local date is still the previous day.
var diff = (day <= 2) ? (7 - 2 + day ) : (day - 2);
Given day is 0 (for me), the above sets diff to 5.
var PastTuesday = new Date();
This creates a date for "now", which for me is 17 April.
var PastWednesday = new Date(PastTuesday.setDate(now.getDate() - diff));
In the above, now.getDate returns 1, and 1 - 5 is -4, so it sets the date for PastTuesday to -4. Now PastTuesday is in April, so it is set to 4 days prior to the start of April, i.e. 27 March.
Note that this adjusts PastTuesday and creates a copy for PastWednesday at the same time.
console.log('End date is', PastTuesday.toISOString());
Shows the equivalent UTC date and time, with the time representing the time that the code was run.
PastWednesday.setDate(PastTuesday.getDate() - 6);
Sets PastWednesday to 6 days prior to PastTuesday.
Anyhow, what is required is to do everything either as UTC or local, don't mix the two.
Sticking to code as closely as possible to the original and assuming a timestamp in YYYY-MM-DD format is parsed to the function, consider the following, which does everything as local:
// Parse timestamp in YYYY-MM-DD format as local
function parseISOLocal(s = new Date().toLocaleDateString('en-CA')) {
let [y, m, d] = s.split(/\D/);
return new Date(y, m-1, d);
}
// Get week Wed to Tue prior to passed date
function getStartAndEndDates (date) {
// Parse timestamp as local
var pastTuesday = parseISOLocal(date);
// Adjust pastTuesday to previous Tuesday
var day = pastTuesday.getDay();
var diff = (day <= 2) ? (7 - 2 + day ) : (day - 2);
var pastWednesday = new Date(pastTuesday.setDate(pastTuesday.getDate() - diff));
console.log('End date is', pastTuesday.toDateString());
// Adjust pastWednesday to previous Wednesday
pastWednesday.setDate(pastTuesday.getDate() - 6);
console.log('Start Date is',pastWednesday.toDateString());
return [pastWednesday, pastTuesday];
}
// Sunday 1 May 2022
console.log(getStartAndEndDates('2022-05-01').map(d => d.toDateString()));
// Current date
console.log(getStartAndEndDates().map(d => d.toDateString()));

Get Date of days of a week given year, month and week number (relative to month) in Javascript / Typescript

I want a function getDaysOfWeekDates that if I pass as parameters a year, a month (between 0 and 11) and a week of each month (usually each month has 4-5 weeks), it gives me a list of dates that contains each day of that week. For example:
function getDaysOfWeekDates(year: number, month: number, weekNumber: number): Array<Date> {
//...
}
const days: Date[] = getDaysOfWeekDates(2020, 0, 2) // Second week of January 2020
console.log(days);
/**
* 2020-01-06T00:00:00.000Z
* 2020-01-07T00:00:00.000Z
* 2020-01-08T00:00:00.000Z
* 2020-01-09T00:00:00.000Z
* 2020-01-10T00:00:00.000Z
* 2020-01-11T00:00:00.000Z
* 2020-01-12T00:00:00.000Z
*/
I was able to build a function getDaysOfWeekDates2 that works like this, but using a year and a week as parameter (week relative to year, each year has 52-53 weeks):
function getDaysOfWeekDates2(year: number, weekNumber: number) {
const [ startDate ] = getDateRangeOfWeek(year, weekNumber);
return new Array(7).fill(null).map((e, index) => {
return new Date(
startDate.getFullYear(),
startDate.getMonth(),
startDate.getDate() + index
);
});
}
function getDateRangeOfWeek(year: number, weekNumber: number){
const date = new Date(String(year));
const numOfdaysPastSinceLastMonday = date.getDay() - 1;
date.setDate(date.getDate() - numOfdaysPastSinceLastMonday);
date.setDate(date.getDate() + (7 * (weekNumber - getWeekNumber(date))));
const rangeIsFrom = new Date(date.getFullYear() + "-" +(date.getMonth() + 1) + "-" + date.getDate());
date.setDate(date.getDate() + 6);
const rangeIsTo = new Date(date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + + date.getDate());
return [rangeIsFrom, rangeIsTo];
};
function getWeekNumber(date: Date): number {
const dateCopy = new Date(date.getTime());
dateCopy.setHours(0, 0, 0, 0);
// Thursday in current week decides the year.
dateCopy.setDate(dateCopy.getDate() + 3 - (dateCopy.getDay() + 6) % 7);
// January 4 is always in week 1.
const week1 = new Date(dateCopy.getFullYear(), 0, 4);
// Adjust to Thursday in week 1 and count number of weeks from date to week1.
return 1 + Math.round(((dateCopy.getTime() - week1.getTime()) / 86400000 - 3 + (week1.getDay() + 6) % 7) / 7);
}
Any idea any idea how to modify getDaysOfWeekDates? to get the desired function getDaysOfWeekDates? Or just build it from scratch using some library?
If you want Monday as the first day of the week, and the first week of a month is the one with the first Thursday, then you can use a similar algorithm to the year week number function.
So get the start of the required week, then just loop 7 times to get each day. E.g.
/* Return first day of specified week of month of year
**
** #param {number|string} year - year for required week
** #param {number|string} month - month for required week
** Month is calendar month number, 1 = Jan, 2 = Feb, etc.
** #param {number|string} week - week of month
** First week of month is the one with the first Thursday
** #returns {Date} date for Monday at start of required week
*/
function getMonthWeek(year, month, week) {
// Set date to 4th of month
let d = new Date(year, month - 1, 4);
// Get day number, set Sunday to 7
let day = d.getDay() || 7;
// Set to prior Monday
d.setDate(d.getDate() - day + 1);
// Set to required week
d.setDate(d.getDate() + 7 * (week - 1));
return d;
}
// Return array of dates for specified week of month of year
function getWeekDates(year, month, week) {
let d = getMonthWeek(year, month, week);
for (var i=0, arr=[]; i<7; i++) {
// Array of date strings
arr.push(d.toDateString());
// For array of Date objects, replace above with
// arr.push(new Date(d));
// Increment date
d.setDate(d.getDate() + 1);
}
return arr;
}
// Week dates for week 1 of Jan 2020 - week starts in prior year
console.log(getWeekDates(2020, 1, 1));
// Week dates for week 5 of Jan 2020 - 5 week month
console.log(getWeekDates(2020, 1, 5));
// Week dates for week 1 of Oct 2020 - 1st is a Thursday
console.log(getWeekDates(2020, 10, 1));
// Week dates for week 1 of Nov 2020 - 1st is a Sunday
console.log(getWeekDates(2020, 11, 1));
It's not clear whether you want an array of Date objects or strings, so a Date object version is included in comments.

Why can't I display JUST the date (date, month, and year without time)?

I have some code, that is doing pretty much all i need it to do. Its calculating 3 days in the future, excluding dates, and then displaying my "estimated dispatch date"
The date, however displays in full date and time, instead of just date.
Day Month Date Year 12:02:57 GMT+0100 (British Summer Time)
Can anyone help with the code below, so that it excludes local time and only displays the future date, excluding weekend, DD/MM/YYYY or, in the below format;
Monday 20th June
Thanks in advance!
function addDates(startDate,noOfDaysToAdd){
var count = 0;
while(count < noOfDaysToAdd){
endDate = new Date(startDate.setDate(startDate.getDate() + 1));
if(endDate.getDay() != 0 && endDate.getDay() != 6){
//Date.getDay() gives weekday starting from 0(Sunday) to 6(Saturday)
count++;
}
}
return startDate;
}
var today = new Date();
var daysToAdd = 3;
document.write ('Estimated Dispatch Date: ' + addDates(today,daysToAdd));
You can use the toDateString method to display just the date portion of your Date object, but you will need to use a few other methods for full control over the format of your date string...
You can display just the date, month and year parts of your local date and time with a few extra lines of code using the getDate, getMonth, and getFullYear methods to help with the formatting. You could try passing specific formatting parameters to toLocaleString, but this may display different results in different browsers. For example, the code below outputs a date in the format dd/mm/yyyy in Chrome but that output is not guaranteed across browsers.
new Date().toLocaleString('en-GB', {year: 'numeric', month: 'numeric', day: 'numeric'})
Not sure I am following how you want to handle weekend dates, so the below handles the date formatting that you want in the formatDate function separately from the addDays function where it just handles weekend dates by rolling the date forward to a Monday if the initially calculated date lands on a Saturday or Sunday.
// format input date to dd/mm/yyyy
const formatDate = (date) => {
const d = date.getDate(); // day of the month
const m = date.getMonth(); // month index from 0 (Jan) to 11 (Dec)
const yyyy = date.getFullYear(); // 4 digit year
const dd = (d < 10 ? '0' : '') + d; // format date to 2 digit
const mm = (m + 1 < 10 ? '0' : '') + (m + 1); // convert index to month and format 2 digit
return `${dd}/${mm}/${yyyy}`;
};
// add input days to today and adjust for weekend output
const addDays = (today, days) => {
const now = today.getTime() // now in UTC milliseconds
const ms = 24 * 60 * 60000; // milliseconds in one day
const date = new Date((days * ms) + now); // today plus input days
const day = date.getDay(); // weekday index from 0 (Sun) to 6 (Sat)
// adjust weekend results to next weekday
if (day === 0 || day === 6) {
let adj = day === 0 ? 1 : 2;
return new Date(((days + adj) * ms) + now);
}
return date;
};
document.write('Estimated Dispatch Date: ' + formatDate(addDays(new Date(), 3)));

Categories