@openmrs/esm-utils 5.7.3-pre.2135 → 5.7.3-pre.2139

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-utils",
3
- "version": "5.7.3-pre.2135",
3
+ "version": "5.7.3-pre.2139",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Helper utilities for OpenMRS",
6
6
  "browser": "dist/openmrs-esm-utils.js",
@@ -39,7 +39,7 @@
39
39
  "access": "public"
40
40
  },
41
41
  "devDependencies": {
42
- "@openmrs/esm-globals": "5.7.3-pre.2135",
42
+ "@openmrs/esm-globals": "5.7.3-pre.2139",
43
43
  "@types/semver": "^7.3.4",
44
44
  "dayjs": "^1.10.4",
45
45
  "rxjs": "^6.5.3"
@@ -0,0 +1,37 @@
1
+ import dayjs from 'dayjs';
2
+ import type { i18n } from 'i18next';
3
+ import { age } from '.';
4
+
5
+ window.i18next = { language: 'en' } as i18n;
6
+
7
+ describe('Age Helper', () => {
8
+ // test cases mostly taken from
9
+ // https://webarchive.nationalarchives.gov.uk/ukgwa/20160921162509mp_/http://systems.digital.nhs.uk/data/cui/uig/patben.pdf
10
+ // (Table 8)
11
+ const now = dayjs('2024-07-30');
12
+ const test1 = now.subtract(1, 'hour').subtract(30, 'minutes');
13
+ const test2 = now.subtract(1, 'day').subtract(2, 'hours').subtract(5, 'minutes');
14
+ const test3 = now.subtract(3, 'days').subtract(17, 'hours').subtract(30, 'minutes');
15
+ const test4 = now.subtract(27, 'days').subtract(5, 'hours').subtract(2, 'minutes');
16
+ const test5 = now.subtract(28, 'days').subtract(5, 'hours').subtract(2, 'minutes');
17
+ const test6 = now.subtract(29, 'days').subtract(5, 'hours').subtract(2, 'minutes');
18
+ const test7 = now.subtract(1, 'year').subtract(1, 'day').subtract(5, 'hours');
19
+ const test8 = now.subtract(1, 'year').subtract(8, 'day').subtract(5, 'hours');
20
+ const test9 = now.subtract(1, 'year').subtract(39, 'day').subtract(5, 'hours');
21
+ const test10 = now.subtract(4, 'year').subtract(39, 'day');
22
+ const test11 = now.subtract(18, 'year').subtract(39, 'day');
23
+
24
+ it('should render durations correctly', () => {
25
+ expect(age(test1, now)).toBe('90 min');
26
+ expect(age(test2, now)).toBe('26 hr');
27
+ expect(age(test3, now)).toBe('3 days');
28
+ expect(age(test4, now)).toBe('27 days');
29
+ expect(age(test5, now)).toBe('4 wks');
30
+ expect(age(test6, now)).toBe('4 wks, 1 day');
31
+ expect(age(test7, now)).toBe('12 mths, 1 day');
32
+ expect(age(test8, now)).toBe('12 mths, 8 days');
33
+ expect(age(test9, now)).toBe('13 mths, 9 days');
34
+ expect(age(test10, now)).toBe('4 yrs, 1 mth');
35
+ expect(age(test11, now)).toBe('18 yrs');
36
+ });
37
+ });
@@ -1,101 +1,55 @@
1
1
  /** @module @category Utility */
2
+ import dayjs from 'dayjs';
2
3
  import { getLocale } from './omrs-dates';
4
+ import { DurationFormat } from '@formatjs/intl-durationformat';
5
+ import { type DurationInput } from '@formatjs/intl-durationformat/src/types';
3
6
 
4
7
  /**
5
- * Gets the number of days in the year of the given date.
6
- * @param date The date to compute the days within the year.
7
- * @returns The number of days.
8
- */
9
- export function daysIntoYear(date: Date) {
10
- return (
11
- (Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()) - Date.UTC(date.getUTCFullYear(), 0, 0)) /
12
- 24 /
13
- 60 /
14
- 60 /
15
- 1000
16
- );
17
- }
18
-
19
- /**
20
- * Checks if two dates are representing the same day.
21
- * @param firstDate The first date.
22
- * @param secondDate The second date.
23
- * @returns True if both are located on the same day.
24
- */
25
- export function isSameDay(firstDate: Date, secondDate: Date) {
26
- const firstISO = firstDate.toISOString();
27
- const secondISO = secondDate.toISOString();
28
- return firstISO.slice(0, firstISO.indexOf('T')) === secondISO.slice(0, secondISO.indexOf('T'));
29
- }
30
-
31
- /**
32
- * Gets a human readable and locale supported age represention of the provided date string.
33
- * @param dateString The stringified date.
8
+ * Gets a human readable and locale supported representation of a person's age, given their birthDate,
9
+ * The representation logic follows the guideline here:
10
+ * https://webarchive.nationalarchives.gov.uk/ukgwa/20160921162509mp_/http://systems.digital.nhs.uk/data/cui/uig/patben.pdf
11
+ * (See Tables 7 and 8)
12
+ *
13
+ * @param birthDate The birthDate.
14
+ * @param currentDate Optional. If provided, calculates the age of the person at the provided currentDate (instead of now).
34
15
  * @returns A human-readable string version of the age.
35
16
  */
