I'm trying to make a function to get all the days of the week given the current day. I had a function that i thought was working until i noticed that if the day of the week is near the end of the month, like for example February, i get weird data. Anyone know whats going on and how to fix it?
function days(current) {
var week = new Array();
// Starting Monday not Sunday
var first = ((current.getDate() - current.getDay()) + 1);
for (var i = 0; i < 7; i++) {
week.push(
new Date(current.setDate(first++))
);
}
return week;
}
var input = new Date(2017, 1, 27);
console.log('input: %s', input);
var result = days(input);
console.log(result.map(d => d.toString()));
.as-console-wrapper{min-height:100%}
If you don't want to use some kind of other library like Moment.js you can also change your function a little and then it will work. Try this:
function dates(current) {
var week= new Array();
// Starting Monday not Sunday
current.setDate((current.getDate() - current.getDay() +1));
for (var i = 0; i < 7; i++) {
week.push(
new Date(current)
);
current.setDate(current.getDate() +1);
}
return week;
}
console.log(dates(new Date(2017, 1, 27)));
You can use Moment.js library - utility library for dates/time operations
Here's examplary code to get current week's dates starting from monday:
function getThisWeekDates() {
var weekDates= [];
for (var i = 1; i <= 7; i++) {
weekDates.push(moment().day(i));
}
return weekDates;
}
var thisWeekDates = getThisWeekDates();
thisWeekDates.forEach(function(date){ console.log(date.format());});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.js"></script>
The code above prints following results to the console:
2017-03-20T21:26:27+01:00
2017-03-21T21:26:27+01:00
2017-03-22T21:26:27+01:00
2017-03-23T21:26:27+01:00
2017-03-24T21:26:27+01:00
2017-03-25T21:26:27+01:00
2017-03-26T21:26:27+02:00
I will trace your code using your example of Feb 27, 2017:
first = 27 - 1 + 1 = 27
loop:
Feb.setDate(27) = 27 feb
Feb.setDate(28) = 28 feb
Feb.setDate(29) = Not 29 days in Feb. So it sets current to 29-28 = 1st day of March
March.setDate(30) = March 30
March.setDate(31) = March 31
March.setDate(32) = Not 32 days in March. So it sets current to 31-32 = 1st of April..
April.setDate(33) = Not 33 days in April. So it sets current day 33-30 = 3rd day of May.
Please note that I used the shorthand of Month.setDate() to show the month of the current Date object when it was being called.
So the issue is with your understanding of setDate that is being used on current. It changes the month and if the value you use isn't a day in the month it adjusts the month and day appropriately. I hope this cleared things up for you.
For how to add one to a date, see Add +1 to current date. Adapted to your code, you can set current to the first day of the week then just keep adding 1 day and pushing copies to the array:
function days(current) {
var week = [];
// Starting Monday not Sunday
var first = current.getDate() - current.getDay() + 1;
current.setDate(first);
for (var i = 0; i < 7; i++) {
week.push(new Date(+current));
current.setDate(current.getDate()+1);
}
return week;
}
var input = new Date(2017, 1, 27);
console.log('input: %s', input);
var result = days(input);
console.log(result.map(d => d.toString()));
Note that this changes the date passed in (per the original code), you may want to make current a copy to avoid that.
Suppose monday starts the week, you can calculate monday and go to sunday. getDategives you the day of the week, and Sunday starts at 0. With momnday, we get just offset forward to 6 days to get sunday
mondayThisWeek(date: Date): Date {
const d = new Date(date)
const day = d.getDay()
const diff = d.getDate() - day + (day === 0 ? -6 : 1)
return new Date(d.setDate(diff))
}
const offsetDate = (base: Date, count: number): Date => {
const date = new Date(base)
date.setDate(base.getDate() + count)
return date
}
thisWeek(today: Date): TimeRange {
const monday = mondayThisWeek(today)
return {
startDate: monday,
endDate: offsetDate(monday, 6)
}
}
This can be achieved easly using moment
const getWeekDates = () => {
let weekDates = [];
for (let i = 0; i < 7; i++)
weekDates.push(moment().add(i, 'd'));
return weekDates;
};
console.log(getWeekDates());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.js"></script>
Related
How can I achieve this sequence of date output if the user input is 04-29-2022 and the output is like this
What I want:
2022-05-14
2022-05-29
2022-06-14
2022-06-29
2022-07-14
2022-07-29
2022-08-14
2022-08-29
my code output
2022-05-13
2022-05-28
2022-06-12
2022-06-27
2022-07-12
2022-07-27
2022-08-11
2022-08-26
var dateRelease = new Date("04-29-2022")
const terms = 8
for (let i = 0; i < terms; i++) {
console.log(new Date(dateRelease.setDate(dateRelease.getDate() + 15)).toISOString().slice(0, 10))
}
Here is a function that takes the day of the month in the given date and determines which other date of the month would be needed in the output (either 15 more or 15 less). Then it generates dates alternating between those two date-of-the-month, and when it is the lesser of those two, incrementing the month. In case a date is invalid and automatically overflows into the next month, it is corrected to the last day of the intended month.
To format the date in the output, it is better to not use toISODateString as that interprets the date as a UTC Date, while new Date("2022-04-29") interprets the given string as a date in the local time zone. This can lead to surprises in some time zones. So I would suggest using toLocaleDateString with a locale that produces your desired format.
Here is the code:
function createSchedule(date, count) {
date = new Date(date);
let day = date.getDate();
let k = +(day > 15);
let days = k ? [day - 15, day] : [day, day + 15];
let result = [];
for (let i = 0; i < count; i++) {
k = 1 - k;
date.setDate(days[k]);
// When date overflows into next month, take last day of month
if (date.getDate() !== days[k]) date.setDate(0);
if (!k) date.setMonth(date.getMonth() + 1);
result.push(date.toLocaleDateString("en-SE"));
}
return result;
}
var dateRelease = new Date("2022-04-29");
var result = createSchedule(dateRelease, 25);
console.log(result);
var dateRelease = new Date("04-29-2022")
const terms = 8
for (let i = 0; i < terms; i++) {
let date = new Date(dateRelease.setDate(dateRelease.getDate() + 15)).toLocaleDateString('en-US');
let format = date.split('/').map(d => d.padStart(2 ,'0')).join('-')
console.log(format);
}
I need to get the next 4 Thursdays with javascript, and append the result into a select box but if the current date is past Sunday, don't get the first Thursday (start a week later).
So for example:
Current date = Saturday 12th June 2021
Get Next 4 Thursdays: 17th June 2021, 24th June 2021, 1st July 2021, 8th July 2021.
Current Date = Tuesday 15th June 2021 -- Don't get 17th June 2021, so list would be:
24th June 2021, 1st July 2021, 8th July 2021, 15th July 2021.
I had some code originally that would get the thursdays for X amount of months, but this isn't quite what I want, as it gets all thursdays in one month, rather than the next 4 thursdays. I'm guessing I can reuse the get day of the week code, and modify it to just get the next 4 days... then somehow filter if the date is past Sunday?
function getNextMonths(num) {
let current = new Date();
let months = [];
for (let i = 0; i <= num; i++) {
let next = new Date();
next.setDate(1); // First day...
next.setMonth(current.getMonth() + i); //...of next month
months.push(next);
}
return months;
}
function getDayOfWeek(num_week_day, dates) {
let days = [];
var today = new Date();
for (let i = 0; i < dates.length; i++) {
// Evaluate current month
let current = {
year: dates[i].getFullYear(),
month: dates[i].getMonth()
};
current.days = new Date(current.year, current.month + 1, 0).getDate();
// Loop & evaluate days
for (let d = 1; d <= current.days; d++) {
let date = new Date(current.year, current.month, d);
if (date.getDay() == num_week_day) {
if(date.getTime() > today.getTime()){
days.push(date);
}
}
}
}
return days;
}
//Convert to Nice looking Date
function dateToString(date){
return date.toLocaleDateString("en-GB", {
dateStyle: 'full'
});
}
//Output date as mm/dd/yyyy for ouput value
function dateToValue(date){
return date.toLocaleDateString("en-GB", {
year: "numeric",
month: "short",
day: "numeric",
});
}
// Get all Thursdays (4th day of the week) within the next 2 months.
var select = document.getElementById("arr");
var elmts = getDayOfWeek(4, getNextMonths(1));
// Main function
jQuery( document ).ready(function() {
jQuery('#sub_start_date').find('option').remove();
jQuery.each(elmts, function(i, p) {
jQuery('#sub_start_date').append(jQuery('<option></option>')
.val(dateToValue(p)).html(dateToString(p)));
});
});
In my eyes your code is incomplete so I cannot run in my own enviroment. My suggestion for you is though quite simple:
You store your dates in an array elmts and you loop through it to create all option elements.
My suggestion is:
Create always five dates
Depends on the daynumber remove the first or the last entry from array elmts.
Javascript offers two methods for it:
The method .shift() removes the first element from an array (see also https://www.w3schools.com/jsref/jsref_shift.asp ).
The method .pop() removes the last element from an array (see also https://www.w3schools.com/jsref/jsref_pop.asp ).
Based on https://gomakethings.com/how-to-get-the-date-for-a-specific-day-of-the-week-with-vanilla-js/
My code:
/* Some nassecary preconditions */
var datebase = new Date();
var targetDaynumber = 4;
var currentDiff = new Date().getDay();
/* Calculates a timestamp based on your wished weekday */
var getNextDay = function (basedate) {
// The current day
var now = basedate.getDay();
var diff = targetDaynumber - now;
diff = diff < 1 ? 7 + diff : diff;
// Get the timestamp for the desired day
var nextDayTimestamp = basedate.getTime() + (1000 * 60 * 60 * 24 * diff);
// Get the next day
return new Date(nextDayTimestamp);
};
/* ------------------------------------------------- */
/* Creating five timestamps */
var dateArray = [];
var loopindex = 5;
for (x = 0; x < loopindex; x++)
{
datebase = getNextDay(datebase);
dateArray.push(datebase);
}
/* Calculating the timegap */
if (currentDiff <= targetDaynumber) {
//Timegap is too small, remove the earliest timestamp
dateArray.shift();
} else {
//Timegap is ok, the fith element is not nassecary
dateArray.pop();
}
I am using Moment.js and it is great. The problem I have now is that I can't figure out how to get the week of the month a certain date is. I can only find "week of year" in the Moment js docs. For example, if I choose today's date (2/12/2014), I would like to know that this date is in the second week of this month of february and consequently, it is the second wednesday of the month. Any ideas?
EDIT:
I guess some clarification is necessary. What I need most is the nth number of a certain day in a month. For example, (from the comments) Feb 1, 2014 would be the first Saturday of the month. Feb 3, 2014 would be the first Monday of the month even though it is "technically" the second week of the month. Basically, exactly how google calendar's repeat function classifies days.
It seems that moment.js does not have the method that implements the functionality that you are looking for.
However, you can find the nth number of a certain day of the week in a month is using the Math.ceil of the date / 7
For example:
var firstFeb2014 = moment("2014-02-01"); //saturday
var day = firstFeb2014.day(); //6 = saturday
var nthOfMoth = Math.ceil(firstFeb2014.date() / 7); //1
var eightFeb2014 = moment("2014-02-08"); //saturday, the next one
console.log( Math.ceil(eightFeb2014.date() / 7) ); //prints 2, as expected
It looks like this is the number you are looking for, as demonstrated by the following test
function test(mJsDate){
var str = mJsDate.toLocaleString().substring(0, 3) +
" number " + Math.ceil(mJsDate.date() / 7) +
" of the month";
return str;
}
for(var i = 1; i <= 31; i++) {
var dayStr = "2014-01-"+ i;
console.log(dayStr + " " + test(moment(dayStr)) );
}
//examples from the console:
//2014-01-8 Wed number 2 of the month
//2014-01-13 Mon number 2 of the month
//2014-01-20 Mon number 3 of the month
//2014-01-27 Mon number 4 of the month
//2014-01-29 Wed number 5 of the month
When calculating the week of the month based on a given date, you have to take the offset into account. Not all months start on the first day of the week.
If you want to take this offset into account, you can use something something like the following if you are using moment.
function weekOfMonth (input = moment()) {
const firstDayOfMonth = input.clone().startOf('month');
const firstDayOfWeek = firstDayOfMonth.clone().startOf('week');
const offset = firstDayOfMonth.diff(firstDayOfWeek, 'days');
return Math.ceil((input.date() + offset) / 7);
}
Simple using moment.js
function week_of_month(date) {
prefixes = [1,2,3,4,5];
return prefixes[0 | moment(date).date() / 7]
}
This library adds the function moment.weekMonth()
https://github.com/c-trimm/moment-recur
I made some modifications based on feedback.
let weeks = moment().weeks() - moment().startOf('month').weeks() + 1;
weeks = (weeks + 52) % 52;
On days passing through the next year, the week value will be negative so I had to add 52.
What about something like:
weekOfCurrentMonth = (moment().week() - (moment().month()*4));
This takes the current week of the year, and subtracts it by the 4 times the number of previous months. Which should give you the week of the current month
I think the answer to this question will be helpful, even though it doesn't use moment.js as requested:
Get week of the month
function countWeekdayOccurrencesInMonth(date) {
var m = moment(date),
weekDay = m.day(),
yearDay = m.dayOfYear(),
count = 0;
m.startOf('month');
while (m.dayOfYear() <= yearDay) {
if (m.day() == weekDay) {
count++;
}
m.add('days', 1);
}
return count;
}
There is a problem with #Daniel Earwicker answer.
I was using his function in my application and the while loop was infinite because of the following situation:
I was trying to figure out which week of december (2016) was the day 31.
the first day of december was day 336 of the year. The last day of december was day 366 of the year.
Problem here: When it was day 366 (31 of december, last day of the year) the code added another day to this date. But with another day added it would be day 1 of january of 2017. Therefore the loop never ended.
while (m.dayOfYear() <= yearDay) {
if (m.day() == weekDay) {
count++;
}
m.add('days', 1);
}
I added the following lines to the code so the problem would be fixed:
function countWeekdayOccurrencesInMonth(date) {
var m = moment(date),
weekDay = m.day(),
yearDay = m.dayOfYear(),
year = m.year(),
count = 0;
m.startOf('month');
while (m.dayOfYear() <= yearDay && m.year() == year) {
if (m.day() == weekDay) {
count++;
}
m.add('days', 1);
}
return count;
}
It verifies if it is still in the same year of the date being veryfied
Here's Robin Malfait's solution implemented with the lightweight library date-fns
import {
differenceInDays,
startOfMonth,
startOfWeek,
getDate
} from 'date-fns'
const weekOfMonth = function (date) {
const firstDayOfMonth = startOfMonth(date)
const firstDayOfWeek = startOfWeek(firstDayOfMonth)
const offset = differenceInDays(firstDayOfMonth, firstDayOfWeek)
return Math.ceil((getDate(date) + offset) / 7)
}
export default weekOfMonth
I'd do the following:
let todaysDate = moment(moment.now());
let endOfLastMonth = moment(get(this, 'todaysDate')).startOf('month').subtract(1, 'week');
let weekOfMonth = todaysDate.diff(endOfLastMonth, 'weeks');
That gets todaysDate and the endOfLastMonth and then uses Moment's built-in diff() method to compute the current month's week number.
It's not built-in, but basically you can subtract the week number of the start of the month from the week number of the date in question.
function weekOfMonth(m) {
return m.week() - moment(m).startOf('month').week() + 1;
}
Credit goes to code by original author, give him a star if it helped you.
How about this?
const moment = require("moment");
// Generate Week Number of The Month From Moment Date
function getWeekOfMonth(input = moment()) {
let dayOfInput = input.clone().day(); // Saunday is 0 and Saturday is 6
let diffToNextWeek = 7 - dayOfInput;
let nextWeekStartDate = input.date() + diffToNextWeek;
return Math.ceil((nextWeekStartDate) / 7);
}
Simple code, but has been working for me.
const weekOfTheMonth = (myMomentDate) => {
const startDay = moment(myMomentDate).startOf('week');
const day = parseInt(startDay.format('DD'),10);
if(day > 28){
return 5;
}
if((day > 21) && (day <= 28) ){
return 4;
}
if((day > 14) && (day <= 21) ){
return 3;
}
if((day > 7) && (day <= 14) ){
return 2;
}
return 1;
}
I am trying to display the date of the last Wednesday in the current month... so that it will automatically change to the correct date when the next month occurs. (So instead of having to say: "Performing the last wednesday of every month", I can dymanmically give the actual date.)
For example, I would want the date to show on the webpage as Wednesday, Sept 25th for this month, and then appear as Wednesday, Oct 30th next month.
A bonus additional solution would be if I could get the next month's date to display after the previous date has past. In my above example, when the current date is Sept 26-30 (any date after that last wednesday, but still in the same month).. the date would show the next performance date of Oct 30th.
It would be great if the solution was through html, javascript/jquery or asp.
Thanks,
SunnyOz
It depends on your criteria for "easy". Here's a simple function to do as required, it's 5 lines of working code that can be reduced to 4, but will lose a bit of clarity if that's done:
function lastDayInMonth(dayName, month, year) {
// Day index map - modify to suit whatever you want to pass to the function
var dayNums = {Sunday: 0, Monday:1, Tuesday:2, Wednesday:3,
Thursday:4, Friday:5, Saturday:6};
// Create a date object for last day of month
var d = new Date(year, month, 0);
// Get day index, make Sunday 7 (could be combined with following line)
var day = d.getDay() || 7;
// Adjust to required day
d.setDate(d.getDate() - (7 - dayNums[dayName] + day) % 7);
return d;
}
You can change the map to whatever, just determine what you want to pass to the function (day name, abbreviation, index, whatever) that can be mapped to an ECMAScript day number.
Edit
So in the case of always wanting to show the last Wednesday of the month or next month if it's passed:
function showLastWed() {
var now = new Date();
var lastWedOfThisMonth = lastDayInMonth('Wednesday', now.getMonth()+1, now.getFullYear());
if (now.getDate() > lastWedOfThisMonth().getDate()) {
return lastDayInMonth('Wednesday', now.getMonth()+2, now.getFullYear());
} else {
return lastWedOfThisMonth;
}
}
Note that the function expects the calendar month number (Jan = 1, Feb = 2, etc.) whereas the getMonth method returns the ECMAScript month index (Jan = 0, Feb = 1, etc.) hence the +1 and +2 to get the calendar month number.
You could use a javascript library such as moment.js:
http://momentjs.com/
and then get it with this:
moment().add('months', 1).date(1).subtract('days', 1).day(-4)
Here is an approach in JS:
var monthLengths = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
function getLastWednesday() {
var d = new Date();
var month = d.getMonth();
var lastDay = monthLengths[month];
// mind leap years
if (month == 1) {
var year = d.getFullYear();
var isLeapYear = ((year % 4 == 0 && year % 100 > 0) || year % 400 == 0);
if (isLeapYear) lastDay++;
}
// get the weekday of last day in the curent mont
d.setDate(lastDay);
var weekday = d.getDay();
// calculate return value (wednesday is day 3)
if (weekday == 3) {
return lastDay;
}
else {
var offset = weekday - 3;
if (offset < 0) offset += 7;
return lastDay - offset;
}
}
I prefer to use an abstraction like moment.js as #Aralo suggested. To do it in raw JavaScript, however, you can use some code like this... create a function that gets all the days in a month. Then reverse-traverse the list to find the last day number. Wednesday is 3.
function getDaysInMonth(date) {
var dayCursor = new Date(today.getFullYear(), today.getMonth()); // first day of month
var daysInMonth = [];
while(dayCursor.getMonth() == date.getMonth()) {
daysInMonth.push(new Date(dayCursor));
dayCursor.setDate(dayCursor.getDate() + 1);
}
return daysInMonth;
}
function findLastDay(date, dayNumber) {
var daysInMonth = getDaysInMonth(date);
for(var i = daysInMonth.length - 1; i >= 0; i--) {
var day = daysInMonth[i];
if(day.getDay() === dayNumber) return day;
}
}
Then, to get the last Wednesday in the current month:
var today = new Date();
var lastWednesday = findLastDay(today, 3);
(first, sorry for my bad english, i'm a beginner)
I have a chart of percent by date. I would like to display every day of the current week in the x-axis.
So, i tried to find how to get the seven days of the week.
that's what i have :
var curr = new Date; // get current date
var first = curr.getDate() - curr.getDay();//to set first day on monday, not on sunday, first+1 :
var firstday = (new Date(curr.setDate(first+1))).toString();
for(var i = 1;i<7;i++){
var next = first + i;
var nextday = (new Date(curr.setDate(next))).toString();
alert(nextday);
}
the alert begins well...until the end of the month. That's what i got :
1 : "Mon 27 Feb 2012 ..."
2 : "Tue 28 Feb 2012 ..."
3 : "Wed 29 Feb 2012 ..."
4 : "Thu 01 Mar 2012 ..."
5 : "Sat 31 Mar 2012 ..."
6 : "Sun 01 Apr 2012 ..."
So, as you can see, it switches the friday and... strangely it switch to the good date...4 weeks later...
So, do you have a better solution for me, or maybe you could just help me and say what is the problem.
Thank you!
I'm afraid you have fallen into one of the numerous traps of object mutation. :)
The problem is that, in the line "var nextday = ...", you are changing the date saved in "curr" on every iteration by calling setDate(). That is no problem as long as next is within the range of the current month; curr.setDate(next) is equivalent to going forward one in this case.
The problems begin when next reaches 30. There is no February 30, so setDate() wraps around to the next month, yielding the 1st of March - so far so good. Unfortunately, the next iteration calls curr.setDate(31), and as curr is the 1st of March (remember that the object referenced by curr is changed in each iteration), we get... March 31! The other strange values can be explained the same way.
A way to fix this is to copy curr on each iteration and then call setDate(), like so:
for (var i = 1; i < 7; i++) {
var next = new Date(curr.getTime());
next.setDate(first + i);
alert(next.toString());
}
Thank you all,
I understood that everytime i change the curr value and that was the problem.
All your solutions are working, but i'll prefer the simplest one, the one from #denisw, which I copy there for anybody else with the same problem :
var curr = new Date; // get current date
var first = curr.getDate() - curr.getDay();
var firstday = (new Date(curr.setDate(first+1))).toString();
for(var i = 1; i < 7; i++) {
var next = new Date(curr.getTime());
next.setDate(first+i);
alert(next.toString());
}
Once again, thank you all, for your quick answers and your help!
You can add date and day. The former goes from 1 to 28..31 and the latter from 0 to 6. What should the Date type do if you set the date to -3?
The solution is to convert all values to milliseconds.
var ONE_DAY_IN_MILLIS = 1000*60*60*24;
var curr = new Date();
// Get offset to first day of week
// Note: Depending on your locale, 0 can be Sunday or Monday.
var offset = curr.getDay() * ONE_DAY_IN_MILLIS;
// Date at the start of week; note that hours, minutes and seconds are != 0
var start = new Date( curr.getTime() - offset );
for( var i=0; i<7; i++ ) {
var nextDay = new Date( start.getTime() + ( i * ONE_DAY_IN_MILLIS ) );
...
}
The problem is that you are modifying your curr date and creating a new date at the same time. There are two ways to do this:
Either never modifiy your curr date object and create new Dates:
var msInDay = 1000 * 60 * 60 * 24;
function addDays(date, days) {
return new Date(date.getTime() + days * msInDay);
}
var curr = new Date();
var first = addDays(curr, -curr.getDay() + 1);
alert(first);
for(var i = 1; i<7; i++) {
var next = addDays(first, i);
alert(next);
}
Or modify your curr date object consistently:
var curr = new Date();
curr.setDate(curr.getDate() - curr.getDay() + 1);
alert(curr);
for(var i = 1; i<7; i++) {
curr.setDate(curr.getDate() + 1);
alert(curr);
}
let curr = new Date;
let week = []
for (let i = 1; i <= 7; i++) {
let first = curr.getDate() - curr.getDay() + i
let day = new Date(curr.setDate(first)).toISOString().slice(0, 10)
week.push(day)
}
console.log('week:', week);
jsfidde: https://jsfiddle.net/sinh_nguyen/v9kszn2h/4/