@dative-gpi/foundation-shared-services 0.0.142 → 0.0.144
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/composables/app/useAppTimeZone.ts +235 -227
- package/package.json +3 -3
|
@@ -11,260 +11,268 @@ import { useAppLanguageCode } from "./useAppLanguageCode";
|
|
|
11
11
|
const timeZone = ref<TimeZoneInfos | null>(null);
|
|
12
12
|
|
|
13
13
|
export const useAppTimeZone = () => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
const setAppTimeZone = (payload: TimeZoneInfos) => {
|
|
15
|
+
timeZone.value = payload;
|
|
16
|
+
};
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
return hours ? offset : offset * 60 * 60 * 1000;
|
|
18
|
+
const getOffsetNumber = (offsetString: string, hours: boolean = false): number => {
|
|
19
|
+
let offset = 0;
|
|
20
|
+
switch (offsetString.toLowerCase().replaceAll(" ", "")) {
|
|
21
|
+
case "utc-11:00:00": offset = -11; break;
|
|
22
|
+
case "utc-10:00:00": offset = -10; break;
|
|
23
|
+
case "utc-09:00:00": offset = -9; break;
|
|
24
|
+
case "utc-08:00:00": offset = -8; break;
|
|
25
|
+
case "utc-07:00:00": offset = -7; break;
|
|
26
|
+
case "utc-06:00:00": offset = -6; break;
|
|
27
|
+
case "utc-05:00:00": offset = -5; break;
|
|
28
|
+
case "utc-04:00:00": offset = -4; break;
|
|
29
|
+
case "utc-03:00:00": offset = -3; break;
|
|
30
|
+
case "utc-02:00:00": offset = -2; break;
|
|
31
|
+
case "utc-01:00:00": offset = -1; break;
|
|
32
|
+
case "utc+01:00:00": offset = +1; break;
|
|
33
|
+
case "utc+02:00:00": offset = +2; break;
|
|
34
|
+
case "utc+03:00:00": offset = +3; break;
|
|
35
|
+
case "utc+04:00:00": offset = +4; break;
|
|
36
|
+
case "utc+05:00:00": offset = +5; break;
|
|
37
|
+
case "utc+06:00:00": offset = +6; break;
|
|
38
|
+
case "utc+07:00:00": offset = +7; break;
|
|
39
|
+
case "utc+08:00:00": offset = +8; break;
|
|
40
|
+
case "utc+09:00:00": offset = +9; break;
|
|
41
|
+
case "utc+10:00:00": offset = +10; break;
|
|
42
|
+
case "utc+11:00:00": offset = +11; break;
|
|
43
|
+
case "utc+12:00:00": offset = +12; break;
|
|
44
|
+
case "utc+13:00:00": offset = +13; break;
|
|
45
|
+
case "utc+14:00:00": offset = +14; break;
|
|
48
46
|
}
|
|
47
|
+
return hours ? offset : offset * 60 * 60 * 1000;
|
|
48
|
+
};
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
const userOffset = (): number => {
|
|
51
|
+
return getOffsetNumber(getUserOffset());
|
|
52
|
+
};
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
const machineOffset = (): number => {
|
|
55
|
+
return getOffsetNumber(getMachineOffset());
|
|
56
|
+
};
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
const getUserOffset = (): string => {
|
|
59
|
+
return timeZone?.value?.offset ?? "UTC +00:00:00";
|
|
60
|
+
};
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const getMachineOffset = (): string => {
|
|
74
|
-
const timeZoneName = Intl.DateTimeFormat("ia", {
|
|
75
|
-
timeZoneName: "short",
|
|
76
|
-
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
77
|
-
}).formatToParts().find((i) => i.type === "timeZoneName")?.value ?? "";
|
|
62
|
+
const getUserOffsetMillis = (): number => {
|
|
63
|
+
const offset = timeZone?.value?.offset.slice(3) ?? "";
|
|
64
|
+
const matchData = offset.match(/([+-])(\d+)(?::(\d+))?/);
|
|
65
|
+
if (matchData) {
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
67
|
+
const [_, sign, hour, minute] = matchData;
|
|
68
|
+
return parseInt(sign + "1") * ((hour ? parseInt(hour) : 0) * 60 + (minute ? parseInt(minute) : 0)) * 60 * 1000;
|
|
69
|
+
}
|
|
70
|
+
return 0;
|
|
71
|
+
};
|
|
78
72
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (matchData) {
|
|
85
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
86
|
-
const [_, sign, hour, minute] = matchData;
|
|
87
|
-
return `UTC ${sign}${hour.padStart(2, "0")}:${(minute ?? "").padStart(2, "0")}:00`;
|
|
88
|
-
}
|
|
89
|
-
return "UTC +00:00:00";
|
|
90
|
-
};
|
|
73
|
+
const getMachineOffset = (): string => {
|
|
74
|
+
const timeZoneName = Intl.DateTimeFormat("ia", {
|
|
75
|
+
timeZoneName: "short",
|
|
76
|
+
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
77
|
+
}).formatToParts().find((i) => i.type === "timeZoneName")?.value ?? "";
|
|
91
78
|
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
79
|
+
const offset = timeZoneName.slice(3);
|
|
80
|
+
if (!offset) {
|
|
81
|
+
return "UTC +00:00:00";
|
|
82
|
+
}
|
|
83
|
+
const matchData = offset.match(/([+-])(\d+)(?::(\d+))?/);
|
|
84
|
+
if (matchData) {
|
|
85
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
86
|
+
const [_, sign, hour, minute] = matchData;
|
|
87
|
+
return `UTC ${sign}${hour.padStart(2, "0")}:${(minute ?? "").padStart(2, "0")}:00`;
|
|
88
|
+
}
|
|
89
|
+
return "UTC +00:00:00";
|
|
90
|
+
};
|
|
97
91
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (matchData) {
|
|
104
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
105
|
-
const [_, sign, hour, minute] = matchData;
|
|
106
|
-
return parseInt(sign + "1") * ((hour ? parseInt(hour) : 0) * 60 + (minute ? parseInt(minute) : 0)) * 60 * 1000;
|
|
107
|
-
}
|
|
108
|
-
return 0;
|
|
109
|
-
};
|
|
92
|
+
const getMachineOffsetMillis = (): number => {
|
|
93
|
+
const timeZoneName = Intl.DateTimeFormat("ia", {
|
|
94
|
+
timeZoneName: "short",
|
|
95
|
+
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
96
|
+
}).formatToParts().find((i) => i.type === "timeZoneName")?.value ?? "";
|
|
110
97
|
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
98
|
+
const offset = timeZoneName.slice(3);
|
|
99
|
+
if (!offset) {
|
|
100
|
+
return 0;
|
|
101
|
+
}
|
|
102
|
+
const matchData = offset.match(/([+-])(\d+)(?::(\d+))?/);
|
|
103
|
+
if (matchData) {
|
|
104
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
105
|
+
const [_, sign, hour, minute] = matchData;
|
|
106
|
+
return parseInt(sign + "1") * ((hour ? parseInt(hour) : 0) * 60 + (minute ? parseInt(minute) : 0)) * 60 * 1000;
|
|
107
|
+
}
|
|
108
|
+
return 0;
|
|
109
|
+
};
|
|
118
110
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
111
|
+
const todayToEpoch = (resetHours: boolean): number => {
|
|
112
|
+
const today = new Date();
|
|
113
|
+
if (resetHours) {
|
|
114
|
+
today.setHours(0, 0, 0, 0);
|
|
115
|
+
}
|
|
116
|
+
return today.getTime() + getMachineOffsetMillis() - getUserOffsetMillis();
|
|
117
|
+
};
|
|
126
118
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
};
|
|
119
|
+
const pickerToEpoch = (value: Date | null | undefined): number => {
|
|
120
|
+
if (value != null) {
|
|
121
|
+
// FSCalendar is always in machine time zone, so we need to convert it to user time zone
|
|
122
|
+
return value.getTime() + getMachineOffsetMillis() - getUserOffsetMillis();
|
|
123
|
+
}
|
|
124
|
+
return 0;
|
|
125
|
+
};
|
|
135
126
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
127
|
+
const epochToPicker = (value: number | null | undefined): Date => {
|
|
128
|
+
const date = new Date(0);
|
|
129
|
+
if (value != null) {
|
|
130
|
+
// Epoch is always without time zone, so we need to convert it to user time zone
|
|
131
|
+
date.setUTCMilliseconds(value - getMachineOffsetMillis() + getUserOffsetMillis());
|
|
132
|
+
}
|
|
133
|
+
return date;
|
|
134
|
+
};
|
|
143
135
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
};
|
|
136
|
+
const epochToPickerHeader = (value: number): { d: number, m: number, y: number } => {
|
|
137
|
+
const date = new Date(0);
|
|
138
|
+
if (value != null) {
|
|
139
|
+
date.setUTCMilliseconds(value - getMachineOffsetMillis() + getUserOffsetMillis());
|
|
140
|
+
}
|
|
141
|
+
return { d: date.getDate(), m: date.getMonth(), y: date.getFullYear() };
|
|
142
|
+
};
|
|
152
143
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
144
|
+
const epochToLongDateFormat = (value: number | null | undefined): string => {
|
|
145
|
+
if (value == null || !isFinite(value)) {
|
|
146
|
+
return "";
|
|
147
|
+
}
|
|
148
|
+
const date = new Date(0);
|
|
149
|
+
date.setUTCMilliseconds(value - getMachineOffsetMillis() + getUserOffsetMillis());
|
|
150
|
+
return format(date, "EEEE dd LLLL yyyy", { locale: getLocale() });
|
|
151
|
+
};
|
|
161
152
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
return format(date, "MM/dd/yyyy", { locale: getLocale() });
|
|
171
|
-
}
|
|
172
|
-
default: {
|
|
173
|
-
return format(date, "dd/MM/yyyy", { locale: getLocale() });
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
};
|
|
153
|
+
const epochToLongTimeFormat = (value: number | null | undefined): string => {
|
|
154
|
+
if (value == null || !isFinite(value)) {
|
|
155
|
+
return "";
|
|
156
|
+
}
|
|
157
|
+
const date = new Date(0);
|
|
158
|
+
date.setUTCMilliseconds(value - getMachineOffsetMillis() + getUserOffsetMillis());
|
|
159
|
+
return format(date, overrideFormat(date, "EEEE dd LLLL yyyy HH:mm"), { locale: getLocale() })
|
|
160
|
+
};
|
|
177
161
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
162
|
+
const epochToShortDateFormat = (value: number | null | undefined): string => {
|
|
163
|
+
if (value == null || !isFinite(value)) {
|
|
164
|
+
return "";
|
|
165
|
+
}
|
|
166
|
+
const date = new Date(0);
|
|
167
|
+
date.setUTCMilliseconds(value - getMachineOffsetMillis() + getUserOffsetMillis());
|
|
168
|
+
switch (getLocale()) {
|
|
169
|
+
case enUS: {
|
|
170
|
+
return format(date, "MM/dd/yyyy", { locale: getLocale() });
|
|
171
|
+
}
|
|
172
|
+
default: {
|
|
173
|
+
return format(date, "dd/MM/yyyy", { locale: getLocale() });
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
};
|
|
193
177
|
|
|
194
|
-
|
|
195
|
-
|
|
178
|
+
const epochToShortTimeFormat = (value: number | null | undefined): string => {
|
|
179
|
+
if (value == null || !isFinite(value)) {
|
|
180
|
+
return "";
|
|
196
181
|
}
|
|
182
|
+
const date = new Date(0);
|
|
183
|
+
date.setUTCMilliseconds(value - getMachineOffsetMillis() + getUserOffsetMillis());
|
|
184
|
+
switch (getLocale()) {
|
|
185
|
+
case enUS: {
|
|
186
|
+
return format(date, "MM/dd/yyyy HH:mm", { locale: getLocale() });
|
|
187
|
+
}
|
|
188
|
+
default: {
|
|
189
|
+
return format(date, "dd/MM/yyyy HH:mm", { locale: getLocale() });
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const todayTimeFormat = (): string => {
|
|
195
|
+
return `'${useTranslationsProvider().$tr("ui.time-zone.today-at", "Today at").replace(/'/g, "''")}' HH:mm:ss`;
|
|
196
|
+
};
|
|
197
197
|
|
|
198
|
-
|
|
199
|
-
|
|
198
|
+
const yesterdayTimeFormat = (): string => {
|
|
199
|
+
return `'${useTranslationsProvider().$tr("ui.time-zone.yesterday-at", "Yesterday at").replace(/'/g, "''")}' HH:mm:ss`;
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const overrideFormat = (date: Date, askedFormat: string): string => {
|
|
203
|
+
const now = new Date();
|
|
204
|
+
if (date.toDateString() === now.toDateString()) {
|
|
205
|
+
return todayTimeFormat();
|
|
206
|
+
}
|
|
207
|
+
if (date.toDateString() === subDays(now, 1).toDateString()) {
|
|
208
|
+
return yesterdayTimeFormat();
|
|
200
209
|
}
|
|
210
|
+
return askedFormat;
|
|
211
|
+
};
|
|
201
212
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
return askedFormat;
|
|
213
|
+
const getLocale = (): Locale => {
|
|
214
|
+
switch (useAppLanguageCode().languageCode.value) {
|
|
215
|
+
case "fr-FR": return fr;
|
|
216
|
+
case "es-ES": return es;
|
|
217
|
+
case "it-IT": return it;
|
|
218
|
+
case "en-GB": return enGB;
|
|
219
|
+
case "de-DE": return de;
|
|
220
|
+
default: return enUS;
|
|
211
221
|
}
|
|
222
|
+
};
|
|
212
223
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
};
|
|
224
|
+
const parseForPicker = (value: string, dateFormat: string = isoTimeFormat()): number | null => {
|
|
225
|
+
let date = parse(value!, dateFormat, new Date());
|
|
226
|
+
date = addMilliseconds(date, userOffset());
|
|
227
|
+
if (!isFinite(date.getTime())) {
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
return date.getTime();
|
|
231
|
+
};
|
|
223
232
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
return date.getTime();
|
|
231
|
-
};
|
|
233
|
+
const formatCurrentForPicker = (daysOffset: number = -1): string => {
|
|
234
|
+
let date = new Date();
|
|
235
|
+
date.setSeconds(0, 0);
|
|
236
|
+
date = addMilliseconds(addDays(date, daysOffset), -machineOffset());
|
|
237
|
+
return format(date, isoTimeFormat());
|
|
238
|
+
};
|
|
232
239
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
240
|
+
const formatFromPicker = (date: number | null): string => {
|
|
241
|
+
if (date != null) {
|
|
242
|
+
const epoch = date - machineOffset() + (machineOffset() - userOffset());
|
|
243
|
+
return format(epoch, isoTimeFormat());
|
|
244
|
+
}
|
|
245
|
+
return "";
|
|
246
|
+
};
|
|
239
247
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
};
|
|
248
|
+
const formatEpochToVariable = (epoch: number | undefined): string => {
|
|
249
|
+
if (epoch == null || !isFinite(epoch)) {
|
|
250
|
+
return "";
|
|
251
|
+
}
|
|
252
|
+
return format(epoch - machineOffset(), isoTimeFormat());
|
|
253
|
+
};
|
|
247
254
|
|
|
248
|
-
|
|
255
|
+
const ready = computed(() => timeZone.value !== null);
|
|
249
256
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
257
|
+
return {
|
|
258
|
+
ready,
|
|
259
|
+
timeZone,
|
|
260
|
+
setAppTimeZone,
|
|
261
|
+
getUserOffset,
|
|
262
|
+
getMachineOffset,
|
|
263
|
+
getUserOffsetMillis,
|
|
264
|
+
getMachineOffsetMillis,
|
|
265
|
+
todayToEpoch,
|
|
266
|
+
pickerToEpoch,
|
|
267
|
+
epochToPicker,
|
|
268
|
+
epochToPickerHeader,
|
|
269
|
+
epochToLongDateFormat,
|
|
270
|
+
epochToLongTimeFormat,
|
|
271
|
+
epochToShortDateFormat,
|
|
272
|
+
epochToShortTimeFormat,
|
|
273
|
+
parseForPicker,
|
|
274
|
+
formatCurrentForPicker,
|
|
275
|
+
formatFromPicker,
|
|
276
|
+
formatEpochToVariable
|
|
277
|
+
};
|
|
270
278
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dative-gpi/foundation-shared-services",
|
|
3
3
|
"sideEffects": false,
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.144",
|
|
5
5
|
"description": "",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
"license": "ISC",
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@dative-gpi/bones-ui": "^0.0.74",
|
|
14
|
-
"@dative-gpi/foundation-shared-domain": "0.0.
|
|
14
|
+
"@dative-gpi/foundation-shared-domain": "0.0.144",
|
|
15
15
|
"@microsoft/signalr": "^8.0.0",
|
|
16
16
|
"vue": "^3.4.23",
|
|
17
17
|
"vue-router": "^4.2.5"
|
|
18
18
|
},
|
|
19
|
-
"gitHead": "
|
|
19
|
+
"gitHead": "e894b5045c2f95bea5635cc4eb3c17dd0934ff2e"
|
|
20
20
|
}
|