@openmrs/esm-utils 3.1.15-pre.718 → 3.1.15-pre.730
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/dist/openmrs-esm-utils.js +1 -1
- package/dist/openmrs-esm-utils.js.map +1 -1
- package/package.json +3 -2
- package/src/omrs-dates.test.ts +62 -0
- package/src/omrs-dates.ts +119 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openmrs/esm-utils",
|
|
3
|
-
"version": "3.1.15-pre.
|
|
3
|
+
"version": "3.1.15-pre.730",
|
|
4
4
|
"license": "MPL-2.0",
|
|
5
5
|
"description": "Helper utilities for OpenMRS",
|
|
6
6
|
"browser": "dist/openmrs-esm-utils.js",
|
|
@@ -43,10 +43,11 @@
|
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"dayjs": "1.x",
|
|
46
|
+
"i18next": "19.x",
|
|
46
47
|
"rxjs": "6.x"
|
|
47
48
|
},
|
|
48
49
|
"dependencies": {
|
|
49
50
|
"semver": "^7.3.2"
|
|
50
51
|
},
|
|
51
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "e054367bca570e181a4cf718ffc6aba16a9adaf7"
|
|
52
53
|
}
|
package/src/omrs-dates.test.ts
CHANGED
|
@@ -4,6 +4,11 @@ import {
|
|
|
4
4
|
isOmrsDateStrict,
|
|
5
5
|
} from "./omrs-dates";
|
|
6
6
|
import dayjs from "dayjs";
|
|
7
|
+
import timezoneMock from "timezone-mock";
|
|
8
|
+
import { formatDate, formatDatetime, formatTime } from ".";
|
|
9
|
+
import { i18n } from "i18next";
|
|
10
|
+
|
|
11
|
+
window.i18next = { language: "en" } as i18n;
|
|
7
12
|
|
|
8
13
|
describe("Openmrs Dates", () => {
|
|
9
14
|
it("converts js Date object to omrs date string version", () => {
|
|
@@ -41,4 +46,61 @@ describe("Openmrs Dates", () => {
|
|
|
41
46
|
).toDate();
|
|
42
47
|
expect(toOmrsIsoString(date, true)).toEqual("2018-03-18T21:05:03.999+0000");
|
|
43
48
|
});
|
|
49
|
+
|
|
50
|
+
it("formats 'Today' with respect to the locale", () => {
|
|
51
|
+
const testDate = new Date();
|
|
52
|
+
window.i18next.language = "en";
|
|
53
|
+
expect(formatDate(testDate)).toEqual("Today");
|
|
54
|
+
expect(formatDate(testDate, "no day")).toEqual("Today");
|
|
55
|
+
expect(formatDate(testDate, "no year")).toEqual("Today");
|
|
56
|
+
expect(formatDate(testDate, "wide")).toEqual("Today");
|
|
57
|
+
window.i18next.language = "sw";
|
|
58
|
+
expect(formatDate(testDate)).toEqual("Leo");
|
|
59
|
+
window.i18next.language = "ru";
|
|
60
|
+
expect(formatDate(testDate)).toEqual("Сегодня");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("formats dates with respect to the locale", () => {
|
|
64
|
+
timezoneMock.register("UTC");
|
|
65
|
+
const testDate = new Date("2021-12-09");
|
|
66
|
+
window.i18next.language = "en";
|
|
67
|
+
expect(formatDate(testDate)).toEqual("09-Dec-2021");
|
|
68
|
+
expect(formatDate(testDate, "no day")).toEqual("Dec 2021");
|
|
69
|
+
expect(formatDate(testDate, "no year")).toEqual("09 Dec");
|
|
70
|
+
expect(formatDate(testDate, "wide")).toEqual("09 — Dec — 2021");
|
|
71
|
+
window.i18next.language = "fr";
|
|
72
|
+
expect(formatDate(testDate)).toEqual("09 déc. 2021");
|
|
73
|
+
expect(formatDate(testDate, "no day")).toEqual("déc. 2021");
|
|
74
|
+
expect(formatDate(testDate, "no year")).toEqual("09 déc.");
|
|
75
|
+
expect(formatDate(testDate, "wide")).toEqual("09 — déc. — 2021");
|
|
76
|
+
window.i18next.language = "sw";
|
|
77
|
+
expect(formatDate(testDate)).toEqual("09 Des 2021");
|
|
78
|
+
window.i18next.language = "ru";
|
|
79
|
+
expect(formatDate(testDate, "wide")).toEqual("09 — дек. — 2021 г.");
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("formats times with respect to the locale", () => {
|
|
83
|
+
timezoneMock.register("Australia/Adelaide");
|
|
84
|
+
const testDate = new Date("2021-12-09T13:15:33");
|
|
85
|
+
window.i18next.language = "en";
|
|
86
|
+
expect(formatTime(testDate)).toEqual("01:15 PM");
|
|
87
|
+
window.i18next.language = "es-CO";
|
|
88
|
+
expect(formatTime(testDate)).toMatch(/1:15 p.\sm./); // it's not a normal space between the 'p.' and 'm.'
|
|
89
|
+
window.i18next.language = "es-MX";
|
|
90
|
+
expect(formatTime(testDate)).toEqual("13:15");
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("formats datetimes with respect to the locale", () => {
|
|
94
|
+
timezoneMock.register("US/Pacific");
|
|
95
|
+
const testDate = new Date("2022-02-09T13:15:33");
|
|
96
|
+
const todayDate = new Date();
|
|
97
|
+
todayDate.setHours(15);
|
|
98
|
+
todayDate.setMinutes(20);
|
|
99
|
+
window.i18next.language = "en";
|
|
100
|
+
expect(formatDatetime(testDate)).toEqual("09-Feb-2022, 01:15 PM");
|
|
101
|
+
expect(formatDatetime(todayDate)).toEqual("Today, 03:20 PM");
|
|
102
|
+
window.i18next.language = "ht";
|
|
103
|
+
expect(formatDatetime(testDate)).toEqual("09 févr. 2022, 13:15");
|
|
104
|
+
expect(formatDatetime(todayDate)).toEqual("Aujourd’hui, 15:20");
|
|
105
|
+
});
|
|
44
106
|
});
|
package/src/omrs-dates.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* @category Date and time
|
|
4
|
+
*/
|
|
5
|
+
import { i18n } from "i18next";
|
|
1
6
|
import dayjs from "dayjs";
|
|
2
7
|
import utc from "dayjs/plugin/utc";
|
|
3
8
|
import isToday from "dayjs/plugin/isToday";
|
|
@@ -5,6 +10,12 @@ import isToday from "dayjs/plugin/isToday";
|
|
|
5
10
|
dayjs.extend(utc);
|
|
6
11
|
dayjs.extend(isToday);
|
|
7
12
|
|
|
13
|
+
declare global {
|
|
14
|
+
interface Window {
|
|
15
|
+
i18next: i18n;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
8
19
|
export type DateInput = string | number | Date;
|
|
9
20
|
|
|
10
21
|
const isoFormat = "YYYY-MM-DDTHH:mm:ss.SSSZZ";
|
|
@@ -79,6 +90,7 @@ export function toOmrsIsoString(date: DateInput, toUTC = false): string {
|
|
|
79
90
|
}
|
|
80
91
|
|
|
81
92
|
/**
|
|
93
|
+
* @deprecated use `formatTime`
|
|
82
94
|
* Formats the input as a time string using the format "HH:mm".
|
|
83
95
|
*/
|
|
84
96
|
export function toOmrsTimeString24(date: DateInput) {
|
|
@@ -86,6 +98,7 @@ export function toOmrsTimeString24(date: DateInput) {
|
|
|
86
98
|
}
|
|
87
99
|
|
|
88
100
|
/**
|
|
101
|
+
* @deprecated use `formatTime`
|
|
89
102
|
* Formats the input as a time string using the format "HH:mm A".
|
|
90
103
|
*/
|
|
91
104
|
export function toOmrsTimeString(date: DateInput) {
|
|
@@ -93,6 +106,7 @@ export function toOmrsTimeString(date: DateInput) {
|
|
|
93
106
|
}
|
|
94
107
|
|
|
95
108
|
/**
|
|
109
|
+
* @deprecated use `formatDate(date, "wide")`
|
|
96
110
|
* Formats the input as a date string using the format "DD - MMM - YYYY".
|
|
97
111
|
*/
|
|
98
112
|
export function toOmrsDayDateFormat(date: DateInput) {
|
|
@@ -100,6 +114,7 @@ export function toOmrsDayDateFormat(date: DateInput) {
|
|
|
100
114
|
}
|
|
101
115
|
|
|
102
116
|
/**
|
|
117
|
+
* @deprecated use `formatDate(date, "no year")`
|
|
103
118
|
* Formats the input as a date string using the format "DD-MMM".
|
|
104
119
|
*/
|
|
105
120
|
export function toOmrsYearlessDateFormat(date: DateInput) {
|
|
@@ -107,8 +122,112 @@ export function toOmrsYearlessDateFormat(date: DateInput) {
|
|
|
107
122
|
}
|
|
108
123
|
|
|
109
124
|
/**
|
|
125
|
+
* @deprecated use `formatDate(date)`
|
|
110
126
|
* Formats the input as a date string. By default the format "YYYY-MMM-DD" is used.
|
|
111
127
|
*/
|
|
112
128
|
export function toOmrsDateFormat(date: DateInput, format = "YYYY-MMM-DD") {
|
|
113
129
|
return dayjs(date).format(format);
|
|
114
130
|
}
|
|
131
|
+
|
|
132
|
+
const DATE_FORMAT_YYYY_MMM_DD = {
|
|
133
|
+
year: "numeric",
|
|
134
|
+
month: "short",
|
|
135
|
+
day: "2-digit",
|
|
136
|
+
};
|
|
137
|
+
const DATE_FORMAT_YYYY_MMM = {
|
|
138
|
+
year: "numeric",
|
|
139
|
+
month: "short",
|
|
140
|
+
};
|
|
141
|
+
const DATE_FORMAT_MMM_DD = {
|
|
142
|
+
month: "short",
|
|
143
|
+
day: "2-digit",
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export type FormatDateMode = "standard" | "no year" | "no day" | "wide";
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Formats the input date according to the current locale and the
|
|
150
|
+
* given format mode.
|
|
151
|
+
*
|
|
152
|
+
* `standard`: "13 Dec 2021"
|
|
153
|
+
* `no year`: "13 Dec"
|
|
154
|
+
* `no day`: "Dec 2021"
|
|
155
|
+
* `wide`: "13 — Dec — 2021"
|
|
156
|
+
*/
|
|
157
|
+
export function formatDate(date: Date, mode: FormatDateMode = "standard") {
|
|
158
|
+
const options = (
|
|
159
|
+
{
|
|
160
|
+
standard: DATE_FORMAT_YYYY_MMM_DD,
|
|
161
|
+
wide: DATE_FORMAT_YYYY_MMM_DD,
|
|
162
|
+
"no year": DATE_FORMAT_MMM_DD,
|
|
163
|
+
"no day": DATE_FORMAT_YYYY_MMM,
|
|
164
|
+
} as Record<string, Intl.DateTimeFormatOptions>
|
|
165
|
+
)[mode];
|
|
166
|
+
let locale = getLocale();
|
|
167
|
+
if (dayjs(date).isToday()) {
|
|
168
|
+
// This produces the word "Today" in the language of `locale`
|
|
169
|
+
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
|
|
170
|
+
let localeString = rtf.format(0, "day");
|
|
171
|
+
localeString =
|
|
172
|
+
localeString[0].toLocaleUpperCase(locale) + localeString.slice(1);
|
|
173
|
+
return localeString;
|
|
174
|
+
} else {
|
|
175
|
+
if (locale == "en") {
|
|
176
|
+
// This locale override is here rather than in `getLocale`
|
|
177
|
+
// because Americans should see AM/PM for times.
|
|
178
|
+
locale = "en-GB";
|
|
179
|
+
}
|
|
180
|
+
let localeString = date.toLocaleDateString(locale, options);
|
|
181
|
+
if (locale == "en-GB" && mode == "standard") {
|
|
182
|
+
// Custom formatting for English. Use hyphens instead of spaces.
|
|
183
|
+
localeString = localeString.replace(/ /g, "-");
|
|
184
|
+
}
|
|
185
|
+
if (mode == "wide") {
|
|
186
|
+
localeString = localeString.replace(/ /g, " — "); // space-emdash-space
|
|
187
|
+
if (/ru.*/.test(locale)) {
|
|
188
|
+
// Remove the extra em-dash that gets added between the year and the suffix 'r.'
|
|
189
|
+
const len = localeString.length;
|
|
190
|
+
localeString =
|
|
191
|
+
localeString.slice(0, len - 5) +
|
|
192
|
+
localeString.slice(len - 5).replace(" — ", " ");
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return localeString;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Formats the input as a time, according to the current locale.
|
|
201
|
+
* 12-hour or 24-hour clock depends on locale.
|
|
202
|
+
*/
|
|
203
|
+
export function formatTime(date: Date) {
|
|
204
|
+
return date.toLocaleTimeString(getLocale(), {
|
|
205
|
+
hour: "2-digit",
|
|
206
|
+
minute: "2-digit",
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Formats the input into a string showing the date and time, according
|
|
212
|
+
* to the current locale. The `mode` parameter is as described for
|
|
213
|
+
* `formatDate`.
|
|
214
|
+
*
|
|
215
|
+
* This is created by concatenating the results of `formatDate`
|
|
216
|
+
* and `formatTime` with a comma and space. This agrees with the
|
|
217
|
+
* output of `Date.prototype.toLocaleString` for *most* locales.
|
|
218
|
+
*/
|
|
219
|
+
export function formatDatetime(date: Date, mode: FormatDateMode = "standard") {
|
|
220
|
+
const dateString = formatDate(date, mode);
|
|
221
|
+
const timeString = formatTime(date);
|
|
222
|
+
return `${dateString}, ${timeString}`;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function getLocale() {
|
|
226
|
+
let language = window.i18next.language;
|
|
227
|
+
language = language.replace("_", "-"); // just in case
|
|
228
|
+
// hack for `ht` until https://unicode-org.atlassian.net/browse/CLDR-14956 is fixed
|
|
229
|
+
if (language === "ht") {
|
|
230
|
+
language = "fr-HT";
|
|
231
|
+
}
|
|
232
|
+
return language;
|
|
233
|
+
}
|