How to transform string into Date object with Typescript?

Asked

Viewed 114 times

3

I am receiving from the HTML form a string containing the date selected in the pattern dd/mm/yyyy, and want to create an object Date from that string.

The problem is that the Date only accepts strings in patterns recognized by the method Date.parse(), which are the standards IETF-compliant RFC 2822 timestamps and ISO8601. There is also the option to pass the numbers separately, following the examples:

let data1 = new Date(ano,mes,dia);
let data2 = new Date(ano,mes,dia,hora,minuto,segundo);

What I need is a practical way to convert a string into the format dd/mm/yyyy at one of the possible inputs of the Date.

I tried to use a function that I had developed during a course, which broke the string into parts and reversed its order, but it was error in VS Code:

textoParaData(texto){
  if(!/\d{2}\/\d{2}\/\d{4}/.test(texto))
    throw new Error(`Deve estar no formato dd/mm/aaaa`);
  return new Date(...(texto.split('/').map((item, indice) => item - indice % 2).reverse())); // Expected 0-7 arguments, but got 0 or more.
}

1 answer

4


You can change the function to:

textoParaData(texto) {
    let m = texto.match(/^(\d{2})\/(\d{2})\/(\d{4})$/);
    if (! m)
        throw new Error('Deve estar no formato dd/mm/aaaa');
    m = m.slice(1, 4).map(v => parseInt(v));
    return new Date(m[2], m[1] - 1, m[0]);
}

Now regex has the markers ^ and $, which are respectively the beginning and end of the string. So I guarantee that the string will only have what is in regex. If I do not use ^ and $, regex can validate strings that have anything else before or after the date.

Then I see if the regex found any match. In case you haven’t found it, I’m already making the mistake.

Notice that I put the numbers in parentheses, because they form capture groups, who are returned in an array. As this array has several other information (such as the full text of the date found), I use slice to obtain only the groups (which will be respectively the day, month and year), and use map to turn them into numbers (remember that a regex always works with text, so m is an array of strings).

Then just create the Date passing the year, month and day (remembering to subtract one of the month, since in the Date from Javascript, January is Zero, February is 1, etc.).


This regex still accepts invalid values, for example 31/02/2019. In the case, as February does not have 31 days, the day 31 is adjusted to March 3. If you want to validate the values, one way is to verify that the Date created has the same original values (as this indicates that none of these automatic adjustments has been made):

textoParaData(texto) {
    let m = texto.match(/^(\d{2})\/(\d{2})\/(\d{4})$/);
    if (! m)
        throw new Error('Deve estar no formato dd/mm/aaaa');
    let [dia, mes, ano] = m.slice(1, 4).map(v => parseInt(v));
    let data = new Date(ano, mes - 1, dia);
    if (data.getDate() !== dia || data.getMonth() + 1 !== mes || data.getFullYear() !== ano)
        throw new Error('Valores inválidos');
    return data;
}

It is even possible to change the regex so that it validates itself if the date values are correct (if the month has 30 or 31 days, if it is leap year, etc), but it is not worth it, because it would become too big and would become a maintenance nightmare - as explained here and here.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.