0

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)

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);

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

The problem with this is that the format has 1 letter, but my date has 2 numbers. (d and 15.) So i get 0.20 instead of 2021 How can i change this to work with all the different formats?

You can see all the possible formats here: node-dateformat

For example: the difference between "d" and "dd" are 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.

Jesper
  • 1,007
  • 7
  • 24

2 Answers2

2

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(/(\w)\1+|(\w)/g, ({length}, w, s) => `(?<${w||s}>${s ? '\\d+' : '\\d'.repeat(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'));

console.log('----');

console.log(getDates('yyyy-m-d', '2021-9-15'));
console.log(getDates('yyyy-m-d', '2021-10-6'));
Hao Wu
  • 17,573
  • 6
  • 28
  • 60
  • The last case has a funny problem, where when the year is turned in to a Date object, the year is assumed to be 1921 and not 2021. – Jesper Oct 15 '21 at 08:30
  • 2
    @Jesper Computers don't know how to resolve ambiguities. year `21` could mean any decade. So it's better to use a full year, or convert a two digit year into four digit manually to avoid ambiguities by putting a `20` in front of it, if it only has two digits. – Hao Wu Oct 15 '21 at 08:34
  • This doesn't seem to work with any single digit dates. – Jesper Oct 15 '21 at 09:41
  • 1
    @Jesper make sure the format matches the input. `yyyy-mm-dd` cannot match `2021-9-31`, must be `2021-09-30` – Hao Wu Oct 15 '21 at 09:46
  • 1
    @Jesper I made a mistake, `yyyy-m-d` should match `2020-10-10` since there's no way that October can be represented by a single digit. I just updated my solution to solve this issue. – Hao Wu Oct 15 '21 at 09:59
1

Another option here to split the format & value, lookup y/m/d at respective index

const lookup = ( format, value ) => {
    const f = format.split(/(m+|d+|y+)/).filter(Boolean);
    const v = value.split(/(\D+)/).filter(Boolean);
    return [
        v[f.findIndex(i => i.startsWith('y'))],
        v[f.findIndex(i => i.startsWith('m'))],
        v[f.findIndex(i => i.startsWith('d'))]
    ];
}
console.log(lookup('d.m.yyyy', '10.5.2021'));
console.log(lookup('d.m.yyyy', '10.12.2021'));
console.log(lookup('dd.mm.yyyy', '10.05.2021'));
ProDec
  • 5,390
  • 1
  • 3
  • 12