36
- export function age(dateString: string): string {
37
- // Different from npm packages such as https://www.npmjs.com/package/timeago
17
+ export function age(birthDate: dayjs.ConfigType, currentDate: dayjs.ConfigType = dayjs()): string {
18
+ const to = dayjs(currentDate);
19
+ const from = dayjs(birthDate);
38
20
 
39
- // First calculate the age in years
40
- const today = new Date();
41
- const birthDate = new Date(dateString);
42
- const monthDifference = today.getUTCMonth() - birthDate.getUTCMonth();
43
- const dateDifference = today.getUTCDate() - birthDate.getUTCDate();
44
- let age = today.getUTCFullYear() - birthDate.getUTCFullYear();
45
- if (monthDifference < 0 || (monthDifference === 0 && dateDifference < 0)) {
46
- age--;
47
- }
48
-
49
- // Now calculate the number of months in addition to the year's age
50
- let monthsAgo = monthDifference >= 0 ? monthDifference : monthDifference + 12;
51
- if (dateDifference < 0) {
52
- monthsAgo--;
53
- }
21
+ const hourDiff = to.diff(from, 'hours');
22
+ const dayDiff = to.diff(from, 'days');
23
+ const weekDiff = to.diff(from, 'weeks');
24
+ const monthDiff = to.diff(from, 'months');
25
+ const yearDiff = to.diff(from, 'years');
54
26
 
55
- // For patients less than a year old, we calculate the number of days/weeks they have been alive
56
- let totalDaysAgo = daysIntoYear(today) - daysIntoYear(birthDate);
57
- if (totalDaysAgo < 0) {
58
- totalDaysAgo += 365;
59
- }
60
- const weeksAgo = Math.floor(totalDaysAgo / 7);
27
+ const duration: DurationInput = {};
61
28
 
62
29
  const locale = getLocale();
63
30
 
64
- // Depending on their age, return a different representation of their age.
65
- if (age === 0) {
66
- if (isSameDay(today, birthDate)) {
67
- const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' });
68
- return rtf.format(0, 'day');
69
- } else if (totalDaysAgo < 31) {
70
- const totalDaysAgoStr = new Intl.NumberFormat(locale, {
71
- style: 'unit',
72
- unit: 'day',
73
- unitDisplay: 'short',
74
- }).format(totalDaysAgo);
75
-
76
- return totalDaysAgoStr;
77
- } else {
78
- const weeksAgoStr = new Intl.NumberFormat(locale, {
79
- style: 'unit',
80
- unit: 'week',
81
- unitDisplay: 'short',
82
- }).format(weeksAgo);
83
- return weeksAgoStr;
84
- }
85
- } else if (age < 2) {
86
- const monthsAgoStr = new Intl.NumberFormat(locale, {
87
- style: 'unit',
88
- unit: 'month',
89
- unitDisplay: 'short',
90
- }).format(monthsAgo + 12);
91
-
92
- return monthsAgoStr;
31
+ if (hourDiff < 2) {
32
+ const minuteDiff = to.diff(from, 'minutes');
33
+ duration['minutes'] = minuteDiff;
34
+ } else if (dayDiff < 2) {
35
+ duration['hours'] = hourDiff;
36
+ } else if (weekDiff < 4) {
37
+ duration['days'] = dayDiff;
38
+ } else if (yearDiff < 1) {
39
+ const remainderDayDiff = to.subtract(weekDiff, 'weeks').diff(from, 'days');
40
+ duration['weeks'] = weekDiff;
41
+ duration['days'] = remainderDayDiff;
42
+ } else if (yearDiff < 2) {
43
+ const remainderDayDiff = to.subtract(monthDiff, 'months').diff(from, 'days');
44
+ duration['months'] = monthDiff;
45
+ duration['days'] = remainderDayDiff;
46
+ } else if (yearDiff < 18) {
47
+ const remainderMonthDiff = to.subtract(yearDiff, 'year').diff(from, 'months');
48
+ duration['years'] = yearDiff;
49
+ duration['months'] = remainderMonthDiff;
93
50
  } else {
94
- const yearsAgoStr = new Intl.NumberFormat(locale, {
95
- style: 'unit',
96
- unit: 'year',
97
- unitDisplay: 'short',
98
- }).format(age);
99
- return yearsAgoStr;
51
+ duration['years'] = yearDiff;
100
52
  }
53
+
54
+ return new DurationFormat(locale, { style: 'short' }).format(duration);
101
55
  }