Home > OS >  Regex to parse dates
Regex to parse dates

Time:10-15

I have a date and a format for that date, given by the user. (d.m.yyyy and 15.10.2021 used for this example)

const format = dateFormat || 'yyyy-mm-dd';

From that format, I need to get the position of the year, month and day, so that I can use that position on the date.

const year = /y{4}|y{2}/.exec(format);
const month = /m{1,2}/.exec(format);
const day = /d{1,2}/.exec(format);

Everything works so far, but when i try to get the position of year from my date:

const yearVal = date.substring(year.index, year.index   year[0].length);

year.index is 4 when it should be 6. So instead of 2021, i get 0.20 It's like index does not include the dots, but how would that make any sense!?

This is where I got the idea: Return positions of a regex match() in Javascript?

Am I using index wrong, or what went wrong with this?

EDIT: Some people understood that the format "d.m.yyyy" was a typo, or means that there is only one number. I understand the confusion, so lets clear that out. Libraries like Luxon or node-dateformat define the difference between "d" and "dd" like this:

"d" Day of the month as digits; no leading zero for single-digit days.

"dd" Day of the month as digits; leading zero for single-digit days.

CodePudding user response:

You could generate a regex from the pattern like this:

format.replace(/([ymd])\1*/g, (match, ymd) => `(?<${ymd}>${'\\d'.repeat(match.length)})`);

yyyy-mm-dd will become /(<?y>\d\d\d\d)-(<?m>\d\d)-(<?d>\d\d)/, then you can extract the year/month/day using group names:

function getDates(format, date) {
  const regex = new RegExp(format.replace(/([ymd])\1*/g, (match, ymd) => `(?<${ymd}>${'\\d'.repeat(match.length)})`));
  const result = date.match(regex);
  if(result) {
    const { y: year, m: month, d: day } = result.groups;
    return { year, month, day };
  }
}


console.log(getDates('yyyy-mm-dd', '2021-10-15'));
console.log(getDates('dd/mm/yyyy', '15/10/2021'));
console.log(getDates('mm-dd-yy', '10-15-21'));
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

This is solution is not smart. You can't easily add hours and minutes to this. But at least it works.

function dateFromString(date, dateFormat) {
  const format = dateFormat || 'yyyy-mm-dd';
  let parts = date.match(/(\d )/g); // get all groups of numbers

  // parse format
  const year = /y{4}|y{2}/.exec(format).index;
  const month = /m{1,2}/.exec(format).index;
  const day = /d{1,2}/.exec(format).index;

  // order the parts
  if (year > month) {
    if (month > day) {
      parts = parts.reverse();
    } else if (day > year) {
      [parts[0], parts[1]] = [parts[1], parts[0]];
    } else {
      [parts[0], parts[1], parts[2]] = [parts[2], parts[0], parts[1]];
    }
  } else if (month > day) {
    if (day > year) {
      [parts[1], parts[2]] = [parts[2], parts[1]];
    } else {
      [parts[0], parts[1], parts[2]] = [parts[1], parts[2], parts[0]];
    }
  }
   
  // make sure year is a full year
  if (parts[0].length < 4) {
    parts[0] = "20"   parts[0];
  }

  return new Date(parts[0], parts[1], parts[2], 0, 0, 0, 0);
}


console.log(dateFromString("15.10.21", "d.m.yy").toString());
console.log(dateFromString("10/15/2021", "mm/dd/yyyy").toString());
console.log(dateFromString("2021-10-15", "yyyy-mm-dd").toString());
console.log(dateFromString("15@2021#10", "dd@yyyy#mm").toString());
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related