So, I need to calculate age by subtracting "todays" date from the converted date of an input field, entered by the user. Although it needs cleaned up, the below code works, I had to get creative as RN uses a different JS execution environment... see here.
My question, without adding the "+1" to this snippet "b.getMonth() + 1", the math on the date subtraction comes back 1 month off every time. When I add the "+1" it works like a charm, why? If it's a logical fix, I don't mind keeping the "+1," but I would surely like to know why the "+1" is necessary.
Also, totally open to improved solutions to this problem, keep in mind I had a much simpler function that worked great while debugger was open, once closed, it did not work, see the link above.
getVerifyBirthday(birthday) {
const b = new Date();
var verify = birthday.length;
const utc2 = Date.UTC(b.getFullYear(), b.getMonth() + 1, b.getDate());
if (verify === 10) {
const splitBirth = birthday.split('-');
var mydate = new Date(splitBirth[2], splitBirth[0], splitBirth[1]);
const a = mydate;
const utc1 = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate());
const diffTime = Math.abs(utc2 - utc1);
const diffYears = (diffTime / (3.15576e+10));
this.setState({ diffYears: diffYears});
return diffYears >= 13;
} else {}
}
Update
I ended up refactoring my original function, leaving the (+1) on months due to months starting at 0, as mentioned below. I still had to split both dates, when I didn't split both, my age came back NaN/Undefined; not sure if this goes back to the RN execution environment vs browser, but I digress.
I'd make a few of my own suggestions over here:
there's no need to hussle with UTC dates (to make sure whether the user in his timezone has already reached the age of 13, assuming along the way that he or she was born in that same timezone ;)
there's no need to split mm-dd-yyyy date string to convert into Date, it may be parsed by new Date()
counting years as 365.25 days has certain error margin depending on the exact leap years quantity that passed since the user's birth year, instead whole years may be compared together with dates
To me, it makes more sense to decompose date strings into days, months and years and make decision based on full years difference minus 1 year (if the person didn't yet celebrate his/her birthday this year):
const today = new Date().toISOString().slice(0,10), // yyyy-mm-dd
birthday = '1982-06-21',
[bYear, bMonth, bDay] = birthday.split('-'),
[tYear, tMonth, tDay] = today.split('-'),
diffYears = tYear - bYear - (bMonth > tMonth || bDay > tDay ? 1 : 0)
console.log(diffYears)
.as-console-wrapper{min-height:100%;}
Months are zero-based in JavaScript Date objects. However, if you get a formatted string, they start from 1:
const date = new Date(2020, 1, 17); // 17th of February 2020
console.log("getMonth:", date.getMonth()); //month is 1
console.log("formatted:", date.toISOString()); //month is 2
So, actually what happens is that you're shifting both dates a month forward. This sort of works:
const originDate = new Date(2020, 1, 17); // 17th of February 2020
const originString = "2020-02-17".split("-");
const dateFromDate = new Date(originDate.getFullYear(), originDate.getMonth() + 1, originDate.getDate())
const dateFromString = new Date(originString[0], originString[1], originString[2])
console.log("dateFromDate:", dateFromDate); //month is 3
console.log("dateFromString:", dateFromString); //month is 3
When you do the subtraction it evens out but you can still run into an overflow of the date for months with different number of days:
const originDate = new Date(2020, 0, 31); // 31st of January 2020
const dateFromDate = new Date(originDate.getFullYear(), originDate.getMonth() + 1, originDate.getDate())
console.log("dateFromDate:", dateFromDate); // 1st of March 2020
This still works logically for most cases, however you are bound to run into a problem at some point if you shift months forward. So, instead you should be doing the opposite and subtracting 1 when converting a 1-based number into a Date object:
const originString = "2020-02-17".split("-");
const dateFromString = new Date(originString[0], originString[1] - 1, originString[2])
console.log("dateFromString:", dateFromString); //month is 2
Related
Good day, I am generating 3 dates from a string, I hope the output was:
billing date: 2020/01/11
cutoff start: 2019/11/11
cuttof end: 2019/12/10
but I get the following:
billing date: 2020/11/10
cutoff start: 2019/11/10
cuttof end: 2019/12/10
I would like to know how javascript works with variables or what is the problem since everything is altered
var month = "Jan-20"
var coverage_month_obj = moment(month, 'MMM-YY').toDate();
var billing_date = new Date(coverage_month_obj.setDate(coverage_month_obj.getDate() + 10))
var cutoff_end = new Date(billing_date.setMonth(billing_date.getMonth() - 1))
cutoff_end = new Date(billing_date.setDate(billing_date.getDate() - 1))
var cutoff_start = new Date(billing_date.setMonth(billing_date.getMonth() - 1))
I would like to know how javascript works with variables or what is the problem since everything is altered
Put simply, calling setXXX on a javascript date variable updates that variable in place. ie, it is what we would call "mutable". You might have assumed dates were immutable and did not change in place.
To answer on a better way to achieve your goal, I'd suggest using the other functionality of momentjs to calculate your 3 dates from the given input string.
var month = "Jan-20"
var coverage_month = moment(month, 'MMM-YY');
//Jan-20 I need to convert it into date format and that the day is 11 (2020/01/11) cutoff start, are two months less from that date (2020/11/11) and cutoff end is one month less from Jan-20, but ends on day 10 (2020/12/10)
var billing_date = coverage_month.clone().add(10, 'days');
var cutoff_start = billing_date.clone().subtract(2, 'months');
var cutoff_end = billing_date.clone().subtract(1,'months').subtract(1,'day')
console.log("billing_date",billing_date);
console.log('cutoff_start',cutoff_start);
console.log('cutoff_end',cutoff_end);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
I'd like to check the date if it's next month from the current.
Some test cases here
2020.1.1 2019.12.30 // true
2019.11.30 2019.10.10 // true
2019.12.11 2019.12.1 // false
So as you can see, I'd like to check if the date is next month from now.
Hope to get the brilliant idea!
Best
Kinji
You could try this approach, we have to handle the case when the dates are in the same year and also for December and January of the next year.
A simple algorithm can be created, whereby we multiply the year by 12, add the month and get the difference of this score between the two dates. As long as the value of this is 1 or -1 we have months that are adjacent. I'm presuming you only need to check if the first parameter is the next month to the second parameter, so we check for a difference of 1.
function isNextMonth(timeStamp1, timeStamp2, format = "YYYY.MM.DD") {
let dt1 = moment(timeStamp1, format);
let dt2 = moment(timeStamp2, format);
return ((dt1.year()*12 + dt1.month() - dt2.year()*12 - dt2.month()) === 1);
}
let inputs = [['2020.1.1','2019.12.30'],['2019.11.30', '2019.10.10'], ['2019.12.11','2019.12.1'], ['2020.12.1','2021.1.1'], ['2020.6.1','2020.5.1'], ['2021.1.1','2019.12.1'], ['2019.3.1', '2019.4.1']];
for(let [inputa, inputb] of inputs) {
console.log(`isNextMonth(${inputa}, ${inputb}): ${isNextMonth(inputa, inputb)}`);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
A very simple solution would be to use Moment’s isSame. This only checks the month. If you also want to make sure that the year matches you would have to make sure that nextMonth.getYear() matches dateToCheck.getYear()
var dateToCheck = new Date(2019, 11, 30)
var nextMonth = new Date()
nextMonth.setMonth(dateToCheck.getMonth() + 1)
moment(dateToCheck).isSame(nextMonth, 'month');
I have a validator that checks if an user is at least 18 years old.
This is the check:
var res = /^([1-2]\d{3})\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01])\-([0-9]{4})$/.exec(str);
var todays_date = new Date();
var birth_date = null;
if (res != null) {
birth_date = new Date(res[1], res[2], res[3]);
if (todays_date - birth_date > 565633905872) {
565633905872 is 18 years in milliseconds but how do I convert it to years before so I can just do:
if (todays_date - birth_date => 18) {
The number you have quoted is not the number of milliseconds in 18 years. It's too small even if you pretend there are no leap years.
The simplest way to test if somebody is at least 18 years old is to initialise a date object to their birthday, then use .getFullYear() and .setFullYear() to directly set the year 18 years forward. Then compare that with the current date.
Note also that in JS dates the month is zero-based, so you probably want to use res[2] - 1 when creating the date object.
birth_date = new Date(res[1], res[2] - 1, res[3]);
birth_date.setFullYear(birth_date.getFullYear() + 18);
if (birth_date <= new Date()) {
Or given you are constructing the birth_date from individual year, month and day you could just do:
birthPlus18 = new Date(+res[1] + 18, res[2] - 1, res[3]);
if (birthPlus18 <= new Date()) {
(The leading + in +res[1] + 18 is not a typo, it converts the string extracted by your regex into a number so that you can add 18 to it. You don't need to do the same thing for res[2] - 1 because - automatically converts both operands.)
Note also that your regex will happily allow dates that specify a day that is too high for the month, e.g., Feb 30 or Jun 31.
There are better ways of checking this (see the answer of "nnnnnn"). But your question wasn't about a better way but, how you could convert to years.
You could write a function that does that, example:
function convertmili( mSeconds )
{
return mSeconds / 31536000000;
}
The output of this function is still far from ideal, because your example would output: 17.9361334941654
So we could clean it up a bit:
function convertmili( mSeconds )
{
var checkYear = Math.floor(mSeconds / 31536000000);
return checkYear;
}
With this function, your example would output 17 and then you can check it the way you wanted.
Divide your millisecond value by 31536000000 you get number of years
http://www.convertunits.com/from/milliseconds/to/year
So what I need to try an accomplish is to output a specific message depending on how close a date is. The task is to change an element of a webpage from a message saying "Renewal Unnecessary" when the date is more than 3 months away, "Renewal upcoming" when the date is less than 3 months away, and finally "Renewal Required!" when the date is 1 month away.
So far I have:
if()
{<hre>Renewal Required!</hre>}
else if()
{<ha>Renewal upcoming</ha>}
else
{<hg>Renewal Unnecessary</hg>}
I am uncertain of how to write the condition for what i need the script to do, for example the renewal month or date might be the 26th February, and is there some way of making it work off the computers date.
Date.now returns currrent date in miliseconds. Just check for
renewal_date - Date.now()
And compare it with the corrent number of miliseconds.
Here's one way you could do it. You could expand this to be considerate of what day of the month it is, also. Live demo (click).
var deadline = new Date(2014, 1, 2); //2014, February 2nd (January is Month 0)
var today = new Date();
var monthDiff = deadline.getMonth() - today.getMonth();
if (monthDiff < 3) {
console.log('Deadline is in 3 months or less!');
}
if (monthDiff <= 1) {
console.log('Deadline is in 1 month or less!');
}
Answering your comment: There a are lots of ways this can be done - learn the basics. Here are two examples that might help.
var p = document.createElement('p);
p.textContent = 'My message here';
document.body.appendChild(p);
Or if the element already exists on the page:
var elem = document.getElementById('myElem');
elem.textContent = 'My message here';
I was playing around with Javascript creating a simple countdown clock when I came across this strange behavior:
var a = new Date(),
now = a.getTime(),
then = Date.UTC(2009,10,31),
diff = then - now,
daysleft = parseInt(diff/(24*60*60*1000));
console.log(daysleft );
The days left is off by 30 days.
What is wrong with this code?
Edit: I changed the variable names to make it more clear.
The month is zero-based for JavaScript.
Days and years are one-based.
Go figure.
UPDATE
The reason this is so, from the creator of JavaScript, is
JS had to "look like Java" only less so, be Java's dumb kid brother or boy-hostage sidekick. Plus, I had to be done in ten days or something worse than JS would have happened.
http://www.jwz.org/blog/2010/10/every-day-i-learn-something-new-and-stupid/#comment-1021
As Eric said, this is due to months being listed as 0-11 range.
This is a common behavior - same is true of Perl results from localtime(), and probably many other languages.
This is likely originally inherited from Unix's localtime() call.
(do "man localtime")
The reason is that days/years are their own integers, while months (as a #) are indexes of an array, which in most languages - especially C where the underlying call is implemented on Unix - starts with 0.
It's an old question but this is still a problem today (or a feature as some might say - and they are wrong).
JS is zero-based month, why? Because.
That means the months range from 0-11 (only the months, the others are normal)
How can you fix this? Add a month, obviously, BUUUUT:
Don't do this :
let date: Date = new Date();
date.setMonth(date.getMonth() + 1);
Why you might ask? Because it won't work as expected, Date in JS is terrible.
You have to make a ... let's call it not so beautiful function to translate the JS date to a normal date
formatJsDateToNormalDate(Date date): string | null {
if(date !== null) {
const realMonth: number = date.getMonth() + 1;
let month: string = (realMonth < 10) ? '0' + realMonth : String(realMonth);
let day: string = (date.getDate() < 10) ? '0' + date.getDate() : String(date.getDate());
return [date.getFullYear(), month, day].join('-');
} else {
return null;
}
Again, if you ask me this is the equivalent of hammering a screw, it's not the right way, but there is no right way here, it's a bug that has been going on for 27 years and more to come.
date1 = new Date();
//year, month, day [, hrs] [, min] [, sec]
date1 = new Date.UTC(date1.getFullYear(),date1.getMonth()+1,date1.getDate(),date1.getHours(),date1.getMinutes(),date1.getSeconds());
date2 = new Date();
date2 = date2.getTime();
alert(date1)
alert(date2)