UNPKG

@openmrs/esm-utils

Version:
96 lines (82 loc) 3.48 kB
/** @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); }