Calculate age in years, months and days

The problem is in if(dias<0) block:

  1. You forgot to use the getMillis in var diff = first_day_next_month - fecha1; + I think you may need to swap the order of operations (fecha1 - first_day.... instead), so check that too.
  2. The dias = days_until_end_month + getMillis(fecha2) - 1; seems wrong to use getMillis(fecha2), I think you wanted fecha2.day?

I can't help with math though, that's not my strong suit :slight_smile:

Ok @bytespiller , I'm going to try to correct what you tell me and then I'll tell you, thanks a thousand times once again!!!

I made the corrections you indicated and the number of days is now expressed as a smaller number. 6 days is expressing it as 42068, strange, it is neither milliseconds, nor seconds, nor minutes, nor hours. :thinking:

2023-08-21 05 15 16

Hi @bytespiller, I'm trying to rewrite the code in pure JScript format, without any OpusFactory, to see if I understand things better, but I'm having a problem, I enter the date of birth, either in yyyy-MM-dd or in dd format -MM-yyyy, and the result is the same, the date used to perform the calculation is quite different from the one specified.

How could I convert that string to a new Date object? I have tried but the result is the famous NaN.

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

	var anioF1 = fecha1.slice(-4);
	var mesF1 = fecha1.slice(-7, 2);
	var diaF1 = fecha1.slice(0, 2);
	var strF1= anioF1 + "-" + mesF1 + "-" + diaF1;

    var fecha1 = new Date(strF1);
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!