Calculate age in years, months and days

function OnClick(clickData)
{
	var dlg = clickData.func.Dlg;

	var fecha1String = dlg.getString("Fecha nacimiento (DD-MM-AAAA):");
	if (!fecha1String) {
		return;
	}

	var datePartsStringArray = fecha1String.split("-"); // Split string (which has date parts separated by "-") to individual parts (parts are still strings, you can't calculate with them unless you convert them to integers first).
	var dayString = datePartsStringArray[0];
	var monthString = datePartsStringArray[1];
	var yearString = datePartsStringArray[2];

    var fecha1JsDateObj = new Date(yearString, parseInt(monthString) - 1, dayString); // Note how we convert the monthString to integer so we can offset it by 1 (JS Date has months in range 0-11 and not 1-12).
	DOpus.Output(fecha1JsDateObj);
}
1 Like

Thank you very much @Bytespiller, you are top, the perfect code. Now I want the days and months of the dates to be shown in the result to always be shown with 2 digits, create these lines, and they work fine, but is there a way to optimize them?!?

01

//Fecha de nacimiento
var diaF1 = ("0" + fecha1.getDate()).slice(-2);
var mesF1 = ("0" + (fecha1.getMonth()+1)).slice(-2);
var anioF1 = fecha1.getFullYear();
var fecha1Corta = diaF1 + "-" + mesF1 + "-" + anioF1

//Fecha actual
var diaF2 = ("0" + fecha2.getDate()).slice(-2);
var mesF2 = ("0" + (fecha2.getMonth()+1)).slice(-2);
var anioF2 = fecha2.getFullYear();
var fecha2Corta = diaF2 + "-" + mesF2 + "-" + anioF2
function OnClick(clickData)
{
	function zfill(n) // Zero fill.
	{
		return ("00" + n).slice(-2);
	}

	var fecha = new Date(); // Test

	var diaStr = zfill(fecha.getDate());
	var mesStr = zfill(fecha.getMonth() + 1);
	var anioStr = fecha.getFullYear(); // Don't zfill unless you want a short year (e.g., 23).
	var formatted = diaStr + "-" + mesStr + "-" + anioStr;
	DOpus.Output(formatted);
}

You may want to wrap the entire formatting functionality into a function, so you can format any date with a single function call.

Code v2
function formatDate(d)
{
	function zfill(n) // Zero fill.
	{
		return ("00" + n).slice(-2);
	}
	
	var diaStr = zfill(d.getDate());
	var mesStr = zfill(d.getMonth() + 1);
	var anioStr = d.getFullYear(); // Don't zfill unless you want a short year (e.g., 23).
	var formatted = diaStr + "-" + mesStr + "-" + anioStr;
	return formatted;
}

function OnClick(clickData)
{
	var fecha1 = new Date(2019, 02 - 1, 13); // Test
	var fecha2 = new Date(2020, 08 - 1, 25); // Test
	var fecha3 = new Date(); // Test
	
	DOpus.Output("F1: " + formatDate(fecha1));
	DOpus.Output("F2: " + formatDate(fecha2));
	DOpus.Output("F3: " + formatDate(fecha3));
}
1 Like

Hi @bytespiller, thank you very, very much, your codes are perfect, they show a lot of professionalism, I am going to apply the first one, I did not understand the second one very well, but from what I managed to understand, it is very practical to format several dates at the same time.

I just didn't understand: the function formatDate(d) create a format pattern, which is automatically applied to variables Fecha1, Fecha2 and Fecha3. Is it the same or am I wrong? But I don't see anything that relates one part of the code to the other, that is, function formatDate(d)with Fechas.

If you have time later, explain that detail to me, I want to learn, thank you very much for everything!!!

That formatDate function creates and returns a new string, the original dates (Fecha variables) remain untouched, nothing is applied to them.

The formatDate function takes a look at the values of fechas it receives, and then it creates and returns new strings. Fechas that were given to formatDate stay the same, they are not modified in any way.

Now I understand, thank you very much! :grinning:

Hi @lxp, could you help me to correct these lines, so that when the day of the birth date is greater than the day of the current date, the days are not calculated wrongly, as if they were milliseconds?

Exemplo:

Birthdate: 28-01-2023
Today ....: 22-08-2023

Age.............: 6 months, 2799900000000020 days
Correct age: 6 months, 25 days

Imagen

//Calculate age
var years = date2.getFullYear() - date1.getFullYear();
var months = date2.getMonth() – date1.getMonth();
var days = date2.getDate() – date1.getDate();

