My current code is
function ageInNDays(days) {
return moment.duration(
moment('1990-10-10').diff(
moment().add(days, 'days'))
);
}
I .add(days, 'days') to today, then diff it against some date in the past. However, moment.duration doesn't exactly always return the number of calendar years that pass. It defines a year as 365 days and returns how many of those years have passed.
EDIT: I'm still looking for my age as a number of Years. Maybe if possible, something like 20 Years, 5 Months, and 10 Days format similar to how moment.duration() looks.
If my birthday is March 5th 1992, then my age should only increment when the calendar passes March 5th. My remainder age in days should only reset when the 5th of every month passes.
EDIT2: My only idea now is something like
age = moment().add(days, 'days').year() - moment('1995-01-05').year()
if ((today's date + added days) < birthday's date)
--age
From the documentation,
Trying to convert years to days makes no sense without context. It is much better to use moment#diff for calculating days or years between two moments than to use Durations.
So it looks like using diff is the answer:
function ageInNDays(days) {
return moment().add(days, 'days').diff('1990-10-10', 'years', true);
}
// ageInNDays(1000);
// 27.977483271480484
Note that gives you the fractional number of years (by virtue of the third argument). You could truncate that if you don't want it rounded (which the default implementation does):
function ageInNDays(days) {
return Math.floor(moment().add(days, 'days').diff('1990-10-10', 'years', true)) + ' years';
}
// ageInNDays(1000);
// 27 years
If you're really looking for age in days, you can use:
moment.duration(moment() - moment('1990-10-10')).asDays();
UPDATE
You can also use this to add days to your current age:
function ageInNDays(days) {
var age = moment.duration(moment() - moment('1990-10-10'));
return age.add(days, 'd').asDays();
}
Add param boolean true for decimals diferency
var currentDate = new Date();
var diff = moment(currentDate).diff('1990-10-10', 'years',true);
console.log("Year", diff);
Example
That will answer 21.23 depending on the date
Related
I am using moment.js. I want to restrict the user son that he can only select a date which is from current date to 50 years before.
In short, i just want that user's date of birth cannot be more than 50 years. So, from the current date, only ranges before the 50 years should only be there.
How can i do so? please guide me.
So you have to calculate 50 years back date first
https://momentjs.com/docs/#/manipulating/subtract/
fiftyYearsBackDate = moment().subtract(50, "years")
Get user Selected date
userDate = new Date()
Create moment object from that and do query
https://momentjs.com/docs/#/query/is-after/
moment(userDate).isAfter(fiftyYearsBackDate)
this will return boolean that you can use to show the error message.
You want to calculate the difference in years between now and the birthdate, and check if it's bigger than 50.
const birthDate = '1970-01-01'
const yearsDiff = moment().diff(birthDate, 'years');
If you want to get the difference of years in decimal:
const yearsDiff = moment().diff(birthDate, 'years', true);
The yearsDiff will contain the difference, so you can do an if check on it to see if it's bigger than 50.
Official docs for this: https://momentjs.com/docs/#/displaying/difference/
By using moment js you can easily get past and future dates like this -
const past = moment().subtract(50, 'years'); // To past
const future = moment().add(50, 'years'); // Back to future
Finally
const today = moment();
moment(today).isAfter(past, 'year'); // return: true || false
The reference site URL is - https://everyday.codes/javascript/how-to-format-date-in-javascript-with-moment-js/
Without moment.js you can test if the birthdate is less than today minus 50 years:
birthdate < new Date().setFullYear(new Date().getFullYear() - 50);
Example use:
let testDates = [
new Date(1970,0,1), // 1 Jan 1970
new Date(2000,0,1) // 1 Jan 2000
].forEach(date => console.log(
`More than 50 years ago?\n` +
`${date.toDateString()}: ${date < new Date().setFullYear(new Date().getFullYear() - 50)}`
));
The only behaviour to check is around 29 Feb. Some places move the birthday to 28 February in non–leap years and others to 1 March.
The goal is to use Javascript to UNIQUELY calculate the total years of a person's work experience, from an array of Date Ranges of the person's work history. There are Date Ranges which overlap (meaning, the person had multiple jobs within the overlapping period). Here is an example below and the date format is yyyy-mm-dd;
2001-02-01 to 2009-03-01
2004-06-01 to 2020-08-01
2005-04-01 to 2021-03-01
2008-07-01 to 2016-06-01
From the date ranges above, there are overlapping work dates.
The correct computation of the person's years of work experience should be 20 years.
The problem I have is to creating an algorithm that can put into account, the overlapping periods within the person's four work histories and not count them as separate years of work experience E.g just summing up the years between each of the four job dates gives 48 years WHICH IS INCORRECT (The experience was over a 20-year period).
var time_diff=0, yrs_diff=0;
var jobExperience = [
{date_began:'2001-02-01', date_ended:'2009-03-01'},
{date_began:'2004-06-01', date_ended:'2020-08-01'},
{date_began:'2005-04-01', date_ended:'2021-03-01'},
{date_began:'2008-07-01', date_ended:'2016-06-01'}
];
for(let i=0; i<jobExperience.length; i++){
let date_1, date_2;
let began = jobExperience[i].date_began.split('-');
let ended = jobExperience[i].date_ended.split('-');
date_1 = new Date(began[1]+'/'+began[2]+'/'+began[0]);
date_2 = new Date(ended[1]+'/'+ended[2]+'/'+ended[0]);
time_diff += date_2.getTime() - date_1.getTime();
}
yrs_diff = parseInt(time_diff/(1000 * 3600 * 24 * 365));
console.log(yrs_diff);
The snippet above only just blindly adds up the years between each record of work history (This is not correct). Where I need some help is a clue or better still pseudocode or complete code on how to sum up the years between each record of work history but account for overlaps between work history dates and by so doing, overlapping periods are only counted once.
Here's the approach I've outlined in my comment:
For each period, turn the start and end date into a unique "month value", then add all month values of a period to a set.
The size of the set is the wanted number of months:
const jobExperience = [
{ date_began: '2001-02-01', date_ended: '2009-03-01' },
{ date_began: '2004-06-01', date_ended: '2020-08-01' },
{ date_began: '2005-04-01', date_ended: '2021-03-01' },
{ date_began: '2008-07-01', date_ended: '2016-06-01' }
];
const months = new Set();
// convert date into unique integer month value based on year 1900
function m1900(yyyymmdd) {
const [_, y, m, d] = yyyymmdd.match(/^(\d{4})-(\d{2})-(\d{2})$/).map(Number);
return (y - 1900) * 12 + m;
}
jobExperience.forEach(job => {
const m1 = m1900(job.date_began);
const m2 = m1900(job.date_ended);
for (let m = m1; m < m2; m++) months.add(m);
});
console.log("years:", months.size / 12);
Here is a "Brute Force" approach.
Extract all the unique years
Sort them
Find the difference between the latest to the oldest year
(Assuming that all the years in the dataset belong to a single field; Different fields should not be part of the same dataset)
Eg: [2001, 2004, 2005, 2008, 2009, 2016, 2020, 2021] => Working for 20 years.
A caveat with this method is that it fails to account for the months.
A solution to the same would be [NOT SURE] to convert the months to a year (month/12) and adding the same to the preceding year (Like Feb 2001 => 2001.166).
Another caveat is that it fails to account for any break taken in between. (As Pointed out in the Comments).
I seem to have a bit of a problem getting the previous Monday given a particular date. I'm trying to use Moment js for the task. Obviously, I can do it by hand, but found it curious that I couldn't get it to work using the example in the moment.js documentation on their website: http://momentjs.com/docs/#/get-set/day/.
I was trying something like:
moment([2013, 08, 15, 15, 20]).day(-1).format('ddd, MMM DD')
which results in the 'two days ago' date, that being September 13 instead of the expected September 9th.
Does anybody have a clue here? Thanks.
Here is how it works:
moment().day(1) // this monday
moment().day(-6) // last monday, think of it as this monday - 7 days = 1 - 7 = -6
Same applies in other direction:
moment().day(8) // next monday, or this monday + 7 days = 1 + 7 = 8
Your code moment().day(-1) can be explained as this Sunday - 1 day = 0 - 1 = -1
or this Saturday - 7 days = 6 - 7 = -1
The accepted answer only works if you already know whether the day in question is in this week or next week. What if you don't know? You simply need the next available Thursday following some arbitrary date?
First, you want to know if the day in question is smaller or bigger than the day you want. If it's bigger, you want to use the next week. If it's smaller, you can use the same week's Monday or Thursday.
const dayINeed = 4; // for Thursday
if (moment().isoWeekday() <= dayINeed) {
return moment().isoWeekday(dayINeed);
} else...
If we're past the day we want already (if for instance, our Moment is a Friday, and we want the next available Thursday), then you want a solution that will give you "the Thursday of the week following our moment", regardless of what day our moment is, without any imperative adding/subtracting. In a nutshell, you want to first go into the next week, using moment().add(1, 'weeks'). Once you're in the following week, you can select any day of that week you want, using moment().day(1).
Together, this will give you the next available day that meets your requirements, regardless of where your initial moment sits in its week:
const dayINeed = 4; // for Thursday
// if we haven't yet passed the day of the week that I need:
if (moment().isoWeekday() <= 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 day
return moment().add(1, 'weeks').isoWeekday(dayINeed);
}
See also: https://stackoverflow.com/a/27305748/800457
function nextWeekday (day, weekday) {
const current = day.day()
const days = (7 + weekday - current) % 7
return day.clone().add(days, 'd')
}
// example: get next Friday starting from 7 Oct 2019
nextWeekday(moment('2019-10-07'), 5)) // 2019-10-11
I think the point is that using day() or isoWeekday() you get a date in the current week, no matter which day of the week is today. As a consequence, the date you get can be past, or still to come.
Example:
if today is Wednesday, moment().isoWeekday(5).format() would return the date of the upcoming Friday.
While
moment().isoWeekday(1).format() would return the previous Monday.
So when you say you want the date of, let's say, "last Tuesday", this date could belong to the current week or to the previous week, depending on which day is today.
A possible function to get the date of the last dayOfTheWeek is
function getDateOfPreviousDay(dayOfTheWeek) {
currentDayOfTheWeek = moment().isoWeekday();
if ( currentDayOfTheWeek >= dayOfTheWeek ) {
return moment().isoWeekday(dayOfTheWeek).format(); // a date in the current week
}
else {
return moment().add(-1,'weeks').isoWeekday(dayOfTheWeek).format(); // a date in the previous week
}
}
const upcomingDay = (dayIndex, format = "DD MMMM YYYY") => {
if (
Number(moment().format("D")) >= Number(moment().day(dayIndex).format("D"))
) {
return moment()
.day(7 + dayIndex)
.format(format);
}
return moment().day(dayIndex).format(format);
};
This is for a system that essentially allows you to set the first date for a given event, then to set the recurrence period.
Eg. I set a date for a week from now, 19/07/2012, so I know that I have to put the cat out with the milk. I also set it to be a weekly notification, so in future weeks I want to be notified of the same.
That original date sits in my database, which is fine for week 1, but in week 2 I need to return the date as the original plus 1 week.
On the face of it, that may seem straightforward, but I need to make sure I can account for leap years and different recurrence frequencies (fortnightly, monthly, yearly, whatever).
I'd like to keep this as a javascript implementation - because it's quicker and I feel probably would require less code than updating dates in the database. Maybe it's not achievable, any pointers would be excellent.
I think these may be a starting point:
Given a start date , how to calculate number of years till current date in javascript
Given a date, how can I efficiently calculate the next date in a given sequence (weekly, monthly, annually)?
Update, I've written the below to return the amount of time to add in each different case, from there I can just use the answer below:
var strDate = $(this).find('.next').text();
var frequency = $(this).find('.occurs').text();
var frmDate = getDateObject(strDate);
var toDate = new Date();
var days = parseInt(Math.floor((frmDate - toDate) / 86400000));
if(days < 0) {
// find out how many WHOLE 'frequencies' have passed
var weeks = Math.ceil(0 - (days / 7));
var months = Math.ceil(0 - (monthDiff(toDate,frmDate)));
var years = Math.ceil(months / 12);
//alert(days + '/' + weeks + '/' + fortnights + '/' + months + '/' + quarters + '/' + years);
if(frequency == 'Weekly') { frmDate.add(weeks).weeks(); }
if(frequency == 'Fortnightly') { frmDate.add(weeks*2).weeks(); }
if(frequency == 'Monthly') { frmDate.add(months).months(); }
if(frequency == 'Quarterly') { frmDate.add(months*3).months(); }
if(frequency == 'Annually') { frmDate.add(years).years(); }
var newdate = frmDate.toString("dd/MM/yyyy");
//alert(newdate);
$(this).find('.next').text(newdate);
}
Also, the SQL implementation for this would be using DATEADD:
http://sql-plsql.blogspot.com/2010/07/dateadd.html
You don't have to worry about special dates like leap year and so forth, because most Date functions take care of that.
Alternatively, you can use the getDate(), getMonth() as the other user suggested.
var today = new Date();
today.setDate(today.getDate() + numberOfDaysToAdd);
What I would do (probably not the best solution, I'm just coming up with it right now) is to start from the initial date and use a loop: while the date you are observing is less than the current date, increment the observed date by a week (fortnight, month, year etc.). If you land on the current date, the event happens. Otherwise it's for another day.
You can use things like date.setDate(date.getDate()+1); to increment the date by a day, the same +7 for a week, using set/getMonth and set/getFullYear for months and years respectively. If you give a value out of bounds, JS will wrap it (so March 32nd becomes April 1st)
Please check out the following code for some raw idea
var someDate = new Date();
for(var i = 0 ; i < 7 ; i++)
{
someDate.setDate(someDate.getDate() + 1);
console.log(someDate)
}
You can test the same in the below fiddle
Consecutive 7 days from current day
This is very weird I don't know what I'm doing wrong. I have a function to grab the date (i.e in this format: 06/24/2011), here's the function:
function checkDate(input){
var d = new Date();
var dspl = input.split("/");
if(dspl.length != 3)
return NaN;
d.setDate(dspl[1]);
d.setMonth(Number(dspl[0])-1);
if(dspl[2].length == 2)
d.setYear("20"+(dspl[2]+""));
else if(dspl[2].length == 4)
d.setYear(dspl[2]);
else
return NaN;
var dt = jsToMsDate(new Date(d));
return dt;
}
If I enter any date of the month, it would parse the date correctly, but if I enter 31st, i.e "01/31/2011", then it would turn into "01/01/2011". I'm not sure what to do and not really sure where the problem might be.
JavaScript's Date objects allow you to give invalid combinations of months and days; they automagically correct those for you (so for instance, if you set the day of the month to 31 when the month is June, it automatically makes it July 1st). That means if you set the fields individually, you can run into situations where that automagic correction gets in your way.
In your case, if you're going to set all three of those fields, you're better off using the form of the Date constructor that accepts them as arguments:
var dt = new Date(year, month, day);
(If you want hours, minutes, seconds, and milliseconds, you can add them as parameters as well.)
So looking at your code, an off-the-cuff update:
function checkDate(input){
var year, month, day, d, dt;
var dspl = input.split("/");
if(dspl.length != 3)
return NaN;
year = parseInt(dspl[2], 10);
month = parseInt(dspl[0], 10) - 1;
day = parseInt(dspl[1], 10);
if (isNaN(year) || isNaN(month) || isNaN(day)) {
return NaN;
}
if (year < 100) {
year += 2000;
}
d = new Date(year, month, day);
var dt = jsToMsDate(d);
return dt;
}
Some other notes on that update:
It's best to use parseInt to parse numbers from end users, and to always specify the radix (10 for decimal). (No, parseInt is not slower than Number or the unary + trick. People assume it is, but it isn't.)
No need to muck about with strings to add 2000 to years given with only two digits. But you can if you like. Note I weakened the validation there, allowing one-digit years for (say) 2001 and three-digit years for (say) 300 AD. So if you need it to be that strong, you'll need to readjust that.
No need to feed the date instance into new Date() again.
You need to set the month before setting the day (or as Marc B points out in his comment, use the Date(yearval, monthval, dayval) constructor).
When you create a Date object, it defaults to the current date. At the time of writing that's in June, so when you try to set the day to 31 it wraps.
...And because of similar behaviour in leap years, you should set the year before setting the month or day.
(It's a good job you developed this code in June rather than in July - the bug would have lurked undiscovered until September, and it would probably have been your users that found it rather than you. :-)
Right hierarchy is set year, then Month and at last add the Day.
This will return the exact date that you added.
function checkDate() {
//Wrong order- will return 1 May 2016
var start = new Date();
start.setDate(31);
start.setMonth(4);
start.setFullYear(2016);
alert(start)
//Right order - will return 31 May 2016
var end = new Date();
end.setFullYear(2016);
end.setMonth(4);
end.setDate(31);
alert(end)
}
<input type="button" value="Test" onclick="checkDate()" />
This is the right heirarchy to set date.
Why are you adding 1 the day position (position 1)? I think that is your problem.
d.setDate(dspl[1] + 1);