@openmrs/esm-utils
Version:
Helper utilities for OpenMRS
96 lines (82 loc) • 3.48 kB
text/typescript
/** @module @category Utility */
import { DurationFormat } from '@formatjs/intl-durationformat';
import { type DurationFormatOptions, type DurationInput } from '@formatjs/intl-durationformat/src/types';
import { attempt } from 'any-date-parser';
import dayjs from 'dayjs';
import objectSupport from 'dayjs/plugin/objectSupport';
import { omit } from 'lodash-es';
import { getLocale } from './get-locale';
dayjs.extend(objectSupport);
/**
* Gets a human readable and locale supported representation of a person's age, given their birthDate,
* The representation logic follows the guideline here:
* https://webarchive.nationalarchives.gov.uk/ukgwa/20160921162509mp_/http://systems.digital.nhs.uk/data/cui/uig/patben.pdf
* (See Tables 7 and 8)
*
* @param birthDate The birthDate. If birthDate is null, returns null.
* @param currentDate Optional. If provided, calculates the age of the person at the provided currentDate (instead of now).
* @returns A human-readable string version of the age.
*/
export function age(birthDate: dayjs.ConfigType, currentDate: dayjs.ConfigType = dayjs()): string | null {
if (birthDate == null) {
return null;
}
const locale = getLocale();
const to = dayjs(currentDate);
let from: dayjs.Dayjs;
if (typeof birthDate === 'string') {
let parsedDate = attempt(birthDate, locale);
if (parsedDate.invalid) {
console.warn(`Could not interpret '${birthDate}' as a date`);
return null;
}
// hack here but any date interprets 2000-01, etc. as yyyy-dd rather than yyyy-mm
if (parsedDate.day && !parsedDate.month) {
parsedDate = Object.assign({}, omit(parsedDate, 'day'), { month: parsedDate.day });
}
// dayjs' object support uses 0-based months, whereas any-date-parser uses 1-based months
if (parsedDate.month) {
parsedDate.month -= 1;
}
// in dayjs day is day of week; in any-date-parser, its day of month, so we need to convert them
if (parsedDate.day) {
parsedDate = Object.assign({}, omit(parsedDate, 'day'), { date: parsedDate.day });
}
from = dayjs(to).set(parsedDate);
} else {
from = dayjs(birthDate);
}
const hourDiff = to.diff(from, 'hours');
const dayDiff = to.diff(from, 'days');
const weekDiff = to.diff(from, 'weeks');
const monthDiff = to.diff(from, 'months');
const yearDiff = to.diff(from, 'years');
const duration: DurationInput = {};
const options: DurationFormatOptions = { style: 'short', localeMatcher: 'lookup' };
if (hourDiff < 2) {
const minuteDiff = to.diff(from, 'minutes');
duration['minutes'] = minuteDiff;
if (minuteDiff === 0) {
options.minutesDisplay = 'always';
}
} else if (dayDiff < 2) {
duration['hours'] = hourDiff;
} else if (weekDiff < 4) {
duration['days'] = dayDiff;
} else if (yearDiff < 1) {
const remainderDayDiff = to.subtract(weekDiff, 'weeks').diff(from, 'days');
duration['weeks'] = weekDiff;
duration['days'] = remainderDayDiff;
} else if (yearDiff < 2) {
const remainderDayDiff = to.subtract(monthDiff, 'months').diff(from, 'days');
duration['months'] = monthDiff;
duration['days'] = remainderDayDiff;
} else if (yearDiff < 18) {
const remainderMonthDiff = to.subtract(yearDiff, 'year').diff(from, 'months');
duration['years'] = yearDiff;
duration['months'] = remainderMonthDiff;
} else {
duration['years'] = yearDiff;
}
return new DurationFormat(locale, options).format(duration);
}