if( days <= 0){
    var first_day_next_month = new Date(date1.getFullYear(), date1.getMonth()+1, 1);
     var diff = first_day_next_month - date1;
     var days_until_end_month = Math.floor(diff /  24 * 60 * 60 * 1000);
     dias = days_until_end_month + date2.getDate() - 1; 

     months--;
     }

     if (months < 0){
       months = 12 + months;
       years--;
}

You can get them via

myDate + myDate.ms

Opus date initialization from JScript Date

Try

var opusDate = DOpus.Create().Date('1970-01-01');
opusDate.Add(jsDate.valueOf()/1000, 's');

Thank you very much @lxp, @bytespiller had already alerted me about that, and he even showed me how to correct that Opus detail, but since the result was still wrong I went back to pure Jscript.

I will try to apply your recommendation, thank you very much once again!

But that will really be the problem, because most of the dates are calculated correctly, only the dates of birth that their day is greater than the current day (today) give a problem. It is as if it were missing to create a new condition to treat the dates with that behavior.

You seem to be after a moving target in this thread, like a dog chasing its own tail. The first step to finding a solution would be to come up with a definition of "month". Once you are happy with that, jump into the calculus.

@lxp I would like to consider 1 month, as the Windows calculator considers, the time elapsed from one day to that same day of the next month, for example, consider, from January 1 to February 1, 1 month; or from February 6 to March 6, 1 month.

Let JScript shuffle around the days and months:

var d1 = new Date(2023, 0, 28);
var d2 = new Date(2023, 7, 22);

var age = new Date(0);
age.setMilliseconds(d2 - d1);

DOpus.Output(d1);
DOpus.Output(d2);
DOpus.Output(age);
DOpus.Output(age.getFullYear() - 1970);
DOpus.Output(age.getMonth());
DOpus.Output(age.getDate());

2 Likes

What a wonderful thing @lxp, thank you a thousand times, I've been here for hours breaking my head, doing a thousand different conditions and nothing works :grinning:

	var df1 = fecha1.getDate());
	var mf1 = fecha1.getMonth()+1;
	var af1 = fecha1.getFullYear();

	var df2 = fecha2.getDate());
	var mf2 = (fecha2.getMonth()+1);
	var af2 = fecha2.getFullYear();

    var febrero = (af1 % 4 == 0 && af1 % 100 != 0) ? 29 : 28; // Si año bisiesto
	var ultimo_dia_meses = [31, febrero , 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
	var ultimo_dia_mes_fecha1 = ultimo_dia_meses.slice(mf1-1, mf1);

	var anios = (df1 < df2 && mf1 <= mf2) ? (af2 - af1 ) : (af2 - af1);
	var meses = (df1 < df2 && af1 == af2) ? (mf2 - mf1 -1) : (mf2 - mf1);
	var meses = (df1 < df2 && af1 != af2) ? (12 - mf1 + mf2 -1) : (12 - mf1 + mf2);
	var dias = (df1 < df2) ? (df2 - df1) : (ultimo_dia_mes_fecha1 - df1 + df2);

such an epic with a script!!! ))) will you post the full working version?

Yes, as soon as I correct the last details, I will post the complete code!

Hi @bytespiller, do you remember:

	//Fecha nacimiento
	var fecha1String = dlg.getString("Fecha nacimiento (DD-MM-AAAA):");
	if (!fecha1String) {
		return;
	}

	//Covertir texto en fecha verdadera
	var fecha1Array = fecha1String.split("-"); //Se eliminan los guiones (-)
	var diaString = fecha1Array[0]; //1° bloque del array
	var mesString = fecha1Array[1]; //2° bloque del array
	var anioString = fecha1Array[2]; //3° bloque del array
    var fecha1 = new Date(anioString, parseInt(mesString) - 1, diaString); //Se obtine una fecha verdadera

Why is it that if I enter some dates with their days or months with 0 to the left, example 01-08-2023, the date obtained is another, following the previous example, the date obtained is 01-12-2020? If I enter 1-8-2023 all good, I get 01-08-2023

It turns out that the parseInt takes only the first zero of the string "08", it also turns out that the parseInt is completely unnecessary and JScript will happily calculate "08" - 1 without need for converting the string to int explicitly.

Therefore change the var fecha1 = ... line to a simpler version:
var fecha1 = new Date(anioString, mesString - 1, diaString);
and all should work.

Thank you very much @lxp, your alternative works perfect, I was calculating with 1 day too much according to the Windows calculator, but I corrected it with -1. I spent all night writing a set of conditions to get the same result, but soon, when I post the full code, the alternative I'll post will be yours, for being simpler, safer and a tribute to you for your great help! !!

Oh @bytespiller, great friend, you helped me so much that I feel that way, a great friend, thank you once again, without you this code would not exist!!!