Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const _getTransformationsStruct = (translate) => [
header: translate('candidate-list-template.headers.birth-date'),
property: 'birthdate',
transformFn: (cellVal) => {
return convertDateValue({ dateString: cellVal, inputFormat: 'DD/MM/YYYY', outputFormat: 'YYYY-MM-DD' });
return convertDateValue({ dateString: cellVal, inputFormat: 'DD/MM/YYYY' });
},
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ function _getDataFromColumnNames({ expectedHeadersKeys, headers, line }) {
convertDateValue({
dateString: currentValue,
inputFormat: 'DD/MM/YYYY',
outputFormat: 'YYYY-MM-DD',
}) ?? currentValue;
} else if (key === 'extraTimePercentage') {
data[key] = currentValue || null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,6 @@ class ImportOrganizationLearnerSet {
return convertDateValue({
dateString: attribute,
inputFormat: dateFormat.config.validate.format,
alternativeInputFormat: dateFormat.config.validate.format,
outputFormat: 'YYYY-MM-DD',
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,12 +164,16 @@ class SharedCsvParser {
}

_buildDateAttribute(dateString) {
const convertedDate = convertDateValue({
let convertedDate = convertDateValue({
dateString,
inputFormat: 'DD/MM/YYYY',
alternativeInputFormat: 'DD/MM/YY',
outputFormat: 'YYYY-MM-DD',
});
if(convertedDate === null) {
convertedDate = convertDateValue({
dateString,
inputFormat: 'DD/MM/YY',
});
}
return convertedDate || dateString;
}

Expand Down
116 changes: 88 additions & 28 deletions api/src/shared/infrastructure/utils/date-utils.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,109 @@
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat.js';

dayjs.extend(customParseFormat, {
parseTwoDigitYear: (yearString) => {
const year = parseInt(yearString);
const currentYear = new Date().getFullYear();
return 2000 + year < currentYear ? 2000 + year : 1900 + year;
},
});

function isValidDate(dateValue, format) {
return dayjs(dateValue, format, true).isValid() || dateValue instanceof Date;
export function isValidDate(dateValue, format) {
const convertedDateValue = convertDateValue({ dateString: dateValue, inputFormat: format });
return convertedDateValue !== null;
//return dayjs(dateValue, format, true).isValid() || dateValue instanceof Date;
}

function convertDateValue({ dateString, inputFormat, alternativeInputFormat = null, outputFormat }) {
const isDateInstance = dateString instanceof Date;

if (isDateInstance) {
return formatDate([dateString], outputFormat);
export function convertDateValue({ dateString, inputFormat }) {
let givenDateObject;
if (dateString === undefined || dateString === null) {
return null;
}
if (typeof dateString === 'object') {
givenDateObject = dateString;
} else {
if (!formatIsMatching(dateString, inputFormat)) {
return null;
}
const year = extractYear(dateString, inputFormat);
const month = extractMonth(dateString, inputFormat);
const dayOfMonth = extractDayOfMonth(dateString, inputFormat);
givenDateObject = new Date(year, month, dayOfMonth);
if (
parseInt(month) !== parseInt(givenDateObject.getMonth()) ||
parseInt(dayOfMonth) !== parseInt(givenDateObject.getDate())
) {
return null;
}
}

if (isValidDate(dateString, inputFormat)) {
return formatDate([dateString, inputFormat, true], outputFormat);
} else if (alternativeInputFormat && isValidDate(dateString, alternativeInputFormat)) {
return formatDate([dateString, alternativeInputFormat, true], outputFormat);
const options = {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour12: false,
};

//YYYY-MM-DD
const formatter = new Intl.DateTimeFormat('sv-SE', options);

return formatter.format(givenDateObject);
}

function formatIsMatching(dateString, inputFormat) {
return dateString.replace(/[0-9]/g, ' ') === inputFormat.replace(/(D|M|Y)/g, ' ');
}

function extractYear(givenDate, incomeDateFormat) {
const splittedIncomeDateFormat = incomeDateFormat?.split('') ?? [];
let year = givenDate
?.split('')
.map((c, i) => {
if (splittedIncomeDateFormat[i] === 'Y') {
return c;
}
return;
})
.filter(Boolean)
.join('');
const currentYear = new Date().getFullYear().toString().slice(-2);
if (year.length === 2 && year < currentYear) {
year = `20${year}`;
} else if (year.length === 2 && year >= currentYear) {
year = `19${year}`;
}
return year;
}

return null;
function extractMonth(givenDate, incomeDateFormat) {
const splittedIncomeDateFormat = incomeDateFormat?.split('') ?? [];
const month = givenDate
?.split('')
.map((c, i) => {
if (splittedIncomeDateFormat[i] === 'M') {
return c;
}
return;
})
.filter(Boolean)
.join('');
return month - 1;
}

function formatDate(params, outputFormat) {
return dayjs(...params).format(outputFormat);
function extractDayOfMonth(givenDate, incomeDateFormat) {
const splittedIncomeDateFormat = incomeDateFormat?.split('') ?? [];
const dayOfMonth = givenDate
?.split('')
.map((c, i) => {
if (splittedIncomeDateFormat[i] === 'D') {
return c;
}
return;
})
.filter(Boolean)
.join('');
return dayOfMonth;
}

/**
* @param {Date} date
* @returns {Date} a new Date object
*/
function anonymizeGeneralizeDate(date) {
export function anonymizeGeneralizeDate(date) {
if (!date) return null;

const newDate = new Date(date);
newDate.setUTCDate(1);
newDate.setUTCHours(0, 0, 0, 0);
return newDate;
}

export { anonymizeGeneralizeDate, convertDateValue, isValidDate };
133 changes: 51 additions & 82 deletions api/tests/shared/unit/infrastructure/utils/date-utils_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ describe('Unit | Utils | date-utils', function () {
it('should accept a date object', function () {
expect(isValidDate(new Date(), 'YYYY-MM-DD')).to.be.true;
});

it('should accept even with french format', function () {
expect(isValidDate('23/12/2022', 'DD/MM/YYYY')).to.be.true;
});
});

describe('Invalid cases', function () {
Expand Down Expand Up @@ -57,95 +61,60 @@ describe('Unit | Utils | date-utils', function () {
});

describe('#convertDateValue', function () {
context('when alternativeInputFormat does not exist', function () {
context('when dateValue does not match inputFormat', function () {
it('should return null', function () {
expect(convertDateValue({ dateString: '1980-05-05', inputFormat: 'DD/MM/YYYY', outputFormat: 'YYYY-MM-DD' }))
.to.be.null;
});
context('when dateValue does not match inputFormat', function () {
it('should return null', function () {
expect(convertDateValue({ dateString: '1980-05-05', inputFormat: 'DD/MM/YYYY' })).to.be.null;
});
});

context('when dateValue matches inputFormat', function () {
it('should return converted date', function () {
expect(convertDateValue({ dateString: '05/05/1980', inputFormat: 'DD/MM/YYYY' })).to.equal('1980-05-05');
});
});

context('when dateValue matches inputFormat', function () {
it('should return converted date', function () {
expect(
convertDateValue({ dateString: '05/05/1980', inputFormat: 'DD/MM/YYYY', outputFormat: 'YYYY-MM-DD' }),
).to.equal('1980-05-05');
});
context('when dateValue is Date Object', function () {
it('should return converted date', function () {
expect(
convertDateValue({
dateString: new Date('1980-05-05'),
inputFormat: 'DD/MM/YYYY',
}),
).to.equal('1980-05-05');
});
});

context('when alternativeInputFormat exists', function () {
context('when dateValue does not match nor inputFormat, nor alternativeInputFormat', function () {
it('should return null', function () {
expect(
convertDateValue({
dateString: '1980-05-05',
inputFormat: 'DD/MM/YYYY',
alternativeInputFormat: 'DD/MM/YY',
outputFormat: 'YYYY-MM-DD',
}),
).to.be.null;
});
});

context('when dateValue matches inputFormat', function () {
it('should return converted date', function () {
expect(
convertDateValue({
dateString: '05/05/1980',
inputFormat: 'DD/MM/YYYY',
alternativeInputFormat: 'DD/MM/YY',
outputFormat: 'YYYY-MM-DD',
}),
).to.equal('1980-05-05');
});
});

context('when dateValue is Date Object', function () {
it('should return converted date', function () {
expect(
convertDateValue({
dateString: new Date('1980-05-05'),
inputFormat: 'DD/MM/YYYY',
alternativeInputFormat: 'DD/MM/YY',
outputFormat: 'YYYY-MM-DD',
}),
).to.equal('1980-05-05');
});
});

context('when dateValue matches alternativeInputFormat with 2 digits year', function () {
it('should return converted date with year 2000 if input year < the current year', function () {
const currentYear = new Date().getFullYear();
const currentTwoDigitYear = currentYear - 2000;
const inputDate = '05/05/' + (currentTwoDigitYear - 1);
const expectedDate = currentYear - 1 + '-05-05';
expect(
convertDateValue({
dateString: inputDate,
inputFormat: 'DD/MM/YYYY',
alternativeInputFormat: 'DD/MM/YY',
outputFormat: 'YYYY-MM-DD',
}),
).to.equal(expectedDate);
});

it('should return converted date with year 1900 if input year >= the current year', function () {
const currentYear = new Date().getFullYear();
const currentTwoDigitYear = currentYear - 2000;
const inputDate = '05/05/' + currentTwoDigitYear;
const expectedDate = 1900 + currentTwoDigitYear + '-05-05';
expect(
convertDateValue({
dateString: inputDate,
inputFormat: 'DD/MM/YYYY',
alternativeInputFormat: 'DD/MM/YY',
outputFormat: 'YYYY-MM-DD',
}),
).to.equal(expectedDate);
});
context('when dateValue matches alternativeInputFormat with 2 digits year', function () {
it('should return converted date with year 2000 if input year < the current year', function () {
const currentYear = new Date().getFullYear();
const currentTwoDigitYear = currentYear - 2000;
const inputDate = '05/05/' + (currentTwoDigitYear - 1);
const expectedDate = currentYear - 1 + '-05-05';
expect(
convertDateValue({
dateString: inputDate,
inputFormat: 'DD/MM/YY',
}),
).to.equal(expectedDate);
});

it('should return converted date with year 1900 if input year >= the current year', function () {
const currentYear = new Date().getFullYear();
const currentTwoDigitYear = currentYear - 2000;
const inputDate = '05/05/' + currentTwoDigitYear;
const expectedDate = 1900 + currentTwoDigitYear + '-05-05';
expect(
convertDateValue({
dateString: inputDate,
inputFormat: 'DD/MM/YY',
}),
).to.equal(expectedDate);
});
});

it('returns null for inexisting date', function () {
expect(convertDateValue({ dateString: '2008-02-31', inputFormat: 'YYYY-MM-DD' })).to.be.null;
});
});

describe('#anonymizeGeneralizeDate', function () {
Expand Down