87

I want to get the date of the next Monday or Thursday (or today if it is Mon or Thurs). As Moment.js works within the bounds of a Sunday - Saturday, I'm having to work out the current day and calculate the next Monday or Thursday based on that:

if (moment().format("dddd")=="Sunday") { var nextDay = moment().day(1); }
if (moment().format("dddd")=="Monday") { var nextDay = moment().day(1); }
if (moment().format("dddd")=="Tuesday") { var nextDay = moment().day(4); }
if (moment().format("dddd")=="Wednesday") { var nextDay = moment().day(4); }
if (moment().format("dddd")=="Thursday") { var nextDay = moment().day(4); }
if (moment().format("dddd")=="Friday") { var nextDay = moment(.day(8); }
if (moment().format("dddd")=="Saturday") { var nextDay = moment().day(8); }

This works, but surely there's a better way!

XML
  • 19,206
  • 9
  • 64
  • 65
Mike Thrussell
  • 4,175
  • 8
  • 43
  • 59

10 Answers10

130

The trick here isn't in using Moment to go to a particular day from today. It's generalizing it, so you can use it with any day, regardless of where you are in the week.

First you need to know where you are in the week: moment().day(), or the slightly more predictable (in spite of locale) moment().isoWeekday(). Critically, these methods return an integer, which makes it easy to use comparison operators to determine where you are in the week, relative to your targets.

Use that to know if today's day is smaller or bigger than the day you want. If it's smaller/equal, you can simply use this week's instance of Monday or Thursday...

const dayINeed = 4; // for Thursday
const today = moment().isoWeekday();

if (today <= dayINeed) { 
  return moment().isoWeekday(dayINeed);
}

But, if today is bigger than the day we want, you want to use the same day of next week: "the monday of next week", regardless of where you are in the current week. In a nutshell, you want to first go into next week, using moment().add(1, 'weeks'). Once you're in next week, you can select the day you want, using moment().day(1).

Together:

const dayINeed = 4; // for Thursday
const today = moment().isoWeekday();

// if we haven't yet passed the day of the week that I need:
if (today <= dayINeed) { 
  // then just give me this week's instance of that day
  return moment().isoWeekday(dayINeed);
} else {
  // otherwise, give me *next week's* instance of that same day
  return moment().add(1, 'weeks').isoWeekday(dayINeed);
}

See also https://stackoverflow.com/a/27305748/800457


EDIT: other commenters have pointed out that the OP wanted something more specific than this: the next of an array of values ("the next Monday or Thursday"), not merely the next instance of some arbitrary day. OK, cool.

The general solution is the beginning of the total solution. Instead of comparing for a single day, we're comparing to an array of days: [1,4]:

const daysINeed = [1,4]; // Monday, Thursday
// we will assume the days are in order for this demo, but inputs should be sanitized and sorted

function isThisInFuture(targetDayNum) {
  // param: positive integer for weekday
  // returns: matching moment or false
  const todayNum = moment().isoWeekday();  

  if (todayNum <= targetDayNum) { 
    return moment().isoWeekday(targetDayNum);
  }
  return false;
}

function findNextInstanceInDaysArray(daysArray) {
    // iterate the array of days and find all possible matches
    const tests = daysINeed.map(isThisInFuture);

    // select the first matching day of this week, ignoring subsequent ones, by finding the first moment object
    const thisWeek = tests.find((sample) => {return sample instanceof moment});

    // but if there are none, we'll return the first valid day of next week (again, assuming the days are sorted)
    return thisWeek || moment().add(1, 'weeks').isoWeekday(daysINeed[0]);;
}
findNextInstanceInDaysArray(daysINeed);

I'll note that some later posters provided a very lean solution that hard-codes an array of valid numeric values. If you always expect to search the same days, and don't need to generalize for other searches, that'll be the more computationally efficient solution, although not the easiest to read, and impossible to extend.

Shahbaz
  • 3,433
  • 1
  • 26
  • 43
XML
  • 19,206
  • 9
  • 64
  • 65
  • Can you explain, how to calculate the previous occurrence ? Ex: Previous Wednesday from today ? – Vasanth Jun 30 '21 at 07:04
  • I think it would just be `moment.substract()` instead of `moment.add()`... – XML Jun 30 '21 at 16:50
  • 1
    Reduced the if-statement down to: `moment().add(+(today > dayINeed), 'weeks').isoWeekday(dayINeed)` More compact, but potentially less readable. – Ecksters Oct 27 '21 at 22:01
31

get the next monday using moment

moment().startOf('isoWeek').add(1, 'week');
AshUK
  • 1,225
  • 14
  • 9
  • Wouldn't this depend on what day is considered the start of the week in the locale that is used? – jorisw Sep 08 '17 at 11:32
  • 4
    As of version 2 @jorisw `startOf('week') uses the locale aware week start day.` – AshUK Sep 15 '17 at 15:14
  • 7
    and `.startOf('isoWeek')` ISO 8601 stipulates that weekday numbers, from 1 through 7, beginning with Monday and ending with Sunday – AshUK Sep 15 '17 at 15:20
16

moment().day() will give you a number referring to the day_of_week.

What's even better: moment().day(1 + 7) and moment().day(4 + 7) will give you next Monday, next Thursday respectively.

See more: http://momentjs.com/docs/#/get-set/day/

James Sumners
  • 14,485
  • 10
  • 59
  • 77
Gavriel
  • 18,880
  • 12
  • 68
  • 105
15

The following can be used to get any next weekday date from now (or any date)

var weekDayToFind = moment().day('Monday').weekday(); //change to searched day name

var searchDate = moment(); //now or change to any date
while (searchDate.weekday() !== weekDayToFind){ 
  searchDate.add(1, 'day'); 
}
vinjenzo
  • 1,490
  • 13
  • 13
5

Most of these answers do not address the OP's question. Andrejs Kuzmins' is the best, but I would improve on it a little more so the algorithm accounts for locale.

var nextMoOrTh = moment().isoWeekday([1,4,4,4,8,8,8][moment().isoWeekday()-1]);
David Kirk
  • 342
  • 3
  • 5
  • 1
    This is a super-efficient one-liner that is probably the fastest way to do the job (as long as we don't ever need to search for different days, or generalize the solution). – XML Jun 03 '19 at 10:21
  • This answer shows the beautiful art of writing code. – quemeful Jun 02 '22 at 17:23
4

Next Monday or any other day

moment().startOf('isoWeek').add(1, 'week').day("monday");
3

Here's a solution to find the next Monday, or today if it is Monday:

const dayOfWeek = moment().day('monday').hour(0).minute(0).second(0);

const endOfToday = moment().hour(23).minute(59).second(59);

if(dayOfWeek.isBefore(endOfToday)) {
  dayOfWeek.add(1, 'weeks');
}
2

IMHO more elegant way:

var setDays = [ 1, 1, 4, 4, 4, 8, 8 ],
    nextDay = moment().day( setDays[moment().day()] );
Rango
  • 3,877
  • 2
  • 22
  • 32
2

Here's e.g. next Monday:

var chosenWeekday = 1 // Monday

var nextChosenWeekday = chosenWeekday < moment().weekday() ? moment().weekday(chosenWeekday + 7) : moment().weekday(chosenWeekday)
softcode
  • 4,358
  • 12
  • 41
  • 68
  • Sorry but this isn't true. Your first example will give Monday of the current week. If it's already Tuesday for example it will give you the previous Monday. – Shannon Poole Apr 26 '17 at 17:58
2

The idea is similar to the one of XML, but avoids the if / else statement by simply adding the missing days to the current day.

const desiredWeekday = 4; // Thursday
const currentWeekday = moment().isoWeekday();
const missingDays = ((desiredWeekday - currentWeekday) + 7) % 7;
const nextThursday = moment().add(missingDays, "days");

We only go "to the future" by ensuring that the days added are between 0 and 6.

omg_me
  • 69
  • 1
  • 6