How to sellect all same weekdays by using momentJS? Ex: All Mondays of current month. If the day is 15th day of the month, there are two Mondays in that month, from 0 to 15th day of the month. Maybe it is some kind of looping, because momenthJS should return two dates-one for first Monday and second for second Monday in the given range and so on.
Or is there any other way to do this by using any other JavaScript library?
As you said a loop can solve this problem
move 4 weeks before from the date you have e.g. if we were on the last monday of the month we move to the first monday of the month or a previous date (if we move to the previous month we can still get the correct dates by doing more iterations)
get the month of the date you have (all the dates you get should have the same month)
move forward from the initial date computed above a week each time and check if the new date has the same month as the input date
function weekdaysFromMonth (date) {
// all the weekdays previous/next to date should be
// 7 days apart and also have the same month
var month = date.get('month')
// make sure that the start date is 4 weeks before now
// we might go to the previous month but anyway we'll
// get the correct dates by doing more iterations
var start = moment(date).subtract(4 * 7, 'days')
var dates = []
for (var i = 0; i < 10; i += 1) {
start.add(7, 'days')
if (start.get('month') === month) {
dates.push(moment(start))
}
}
return dates
}
document.write(
JSON.stringify(
weekdaysFromMonth(moment()), null, ' '
)
)
<script src="http://momentjs.com/downloads/moment.js"></script>
Related
I want to get the date for the next coming Sunday at 15:30 JST.
How to do that?
I got a string "Sunday 15:00 JST" and what I need to do is, convert that into the closest coming Sunday 15:00 JST and then turn all of that into Unix epoch time. I might run this code on any day of the week for any day of the week not just Sunday.
js
const currentDate = new Date();
// Sunday - Saturday : 0 - 6.
const currentDayOfWeek = currentDate.getDay();
// 1 - 31.
const currentDayOfMonth = currentDate.getDate();
// thursday would be: 7 - 4.
const daysUntilSunday = 7 - currentDayOfWeek;
// currentDayOfMonth + 7 would be the same day, but
// next week, then just subtract the difference between
// now and sunday.
const nextSunday = new Date().setDate(currentDayOfMonth + 7 - currentDayOfWeek);
const nextSundayAt3pm = new Date(nextSunday).setHours(15, 0, 0);
Moment.js
Using moment.js you can get and set the day of the week
https://momentjs.com/docs/#/get-set/day/
All you need to do is create a new Moment, then set the day to Sunday. But..
If the value given is from 0 to 6, the resulting date will be within the current (Sunday-to-Saturday) week.
Due to it recognising Sunday as the start of the week, you will need to get the Sunday at the start of the current week, then add 7 days on to the date to get the next Sunday from today.
In other words, you add 7 to the days.
// 0 - 6 sets it to a date of the week within the current week.
// if you provide a number greater than 6, it will bubble in to
// later weeks.
// i.e. 7 = 0 + 6 + 1. where 0 would be the previous Sunday, 6 would
// set it to Saturday of the current week, then adding an additional 1
// will set it to the Sunday of the next week.
const nextSunday = new moment(7); // sets the date to next Sunday.
// now just set the time to 3pm.
nextSunday.hour(15);
I have a JavaScript control consisting of 3 dropdowns to collect date of birth from users (don't ask me why we're not using a date picker)
A dropdown for day, month, and year. When all 3 dropdowns have a value selected, I collect the values and construct a date:
var d = new Date(Date.UTC(this.selectedYear, this.selectedMonth - 1, this.selectedDay));
I'm not sure why you need to subtract 1 from the month, I just copied that bit from existing codebase and it seems to work. I guess months have a zero-based index for whatever reason.
The obvious problem with these dropdowns is that the user can select an invalid date. There's nothing stopping them to select 31 for day and then select February. This will result in the date being shifted forward by a number of days, i.e. values 1999, 2, 31, would give me March 3rd, 1999. So I have a check in place:
if (d.getDate() != this.selectedDay) {
d = new Date(Date.UTC(this.selectedYear, this.selectedMonth - 1, 0));
this.selectedDay = d.getDate();
If the day of month is different then my original value, it means the date has shifted, so I change the date to the last day of last month (hence the 0 for day) and then I update the value in the 'days' dropdown.
The strange thing is, I can't do this.selectedMonth - 1 in this second conversion. This would bring me all the way back to January 31st. So I have to do the following:
var d = new Date(Date.UTC(this.selectedYear, this.selectedMonth - 1, this.selectedDay));
if (d.getDate() != this.selectedDay) {
d = new Date(Date.UTC(this.selectedYear, this.selectedMonth, 0));
this.selectedDay = d.getDate();
}
This works, but it's just mind-boggling to me. Why do months behave differently if I use 0 as a value for days instead of a valid day of month? Why would anyone implement it this way? Does anyone have a logical explanation?
Actually, it's not the month field that's any different from the others: it's the day part that is the only one that is 1-indexed, as you can find in the docs on Date:
Given at least a year and month, this form of Date() returns a Date object whose component values (year, month, day, hour, minute, second, and millisecond) all come from the following parameters. Any missing fields are given the lowest possible value (1 for the day and 0 for every other component).
(emphasis mine)
The incorrect assumption you made is that using 0 for the day part would represent the last day of the month. There's no such quirks to JS Dates!
Picking the day 0, instead of the day 1, merely offsets the Date you picked by one day. Just one full day before the first day of the month...
That would be the last day of the previous month.
If the month you want to select is this.selectedMonth - 1, its last day is obtained by doing the following:
select the following month — that's + 1, so: (this.selectedMonth - 1) + 1
go back one day before the first — that's day 0, one before the day 1.
This is exactly what you're doing when you go:
// ┌───── year ────┐ ┌───── month ────┐ day
new Date(Date.UTC(this.selectedYear, this.selectedMonth, 0))
// │ │ │
// ┌─────────────────────┘ │ │
// the month after (this.selectedMonth - 1) │
// │
// ┌──────────────────────────────┤
// the day before the first day (1)
Sometimes, even an ASCII picture is worth more than a thousand words 🙂.
As others have pointed out, months are zero indexed hence you need to subtract 1 from the calendar month number. You can make life easier by setting the values of the month options to their month index (0 to 11) rather than calendar month number (1 to 12). The displayed text can be the calendar month number or name.
To validate the input date values, you can just check that the month hasn't changed when creating the date.
I can't see why you're using Date.UTC, it will change the date for users east of Greenwich as for anyone with a positive timezone offset (or negative ECMAScript offset) 2019-10-01 UTC is 2019-09-30 local.
let i;
let ySel = document.getElementById('inYear');
for (i=0; i<10; i++) {
ySel.appendChild(new Option(2010+i, 2010+i));
}
let mSel = document.getElementById('inMonth');
'January February March April May June July August September October November December'
.split(' ')
.forEach((m, i) => mSel.appendChild(new Option(m, i)));
let dSel = document.getElementById('inDay');
for (i=1; i<32; i++) {
dSel.appendChild(new Option(i, i));
}
[ySel, mSel, dSel].forEach(el => el.addEventListener('change', validateDate, false));
function validateDate(){
let y = document.getElementById('inYear').value;
let m = document.getElementById('inMonth').value;
let d = document.getElementById('inDay').value;
let date = new Date(y, m, d); // m is already zero indexed
let errSpan = document.getElementById('dErr');
if (date.getMonth() != m) {
errSpan.textContent = 'Invalid date';
} else {
errSpan.textContent = date.toString();
}
}
Year: <select id="inYear"></select>
Month: <select id="inMonth"></select>
Day: <select id="inDay"></select><span id="dErr"></span>
I would suggest to make year input first and required, after it has value enable month picker and then create new date object from where you would display day picker
I am writing some javascript and came across moment library.I would like to use the moment to get the first Monday of 18 Month ago. How would I do it?
I know 18 months ago it is
moment().subtract(18, 'months');
But how would I know the first Monday of that time.
Thanks ahead of time!
You can do this in one line.
moment().subtract(18,'months').startOf('month').add(6 - moment().day("Monday").day() ,'days').startOf('week').day(1);
Find the moment 18 months ago, get the start date of that month, add 6 days since in worst case the first of that month is a tuesday(results in a date which is in the week that includes the first monday) and then get the start of that week.
Voila, all in one line.
1st edit: corrected the calculation to be locale independent and always return a Monday and not beginning of week since that is locale dependent.
2nd edit: locales makes it a bit more complicated. Adding 6 days to a Monday with a locale where the week ends on Saturday will move into another week thus we need to adapt the algorithm to take the Monday week number into consideration, i.e. subtract moment().day("Monday").day() which gives the locale dependent week day number of a Monday(0 or 1). Changed in the code above.
cleaner and more reusable IMHO ;)
var monday = moment().day('Monday').weekday();
var searchFirstMonday = moment().subtract(18, 'months').startOf('month');
while (searchFirstMonday.weekday() !== monday){
searchFirstMonday.add(1, 'day');
}
If you go back 18 months, get the first day of that month, then the Monday of that week, you'll get close:
moment().subtract(18, 'months').startOf('month').day(1)
To make sure the Monday is in the right month, you need to break that down a bit:
var month = moment().subtract(18, 'months');
var firstMonday = month.startOf('month').day(1);
if (firstMonday.month() != month.month()) {
firstMonday = firstMonday.add(7, 'days');
}
If anyone wants to do the same without any libraries.
Not sure if this is the best way to do it :P
var now = new Date();
//Get year and month
var month = now.getMonth();
var year = now.getFullYear();
//Months to go back
var monthsIntoPast = 18;
//Day of week we're looking for
var firstWeekDay= 2;
//Loop for one week
for(var x = 0; x < 7; x++) {
//Go back 18 months to first day + x of the month
var past = new Date(year, month - monthsIntoPast, 2 + x);
//First monday
if(past.getDay() == firstWeekDay) {
//First monday 18 months ago
alert(past.toUTCString())
break;
}
}
You use the following code to get what you need:
// Subtract 18 months from the current date, then get the first day of the month
var date = moment().subtract(18, 'months').startOf('month');
// Get current month
var month = date.month();
// Get monday of the first week of the month
var firstMonday = moment(date).weekday(0);
// Check if the first day of the month is not Monday
// and first monday of first week is in the desired month
if( date.weekday() != 0 && firstMonday.month() != month ){
// Add 1 week if needed
firstMonday.add(1, 'weeks');
}
The example above consideres Monday as the first day of the week. If Monday is not the first day of the week (day with index 0), you can get the correct index using moment.weekdays()
var moment = require('moment');
date = moment().subtract(18, 'months').startOf('month');
First we get the the current date and subtract 18 months. Then we find the start of the month, which as of today is
_d: Tue Jul 01 2014 00:00:00 GMT-0800 (AKDT),
So now we need to adjust for the next Monday. We get the current day of the week with date.day() which will give us a number between 0-7 with 0 being last Sunday and 7 being next Sunday. In this case, the first is on a Tuesday.
>date.day();
2
So we take the offset of the day of the week and subtract it from 8. Why 8 you say? Because if you count every number including 0 and 7 there are 8 numbers. (Think arrays)
//since it's not monday we add the offset
date = date.add(8-date.day(), 'days');
In your code you'd want to check if the First day returned actually IS a Monday so as to not get the second Monday of the month. So the whole thing might look like
date = moment().subtract(18, 'months').startOf('month');
if(date.day() > 1){ //check if it's Monday
//since it's not monday we add the offset
date = date.add(8-date.day(), 'days');
}
returns
_d: Mon Jul 07 2014 00:00:00 GMT-0800 (AKDT),
I'm trying to get last day of the previous month using:
var dateFrom = moment(dateFrom).subtract(1, 'months').format('YYYY-MM-DD');
Where:
dateFrom = 2014-11-30
But after using
subtract(1, 'months')
it returns date
DATE_FROM: "2014-10-30"
But last day of the 10'th month is 31.
How can I solve i please?
Many thanks for any help.
Simply add a endOf('month') to your calls:
var dateFrom = moment(dateFrom).subtract(1,'months').endOf('month').format('YYYY-MM-DD');
http://jsfiddle.net/r42jg/327/
An even easier solution would be to use moment.date(0). the .date() function takes the 1 to n day of the current month, however, passing a zero or negative number will yield a dates in the previous month.
For example if current date is February 3rd:
var _date = moment(); // 2018-02-03 (current day)
var _date2 = moment().date(0) // 2018-01-31 (start of current month minus 1 day)
var _date3 = moment().date(4) // 2018-02-04 (4th day of current month)
var _date4 = moment().date(-4) // 2018-01-27 (start of current month minus 5 days)
console.log(_date.format("YYYY-MM-DD"));
console.log(_date2.format("YYYY-MM-DD"));
console.log(_date3.format("YYYY-MM-DD"));
console.log(_date4.format("YYYY-MM-DD"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.js"></script>
Last month's First date and last month's last date from the current date basis. The Format of the date changes depending upon. (DD-MM-YYYY)
console.log("last month first date");
const lastmonthlastdate=moment().subtract(1, 'months').startOf('month').format('DD-MM-YYYY')
console.log(lastmonthlastdate);
console.log("lastmonth last date");
const lastmonthfirstdate=moment().subtract(1, 'months').endOf('month').format('DD-MM-YYYY')
console.log(lastmonthfirstdate);
moment().subtract(1, 'months').endOf('month').format('YYYY-MM-DD')
You can get the first day of the month then subtract 1 day to get the last day of the previous month.
const monthyear = moment().format('YYYY-MM')
const firstDay = moment(monthyear + "-01").format("YYYY-MM-DD");
// Subtract 1 day to get the end of the previous month
const dateTo = moment(firstDay).subtract('1', 'days').format("YYYY-MM-DD");
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.