-1

How can I generate the date of birth from South African ID number?

The first 6 digits of the ID number represent their date of birth in the format YYMMDD.

From the ID number inputted by the user, I want to extract the first 6 characters and use this to fill in the date of birth input Date in the format dd/mm/yyyy

This is my code to get first 6 digits as a valid date:

var currDate = new Date(saIDNumber.substring(0, 2),
                        saIDNumber.substring(2, 4) - 1,
                        saIDNumber.substring(4, 6)); 
var id_date  = currDate.getDate(); 
var id_month = currDate.getMonth(); 
var id_year  = currDate.getFullYear();

The code doesn't generate the date of birth automatically but it doesn't show any errors either.

Solomon Ucko
  • 5,724
  • 3
  • 24
  • 45
  • 4
    The first 6 digits are `YYMMDD` ... how do we know if YY = 23 means 1923 or 2023? – Tim Biegeleisen May 13 '23 at 04:00
  • The first 6 digits will output from the ID Number as follows for example if someone ID number is 931205 then the output should extract the first 6 digits and shows as new date as follows 05/12/1993 – Gee Developer May 13 '23 at 04:03
  • 2
    Please answer the question posed to you in the above comment. – Tim Biegeleisen May 13 '23 at 04:04
  • But get full year shows in full if the first year is 23 is born in 1923 – Gee Developer May 13 '23 at 04:08
  • If the first 6 digits it's YYDDMM then the year is 1923 not 2023 because 23 presents the 20th century before the 2000 – Gee Developer May 13 '23 at 04:41
  • 2
    Why is your posted code not working for you? Please add that to your post – Hans Kesting May 13 '23 at 04:58
  • I just did that my code doesn't show any errors that's why I need help where did I go wrong – Gee Developer May 13 '23 at 05:57
  • 2
    @Yogi I agree that this is probably an obscure edge case, and in fact those very old SA citizens may not even have these numbers. But I just wanted to get the rules/assumptions from the OP so that someone might give an exact answer. – Tim Biegeleisen May 13 '23 at 07:30
  • Also, for us who are not familiar with South African IDs, is it `YYMMDD` as @TimBiegeleisen asked, or `YYDDMM`? Your example "931205 = 05/12/1993" doesn't clarify because both 05 and 12 could be either the day or month. – user1601324 May 13 '23 at 19:28
  • 1
    You have given us the code for creating a date from the first 6 digits - have you confirmed that (1) a valid `Date` object is created and (2) the right values are being added to your 3 `id_` variables? And what are you doing with those variables? You mention a date of birth input but you don't show us any code for it, or how you use the variables to add them to that input. – user1601324 May 13 '23 at 19:48

2 Answers2

2

Rewriting my answer a bit because I found some issues after reading the comments! Generally your code works, but you WILL have issues with dates after 1999 because a two-digit year after that can begin with a leading zero, which is not allowed in a number. For example in the console running console.log(001234) will produce 668 since it apparently will try to convert this number into octal!

So, you absolutely must have the "numbers" input as strings of numbers to ensure your data is accurate. This means you must always save these number as strings, and pass them around as strings.

With that covered the other issue is that dates after 1999 will assume a '19' prefix. So a number of '001205' will assume the year meant by 00 is 1900 and not 2000. As it was pointed out above in a comment there is a 0.025% chance for a person to be over 100 years old, and that a person this old in this country may not have even been issued a number, this seems like it's safe to assume they were worn in this century.

I think a good way to address this is to compare the two digit input year against the last two digits of the current year. As I write this is is 2023, so that becomes 23. Here are some examples

  • An input year of 05 is less than 23 so we can prepend 20 so the full year is 2005.
  • An input year of 27 is greater than 23 so we can prepend 19 so the full year is 1927.

Here is my recommendation that takes all of this into account. I also removed the need for a Date object. This means we don't need to subtract 1 from the month now either. We can just get the numbers from the string and then parse them into real numbers.

function parseIdNumber(numStr){
  //if the last 2 digits of the input year are less than the last 2 of the current year
  //assume they were born after the year 2000
  var currentYearTwoDigits = parseInt(new Date().getFullYear().toString().substring(2,4), 10);
  var inputYear = parseInt(numStr.substring(0, 2), 10);
  var bestGuessYear = (inputYear < currentYearTwoDigits ? '20' : '19') + inputYear;

 return {
  day: parseInt(numStr.substring(4, 6), 10),
  month: parseInt(numStr.substring(2, 4), 10),
  year: parseInt(bestGuessYear, 10)
 }
}

console.log(parseIdNumber('541213'));
console.log(parseIdNumber('841003'));
console.log(parseIdNumber('930214'));
console.log(parseIdNumber('991205'));
console.log(parseIdNumber('000101'));
console.log(parseIdNumber('071205'));
console.log(parseIdNumber('220824'));
Chris Barr
  • 29,851
  • 23
  • 95
  • 135
  • `new Date(saIDNumber.substring(0, 2), ...)` will treat all years as being in the twentieth century. So anyone born since 2000 will be considered as over 100 years old. Some logic needs to be added to determine wether the year should be prefixed by "19" or "20". – RobG May 15 '23 at 12:25
  • 1
    but that number is issues by the South African government. How that seems like their oversight when these numbers were issued. How in the world is any code supposed to guess at that without any additional information? Should this code just assume that its more likely to not be 100 years old? – Chris Barr May 15 '23 at 12:31
  • after I wrote that comment I thought of a good way to make that assumption and also fix some bugs I found. See my revised answer above. – Chris Barr May 15 '23 at 12:56
  • 1
    Probably. It might be prudent for the OP to assume "23" represents "2023" and add a checkbox to select if it should be 1923 (or any value from 0 to the current year % 100). – RobG May 15 '23 at 12:57
  • 1
    `new Date(Date.now())` will produce an identical result to `new Date()`. ;-) – RobG May 15 '23 at 13:15
  • Thanks, updated. Seems obvious now, not sure why I did that, haha. I think I was messing with `Date.now()` which gave me a number, so I wanted to convert that to a current date and didn't think about what I was doing too much. – Chris Barr May 15 '23 at 14:15
1

There is no need to use a Date object, an identical result to the OP code is given by:

var id_date  = saIDNumber.substring(4, 6);
var id_month = saIDNumber.substring(2, 4); 
var id_year  = "19" + saIDNumber.substring(0, 2);

The Date constructor treats year values 0 to 99 as 1900 + year (see step 5.j.ii).

There is an issue that anyone born since 1999 (i.e. year value 00 to 23) will be treated as 1900 to 1923. You might assume that any ID year that is prior to the current two digit year must be in the 21st century, but there will be centenarians who will be children again. ;-)

So:

function getIDDate(saIDNumber) {
    let currentYear = new Date().getFullYear() % 100;
    let [year, month, day]  = saIDNumber.match(/\d\d/g);
    return `${day}/${month}/${(year <= currentYear? '20' : '19') + year}`;
}

['931205','150124'].forEach( id =>
  console.log(`${id} => ${getIDDate(id)}`)
);

This doesn't validate the values, they may not represent a valid date.

PS.

new Date().getFullYear() % 100 could be new Date().getYear() but I think the former is clearer in getting an appropriate year value.

RobG
  • 142,382
  • 31
  • 172
  • 209