Convert milliseconds to years - javascript

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

Related

Age verification based on birthdate and current date

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

Calculate difference between dates in javascript

I am aware that this question was asked multiple times before but the suggested solutions were always something like
var diff = date1 - date2;
My problem is that I want to get the difference in years, months, day, ... ,seconds.
So for example 5y 3m 39d 12h 39i 32s
But simply dividing the difference is too inaccurate for my purpose.
So I can't assume that every month has 30.4375*24*60*60*1000 milliseconds.
I need the exact difference!
So if date1 is the 1st of february and date2 is the 1st of march, it should display 1m not 28d (or 29d in leap years)!
Thank you.
First you need to find out which date is bigger, subtract the dates, and if they turn out to be negative borrow from the larger digit (similar to elementary multi-digit subtraction).
function DateDiff(a,b){
if(b>a){ // We want a-b to be positive
var c=b;
b=a;
a=c;
}
var s=a.getSeconds()-b.getSeconds();
var mi=a.getMinutes()-b.getMinutes();
var h=a.getHours()-b.getHours();
var d=a.getDate()-b.getDate(); // Subtract days
var m=a.getMonth()-b.getMonth(); // Subtract months
var y=a.getYear()-b.getYear(); // Subtract years
if(s<0){
mi--;
s+=60;
}
if(mi<0){
h--;
mi+=60;
}
if(h<0){
d--;
h+=24;
}
if(d<0){ // Need to borrow from months
m--;
d+=new Date(1900+b.getYear(),1+b.getMonth(),0).getDate();
}if(m<0){ // Need to borrow from years
y--;
m+=12;
}
return [y,m,d,h,mi,s];
}
console.log('Mar 1 - Feb 2 (Leap Year):', DateDiff(new Date(2016,1,2),new Date(2016,2,1)));
console.log('Mar 1 - Feb 2 (Reg Year): ',DateDiff(new Date(2015,1,2),new Date(2015,2,1)));
console.log('Feb 1, 2017 - Feb 2, 2016: ',DateDiff(new Date(2017,1,1),new Date(2016,1,2)));
console.log('5:00 - 4:59: ', DateDiff(new Date(2015,7,1,17), new Date(2015,7,1,16,59)));
You can use moment.js to achieve this: ( MomentJS Doc )
var start = moment(date1);
var end = moment(date2);
var diff = end.diff(start)
If you want specific things like difference in days, you can do:
var diff = end.diff(start, 'days')
For what you are describing, you will want to hold the year/month/day in three different variables and directly compare the years using
var yeardiff = date1.GetFullYear() - date2.GetFullYear();
var monthdiff = date1.GetMonth() - date2.GetMonth();
var daydiff = date1.GetDate() - date2.GetDate();
However, you are going to have to do a lot of checking in this. For example, 8/2/2012 - 7/20/2012 is going to give you a 1 month and -18 days, then you have to convert that into days based on the number of days in July. Because of these issues, the other conversion in the OP is actually easier.
Not using any library you could do
function mydiff(aa,bb){var a,b;
if(aa<bb) a=aa,b=bb;
else a=bb,b=aa;
var am=a.getMonth(),ay=a.getFullYear();
var dd=b.getDate()-a.getDate();
var dm=b.getMonth()-am-(dd<0?1:0);
return b.getFullYear()-ay-(dm<0?1:0)+'y, '
+ ((12+dm)%12)+'m, '
+((dd<0?new Date(ay, am+1, 0).getDate():0)+dd)+'d';
}
dd contains the difference 'b minus a in days of month' which can be negative. In that case the month-difference dm has to be reduced by 1 and the (negative) day-difference must be increased by the number of days of the preceding month of date b. I got the formula for "number of days in a particular month" from here. Similar action has to take place with the month- and year-differences dm and dm.
A few samples:
mydiff(new Date(2014,1,2),new Date(2014,2,1)) // "0y, 0m, 27d"
mydiff(new Date(2012,1,1),new Date(2012,2,1)) // "0y, 1m, 0d" (leap year)
mydiff(new Date(2012,1,2),new Date(2012,2,1)) // "0y, 0m, 28d" (leap year)
mydiff(new Date(2014,11,31),new Date(2015,0,1)) // "0y, 0m, 1d" (different years)
mydiff(new Date(2012,10,30),new Date(2013,1,28)) // "0y, 2m, 28d" (different years)
The last example shows that this kind of "calculation" has its limits: compared to "normal" months 28 days are not a full month. On the other hand, compared to the current month February 28 days is a full month. So it could also be argued that a correct response should be "0y, 3m, 0d".

JS time calculation - How many times a date has occurred between two dates

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.

Get the week day from a given date

I am writing my own calendar plugin but I am struggling to get the day of the week for a given date.
Lets say I have the year - 1905, the month - 4 and the day - 23. Is there any way at all that I could use this data - smash it together in a better format say YYYY/DD/MM and use this to calculate the day of the week - I was hoping to find some Gregorian calendar methods like in PHP but I am yet to find any.
Sorry if this has been asked before but I could only find questions using new Date for todays day of the week.
Construct a date object and ask it what day it is:
// Note months are zero indexed so May is 4, not 5
var d = new Date(1905, 4, 23).getDay(); // 2
Which you can turn into a function:
function getDay(y, m, d) {
var days = ['Sunday','Monday','Tuesday',
'Wednesday','Thursday','Friday','Saturday'];
var d = new Date(y, --m, d);
return d && days[d.getDay()];
}
// What day was 23 May, 1905?
console.log(getDay(1905,5,23)); // Tuesday
Edit
Note that these types of functions will convert two digit years into 20th century dates, e.g.
var d = new Date(5, 4, 23) // 23 May, 1905
and they don't check that the values are valid dates:
var d = new Date(5, 16, 23) // 23 May, 1906
If you don't want that, you have to construct the date differently and check the values:
// Create a generic date object
var d = new Date();
// Set the values for 23 May, 0005
// This way doesn't convert 5 to 1905
d.setFullYear(5, 4, 23);
// Check at least 2 values in the date are the same as the input
// The easiest to check are year and date
if (d.getFullYear() == 5 && d.getDate() == 23) {
console.log(d + 'is a valid date!');
}
You can create a separate function based on the above to create dates that returns either a date object or NaN if the values aren't valid (and honours two digit years).

Javascript Date.UTC() function is off by a month?

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)

Categories

Resources