Calculate age from South African ID number displayed from a barcode scan

1. What is the issue? Please be detailed.
I have introduced the formulas to calculate the age from the SA ID number:
type name Label
barcode id_barcode Please scan the ID Barcode of head of the household
type name calculation
calculate birth_year if(substr(${id_barcode}, 0, 2) > (format-date(today(), '%y')), concat('19', substr(${id_barcode}, 0, 2)), concat('20', substr(${id_barcode}, 0, 2)))
calculate birth_month substr(${id_barcode}, 2, 2)
calculate birth_day substr(${id_barcode}, 4, 2)
calculate birth_date concat(${birth_year}, '-', ${birth_month}, '-', ${birth_day})
calculate head_age int((today() - date(${birth_date})) div 365.25)

When testing the form, at the step when I'm supposed to capture the details of the household head, I get the following error:
Error evaluating field 'head_age' (/data/household_head[1]/head_age[1]):
The problem was located in Calculate expression for / data/ household_head/head_age
XPath evaluation: type mismatch
The value "20--" can't be converted to a date.

2. What steps can we take to reproduce this issue?

3. What have you tried to fix the issue?

4. Upload any forms or screenshots you can share publicly below.

Hi @FeSoZA
What I can deduce from this is that your formula created an invalid date string, which caused the XPath type mismatch error. By adding checks for valid date components before calculating the date and age, you can prevent this error and ensure that the age calculation only happens with a valid date.

Try the code below and see if it's going to work:
calculate birth_year if(substr(${id_barcode}, 0, 2) > (format-date(today(), '%y')), concat('19', substr(${id_barcode}, 0, 2)), concat('20', substr(${id_barcode}, 0, 2)))

calculate birth_month if(number(substr(${id_barcode}, 2, 2)) > 0 and number(substr(${id_barcode}, 2, 2)) <= 12, substr(${id_barcode}, 2, 2), '')

calculate birth_day if(number(substr(${id_barcode}, 4, 2)) > 0 and number(substr(${id_barcode}, 4, 2)) <= 31, substr(${id_barcode}, 4, 2), '')

calculate birth_date if(${birth_year} != '' and ${birth_month} != '' and ${birth_day} != '', concat(${birth_year}, '-', ${birth_month}, '-', ${birth_day}), '')

calculate head_age if(${birth_date} != '', int((today() - date(${birth_date})) div 365.25), '')

Key changes from your initial code:
Birth month and birth day validation: The code now checks if the birth_month is between 1 and 12 and if the birth_day is between 1 and 31. If not, it returns an empty string, avoiding invalid dates.

Validation of complete birth date: The birth_date is only concatenated if all components (year, month, day) are valid. Otherwise, it returns an empty string.

Age calculation only if valid date: head_age is only calculated if a valid birth_date exists, avoiding type mismatches in date parsing.

@FeSoZA, please let me know if it works or not.

Best regards.

1 Like

Hi @Certified_Bashir

Thank you so much for the response and advice. I can confirm that it works, but only as far as completing the calculation. I have a display step at the end of the calculation and it doesn't display the age.

My code is as follows:
type name label
note display_head_age The age of the head of the household is ${head_age}
image

This code returns "NaN" as the value for ${head_age}. This is the same result for the application reference number.

What could I be missing?

2 Likes

Hello @FeSoZA, It's cool to know that it works.

The issue you're facing with the NaN (Not a Number) result may likely be due to improper handling of dates or number conversion during the calculations. Let's try to break the problem into chunks by creating a note for each input and validating each one. By these, we should be able to figure out where the issues are. Try creating a note for each and every input like this:

type name label
note check_birth_year ${birth_year}
note check_birth_month ${birth_month}
note check_birth_day ${birth_day}
note check_birth_date ${birth_date}

Once we verify these points, we can figure out where the error lies.
Try giving it a shot @FeSoZA

Best regards.

1 Like

Thank you @Certified_Bashir

I tried your suggestion and got the result below, which only displays the birth year.
image

To me, this suggests that the form logic skips the steps that follow the birth year.

I would appreciate any advice.