@stridge/noctis-intl 1.0.0-beta.0
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/LICENSE +201 -0
- package/README.md +41 -0
- package/dist/date/CalendarDate.d.ts +211 -0
- package/dist/date/CalendarDate.js +340 -0
- package/dist/date/DateFormatter.d.ts +26 -0
- package/dist/date/DateFormatter.js +114 -0
- package/dist/date/calendars/BuddhistCalendar.d.ts +20 -0
- package/dist/date/calendars/BuddhistCalendar.js +33 -0
- package/dist/date/calendars/EthiopicCalendar.d.ts +49 -0
- package/dist/date/calendars/EthiopicCalendar.js +129 -0
- package/dist/date/calendars/GregorianCalendar.d.ts +26 -0
- package/dist/date/calendars/GregorianCalendar.js +117 -0
- package/dist/date/calendars/HebrewCalendar.d.ts +25 -0
- package/dist/date/calendars/HebrewCalendar.js +114 -0
- package/dist/date/calendars/IndianCalendar.d.ts +21 -0
- package/dist/date/calendars/IndianCalendar.js +75 -0
- package/dist/date/calendars/IslamicCalendar.d.ts +55 -0
- package/dist/date/calendars/IslamicCalendar.js +162 -0
- package/dist/date/calendars/JapaneseCalendar.d.ts +26 -0
- package/dist/date/calendars/JapaneseCalendar.js +154 -0
- package/dist/date/calendars/PersianCalendar.d.ts +23 -0
- package/dist/date/calendars/PersianCalendar.js +63 -0
- package/dist/date/calendars/TaiwanCalendar.d.ts +23 -0
- package/dist/date/calendars/TaiwanCalendar.js +51 -0
- package/dist/date/conversion.d.ts +41 -0
- package/dist/date/conversion.js +181 -0
- package/dist/date/createCalendar.d.ts +7 -0
- package/dist/date/createCalendar.js +30 -0
- package/dist/date/manipulation.js +274 -0
- package/dist/date/queries.d.ts +92 -0
- package/dist/date/queries.js +233 -0
- package/dist/date/string.d.ts +36 -0
- package/dist/date/string.js +162 -0
- package/dist/date/types.d.ts +138 -0
- package/dist/date/utils.d.ts +4 -0
- package/dist/date/utils.js +6 -0
- package/dist/date/weekStartData.js +100 -0
- package/dist/date.d.ts +17 -0
- package/dist/date.js +16 -0
- package/dist/i18n/context.d.ts +17 -0
- package/dist/i18n/context.js +13 -0
- package/dist/i18n/use-collator.d.ts +8 -0
- package/dist/i18n/use-collator.js +19 -0
- package/dist/i18n/use-date-formatter.d.ts +14 -0
- package/dist/i18n/use-date-formatter.js +25 -0
- package/dist/i18n/use-deep-memo.d.ts +8 -0
- package/dist/i18n/use-deep-memo.js +15 -0
- package/dist/i18n/use-filter.d.ts +17 -0
- package/dist/i18n/use-filter.js +49 -0
- package/dist/i18n/use-list-formatter.d.ts +5 -0
- package/dist/i18n/use-list-formatter.js +11 -0
- package/dist/i18n/use-locale.d.ts +7 -0
- package/dist/i18n/use-locale.js +13 -0
- package/dist/i18n/use-localized-string-formatter.d.ts +13 -0
- package/dist/i18n/use-localized-string-formatter.js +30 -0
- package/dist/i18n/use-number-formatter.d.ts +14 -0
- package/dist/i18n/use-number-formatter.js +15 -0
- package/dist/i18n/utils.d.ts +15 -0
- package/dist/i18n/utils.js +50 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +21 -0
- package/dist/messages/en.d.ts +6 -0
- package/dist/messages/en.js +68 -0
- package/dist/messages/fa.d.ts +6 -0
- package/dist/messages/fa.js +68 -0
- package/dist/number/NumberFormatter.d.ts +32 -0
- package/dist/number/NumberFormatter.js +135 -0
- package/dist/number/NumberParser.d.ts +30 -0
- package/dist/number/NumberParser.js +234 -0
- package/dist/number.d.ts +3 -0
- package/dist/number.js +3 -0
- package/dist/react.d.ts +17 -0
- package/dist/react.js +17 -0
- package/dist/ssr/use-is-ssr.d.ts +8 -0
- package/dist/ssr/use-is-ssr.js +15 -0
- package/dist/string/LocalizedStringDictionary.d.ts +22 -0
- package/dist/string/LocalizedStringDictionary.js +58 -0
- package/dist/string/LocalizedStringFormatter.d.ts +22 -0
- package/dist/string/LocalizedStringFormatter.js +46 -0
- package/dist/string.d.ts +3 -0
- package/dist/string.js +3 -0
- package/package.json +80 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { GregorianCalendar, getExtendedYear } from "./calendars/GregorianCalendar.js";
|
|
2
|
+
import { constrain } from "./manipulation.js";
|
|
3
|
+
import { getLocalTimeZone, isEqualCalendar, isLocalTimeZoneOverridden } from "./queries.js";
|
|
4
|
+
import { CalendarDate, CalendarDateTime, Time, ZonedDateTime } from "./CalendarDate.js";
|
|
5
|
+
//#region src/date/conversion.ts
|
|
6
|
+
function epochFromDate(date) {
|
|
7
|
+
date = toCalendar(date, new GregorianCalendar());
|
|
8
|
+
return epochFromParts(getExtendedYear(date.era, date.year), date.month, date.day, date.hour, date.minute, date.second, date.millisecond);
|
|
9
|
+
}
|
|
10
|
+
function epochFromParts(year, month, day, hour, minute, second, millisecond) {
|
|
11
|
+
let date = /* @__PURE__ */ new Date();
|
|
12
|
+
date.setUTCHours(hour, minute, second, millisecond);
|
|
13
|
+
date.setUTCFullYear(year, month - 1, day);
|
|
14
|
+
return date.getTime();
|
|
15
|
+
}
|
|
16
|
+
function getTimeZoneOffset(ms, timeZone) {
|
|
17
|
+
if (timeZone === "UTC") return 0;
|
|
18
|
+
if (ms > 0 && timeZone === getLocalTimeZone() && !isLocalTimeZoneOverridden()) return new Date(ms).getTimezoneOffset() * -60 * 1e3;
|
|
19
|
+
let { year, month, day, hour, minute, second } = getTimeZoneParts(ms, timeZone);
|
|
20
|
+
return epochFromParts(year, month, day, hour, minute, second, 0) - Math.floor(ms / 1e3) * 1e3;
|
|
21
|
+
}
|
|
22
|
+
const formattersByTimeZone = /* @__PURE__ */ new Map();
|
|
23
|
+
function getTimeZoneParts(ms, timeZone) {
|
|
24
|
+
let formatter = formattersByTimeZone.get(timeZone);
|
|
25
|
+
if (!formatter) {
|
|
26
|
+
formatter = new Intl.DateTimeFormat("en-US", {
|
|
27
|
+
timeZone,
|
|
28
|
+
hour12: false,
|
|
29
|
+
era: "short",
|
|
30
|
+
year: "numeric",
|
|
31
|
+
month: "numeric",
|
|
32
|
+
day: "numeric",
|
|
33
|
+
hour: "numeric",
|
|
34
|
+
minute: "numeric",
|
|
35
|
+
second: "numeric"
|
|
36
|
+
});
|
|
37
|
+
formattersByTimeZone.set(timeZone, formatter);
|
|
38
|
+
}
|
|
39
|
+
let parts = formatter.formatToParts(new Date(ms));
|
|
40
|
+
let namedParts = {};
|
|
41
|
+
for (let part of parts) if (part.type !== "literal") namedParts[part.type] = part.value;
|
|
42
|
+
return {
|
|
43
|
+
year: namedParts.era === "BC" || namedParts.era === "B" ? -namedParts.year + 1 : +namedParts.year,
|
|
44
|
+
month: +namedParts.month,
|
|
45
|
+
day: +namedParts.day,
|
|
46
|
+
hour: namedParts.hour === "24" ? 0 : +namedParts.hour,
|
|
47
|
+
minute: +namedParts.minute,
|
|
48
|
+
second: +namedParts.second
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const DAYMILLIS = 864e5;
|
|
52
|
+
function possibleAbsolutes(date, timeZone) {
|
|
53
|
+
let ms = epochFromDate(date);
|
|
54
|
+
return getValidWallTimes(date, timeZone, ms - getTimeZoneOffset(ms - DAYMILLIS, timeZone), ms - getTimeZoneOffset(ms + DAYMILLIS, timeZone));
|
|
55
|
+
}
|
|
56
|
+
function getValidWallTimes(date, timeZone, earlier, later) {
|
|
57
|
+
return (earlier === later ? [earlier] : [earlier, later]).filter((absolute) => isValidWallTime(date, timeZone, absolute));
|
|
58
|
+
}
|
|
59
|
+
function isValidWallTime(date, timeZone, absolute) {
|
|
60
|
+
let parts = getTimeZoneParts(absolute, timeZone);
|
|
61
|
+
return date.year === parts.year && date.month === parts.month && date.day === parts.day && date.hour === parts.hour && date.minute === parts.minute && date.second === parts.second;
|
|
62
|
+
}
|
|
63
|
+
function toAbsolute(date, timeZone, disambiguation = "compatible") {
|
|
64
|
+
let dateTime = toCalendarDateTime(date);
|
|
65
|
+
if (timeZone === "UTC") return epochFromDate(dateTime);
|
|
66
|
+
if (timeZone === getLocalTimeZone() && disambiguation === "compatible" && !isLocalTimeZoneOverridden()) {
|
|
67
|
+
dateTime = toCalendar(dateTime, new GregorianCalendar());
|
|
68
|
+
let date = /* @__PURE__ */ new Date();
|
|
69
|
+
let year = getExtendedYear(dateTime.era, dateTime.year);
|
|
70
|
+
date.setFullYear(year, dateTime.month - 1, dateTime.day);
|
|
71
|
+
date.setHours(dateTime.hour, dateTime.minute, dateTime.second, dateTime.millisecond);
|
|
72
|
+
return date.getTime();
|
|
73
|
+
}
|
|
74
|
+
let ms = epochFromDate(dateTime);
|
|
75
|
+
let offsetBefore = getTimeZoneOffset(ms - DAYMILLIS, timeZone);
|
|
76
|
+
let offsetAfter = getTimeZoneOffset(ms + DAYMILLIS, timeZone);
|
|
77
|
+
let valid = getValidWallTimes(dateTime, timeZone, ms - offsetBefore, ms - offsetAfter);
|
|
78
|
+
if (valid.length === 1) return valid[0];
|
|
79
|
+
if (valid.length > 1) switch (disambiguation) {
|
|
80
|
+
case "compatible":
|
|
81
|
+
case "earlier": return valid[0];
|
|
82
|
+
case "later": return valid[valid.length - 1];
|
|
83
|
+
case "reject": throw new RangeError("Multiple possible absolute times found");
|
|
84
|
+
}
|
|
85
|
+
switch (disambiguation) {
|
|
86
|
+
case "earlier": return Math.min(ms - offsetBefore, ms - offsetAfter);
|
|
87
|
+
case "compatible":
|
|
88
|
+
case "later": return Math.max(ms - offsetBefore, ms - offsetAfter);
|
|
89
|
+
case "reject": throw new RangeError("No such absolute time found");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function toDate(dateTime, timeZone, disambiguation = "compatible") {
|
|
93
|
+
return new Date(toAbsolute(dateTime, timeZone, disambiguation));
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Takes a Unix epoch (milliseconds since 1970) and converts it to the provided time zone.
|
|
97
|
+
*/
|
|
98
|
+
function fromAbsolute(ms, timeZone) {
|
|
99
|
+
let offset = getTimeZoneOffset(ms, timeZone);
|
|
100
|
+
let date = new Date(ms + offset);
|
|
101
|
+
let year = date.getUTCFullYear();
|
|
102
|
+
let month = date.getUTCMonth() + 1;
|
|
103
|
+
let day = date.getUTCDate();
|
|
104
|
+
let hour = date.getUTCHours();
|
|
105
|
+
let minute = date.getUTCMinutes();
|
|
106
|
+
let second = date.getUTCSeconds();
|
|
107
|
+
let millisecond = date.getUTCMilliseconds();
|
|
108
|
+
return new ZonedDateTime(year < 1 ? "BC" : "AD", year < 1 ? -year + 1 : year, month, day, timeZone, offset, hour, minute, second, millisecond);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Takes a `Date` object and converts it to the provided time zone.
|
|
112
|
+
*/
|
|
113
|
+
function fromDate(date, timeZone) {
|
|
114
|
+
return fromAbsolute(date.getTime(), timeZone);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Takes a `Date` object and converts it to the time zone identifier for the current user.
|
|
118
|
+
*/
|
|
119
|
+
function fromDateToLocal(date) {
|
|
120
|
+
return fromDate(date, getLocalTimeZone());
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Converts a value with date components such as a `CalendarDateTime` or `ZonedDateTime` into a
|
|
124
|
+
* `CalendarDate`.
|
|
125
|
+
*/
|
|
126
|
+
function toCalendarDate(dateTime) {
|
|
127
|
+
return new CalendarDate(dateTime.calendar, dateTime.era, dateTime.year, dateTime.month, dateTime.day);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Converts a date value to a `CalendarDateTime`. An optional `Time` value can be passed to set the
|
|
131
|
+
* time of the resulting value, otherwise it will default to midnight.
|
|
132
|
+
*/
|
|
133
|
+
function toCalendarDateTime(date, time) {
|
|
134
|
+
let hour = 0, minute = 0, second = 0, millisecond = 0;
|
|
135
|
+
if ("timeZone" in date) ({hour, minute, second, millisecond} = date);
|
|
136
|
+
else if ("hour" in date && !time) return date;
|
|
137
|
+
if (time) ({hour, minute, second, millisecond} = time);
|
|
138
|
+
return new CalendarDateTime(date.calendar, date.era, date.year, date.month, date.day, hour, minute, second, millisecond);
|
|
139
|
+
}
|
|
140
|
+
/** Extracts the time components from a value containing a date and time. */
|
|
141
|
+
function toTime(dateTime) {
|
|
142
|
+
return new Time(dateTime.hour, dateTime.minute, dateTime.second, dateTime.millisecond);
|
|
143
|
+
}
|
|
144
|
+
/** Converts a date from one calendar system to another. */
|
|
145
|
+
function toCalendar(date, calendar) {
|
|
146
|
+
if (isEqualCalendar(date.calendar, calendar)) return date;
|
|
147
|
+
let calendarDate = calendar.fromJulianDay(date.calendar.toJulianDay(date));
|
|
148
|
+
let copy = date.copy();
|
|
149
|
+
copy.calendar = calendar;
|
|
150
|
+
copy.era = calendarDate.era;
|
|
151
|
+
copy.year = calendarDate.year;
|
|
152
|
+
copy.month = calendarDate.month;
|
|
153
|
+
copy.day = calendarDate.day;
|
|
154
|
+
constrain(copy);
|
|
155
|
+
return copy;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Converts a date value to a `ZonedDateTime` in the provided time zone. The `disambiguation` option
|
|
159
|
+
* can be set to control how values that fall on daylight saving time changes are interpreted.
|
|
160
|
+
*/
|
|
161
|
+
function toZoned(date, timeZone, disambiguation) {
|
|
162
|
+
if (date instanceof ZonedDateTime) {
|
|
163
|
+
if (date.timeZone === timeZone) return date;
|
|
164
|
+
return toTimeZone(date, timeZone);
|
|
165
|
+
}
|
|
166
|
+
return fromAbsolute(toAbsolute(date, timeZone, disambiguation), timeZone);
|
|
167
|
+
}
|
|
168
|
+
function zonedToDate(date) {
|
|
169
|
+
let ms = epochFromDate(date) - date.offset;
|
|
170
|
+
return new Date(ms);
|
|
171
|
+
}
|
|
172
|
+
/** Converts a `ZonedDateTime` from one time zone to another. */
|
|
173
|
+
function toTimeZone(date, timeZone) {
|
|
174
|
+
return toCalendar(fromAbsolute(epochFromDate(date) - date.offset, timeZone), date.calendar);
|
|
175
|
+
}
|
|
176
|
+
/** Converts the given `ZonedDateTime` into the user's local time zone. */
|
|
177
|
+
function toLocalTimeZone(date) {
|
|
178
|
+
return toTimeZone(date, getLocalTimeZone());
|
|
179
|
+
}
|
|
180
|
+
//#endregion
|
|
181
|
+
export { epochFromDate, fromAbsolute, fromDate, fromDateToLocal, possibleAbsolutes, toAbsolute, toCalendar, toCalendarDate, toCalendarDateTime, toDate, toLocalTimeZone, toTime, toTimeZone, toZoned, zonedToDate };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Calendar, CalendarIdentifier } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/date/createCalendar.d.ts
|
|
4
|
+
/** Creates a `Calendar` instance from a Unicode calendar identifier string. */
|
|
5
|
+
declare function createCalendar(name: CalendarIdentifier): Calendar;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { createCalendar };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { GregorianCalendar } from "./calendars/GregorianCalendar.js";
|
|
2
|
+
import { JapaneseCalendar } from "./calendars/JapaneseCalendar.js";
|
|
3
|
+
import { BuddhistCalendar } from "./calendars/BuddhistCalendar.js";
|
|
4
|
+
import { TaiwanCalendar } from "./calendars/TaiwanCalendar.js";
|
|
5
|
+
import { PersianCalendar } from "./calendars/PersianCalendar.js";
|
|
6
|
+
import { IndianCalendar } from "./calendars/IndianCalendar.js";
|
|
7
|
+
import { IslamicCivilCalendar, IslamicTabularCalendar, IslamicUmalquraCalendar } from "./calendars/IslamicCalendar.js";
|
|
8
|
+
import { HebrewCalendar } from "./calendars/HebrewCalendar.js";
|
|
9
|
+
import { CopticCalendar, EthiopicAmeteAlemCalendar, EthiopicCalendar } from "./calendars/EthiopicCalendar.js";
|
|
10
|
+
//#region src/date/createCalendar.ts
|
|
11
|
+
/** Creates a `Calendar` instance from a Unicode calendar identifier string. */
|
|
12
|
+
function createCalendar(name) {
|
|
13
|
+
switch (name) {
|
|
14
|
+
case "buddhist": return new BuddhistCalendar();
|
|
15
|
+
case "ethiopic": return new EthiopicCalendar();
|
|
16
|
+
case "ethioaa": return new EthiopicAmeteAlemCalendar();
|
|
17
|
+
case "coptic": return new CopticCalendar();
|
|
18
|
+
case "hebrew": return new HebrewCalendar();
|
|
19
|
+
case "indian": return new IndianCalendar();
|
|
20
|
+
case "islamic-civil": return new IslamicCivilCalendar();
|
|
21
|
+
case "islamic-tbla": return new IslamicTabularCalendar();
|
|
22
|
+
case "islamic-umalqura": return new IslamicUmalquraCalendar();
|
|
23
|
+
case "japanese": return new JapaneseCalendar();
|
|
24
|
+
case "persian": return new PersianCalendar();
|
|
25
|
+
case "roc": return new TaiwanCalendar();
|
|
26
|
+
default: return new GregorianCalendar();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { createCalendar };
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { GregorianCalendar } from "./calendars/GregorianCalendar.js";
|
|
2
|
+
import { epochFromDate, fromAbsolute, toAbsolute, toCalendar, toCalendarDateTime } from "./conversion.js";
|
|
3
|
+
//#region src/date/manipulation.ts
|
|
4
|
+
const ONE_HOUR = 36e5;
|
|
5
|
+
function add(date, duration) {
|
|
6
|
+
let mutableDate = date.copy();
|
|
7
|
+
let days = "hour" in mutableDate ? addTimeFields(mutableDate, duration) : 0;
|
|
8
|
+
addYears(mutableDate, duration.years || 0);
|
|
9
|
+
if (mutableDate.calendar.balanceYearMonth) mutableDate.calendar.balanceYearMonth(mutableDate, date);
|
|
10
|
+
mutableDate.month += duration.months || 0;
|
|
11
|
+
balanceYearMonth(mutableDate);
|
|
12
|
+
constrainMonthDay(mutableDate);
|
|
13
|
+
mutableDate.day += (duration.weeks || 0) * 7;
|
|
14
|
+
mutableDate.day += duration.days || 0;
|
|
15
|
+
mutableDate.day += days;
|
|
16
|
+
balanceDay(mutableDate);
|
|
17
|
+
if (mutableDate.calendar.balanceDate) mutableDate.calendar.balanceDate(mutableDate);
|
|
18
|
+
if (mutableDate.year < 1) {
|
|
19
|
+
mutableDate.year = 1;
|
|
20
|
+
mutableDate.month = 1;
|
|
21
|
+
mutableDate.day = 1;
|
|
22
|
+
}
|
|
23
|
+
let maxYear = mutableDate.calendar.getYearsInEra(mutableDate);
|
|
24
|
+
if (mutableDate.year > maxYear) {
|
|
25
|
+
let isInverseEra = mutableDate.calendar.isInverseEra?.(mutableDate);
|
|
26
|
+
mutableDate.year = maxYear;
|
|
27
|
+
mutableDate.month = isInverseEra ? 1 : mutableDate.calendar.getMonthsInYear(mutableDate);
|
|
28
|
+
mutableDate.day = isInverseEra ? 1 : mutableDate.calendar.getDaysInMonth(mutableDate);
|
|
29
|
+
}
|
|
30
|
+
if (mutableDate.month < 1) {
|
|
31
|
+
mutableDate.month = 1;
|
|
32
|
+
mutableDate.day = 1;
|
|
33
|
+
}
|
|
34
|
+
let maxMonth = mutableDate.calendar.getMonthsInYear(mutableDate);
|
|
35
|
+
if (mutableDate.month > maxMonth) {
|
|
36
|
+
mutableDate.month = maxMonth;
|
|
37
|
+
mutableDate.day = mutableDate.calendar.getDaysInMonth(mutableDate);
|
|
38
|
+
}
|
|
39
|
+
mutableDate.day = Math.max(1, Math.min(mutableDate.calendar.getDaysInMonth(mutableDate), mutableDate.day));
|
|
40
|
+
return mutableDate;
|
|
41
|
+
}
|
|
42
|
+
function addYears(date, years) {
|
|
43
|
+
if (date.calendar.isInverseEra?.(date)) years = -years;
|
|
44
|
+
date.year += years;
|
|
45
|
+
}
|
|
46
|
+
function balanceYearMonth(date) {
|
|
47
|
+
while (date.month < 1) {
|
|
48
|
+
addYears(date, -1);
|
|
49
|
+
date.month += date.calendar.getMonthsInYear(date);
|
|
50
|
+
}
|
|
51
|
+
let monthsInYear = 0;
|
|
52
|
+
while (date.month > (monthsInYear = date.calendar.getMonthsInYear(date))) {
|
|
53
|
+
date.month -= monthsInYear;
|
|
54
|
+
addYears(date, 1);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function balanceDay(date) {
|
|
58
|
+
while (date.day < 1) {
|
|
59
|
+
date.month--;
|
|
60
|
+
balanceYearMonth(date);
|
|
61
|
+
date.day += date.calendar.getDaysInMonth(date);
|
|
62
|
+
}
|
|
63
|
+
while (date.day > date.calendar.getDaysInMonth(date)) {
|
|
64
|
+
date.day -= date.calendar.getDaysInMonth(date);
|
|
65
|
+
date.month++;
|
|
66
|
+
balanceYearMonth(date);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function constrainMonthDay(date) {
|
|
70
|
+
date.month = Math.max(1, Math.min(date.calendar.getMonthsInYear(date), date.month));
|
|
71
|
+
date.day = Math.max(1, Math.min(date.calendar.getDaysInMonth(date), date.day));
|
|
72
|
+
}
|
|
73
|
+
function constrain(date) {
|
|
74
|
+
if (date.calendar.constrainDate) date.calendar.constrainDate(date);
|
|
75
|
+
date.year = Math.max(1, Math.min(date.calendar.getYearsInEra(date), date.year));
|
|
76
|
+
constrainMonthDay(date);
|
|
77
|
+
}
|
|
78
|
+
function invertDuration(duration) {
|
|
79
|
+
let inverseDuration = {};
|
|
80
|
+
for (let key in duration) {
|
|
81
|
+
let k = key;
|
|
82
|
+
let value = duration[k];
|
|
83
|
+
if (typeof value === "number") inverseDuration[k] = -value;
|
|
84
|
+
}
|
|
85
|
+
return inverseDuration;
|
|
86
|
+
}
|
|
87
|
+
function subtract(date, duration) {
|
|
88
|
+
return add(date, invertDuration(duration));
|
|
89
|
+
}
|
|
90
|
+
function set(date, fields) {
|
|
91
|
+
let mutableDate = date.copy();
|
|
92
|
+
if (fields.era != null) mutableDate.era = fields.era;
|
|
93
|
+
if (fields.year != null) mutableDate.year = fields.year;
|
|
94
|
+
if (fields.month != null) mutableDate.month = fields.month;
|
|
95
|
+
if (fields.day != null) mutableDate.day = fields.day;
|
|
96
|
+
constrain(mutableDate);
|
|
97
|
+
return mutableDate;
|
|
98
|
+
}
|
|
99
|
+
function setTime(value, fields) {
|
|
100
|
+
let mutableValue = value.copy();
|
|
101
|
+
if (fields.hour != null) mutableValue.hour = fields.hour;
|
|
102
|
+
if (fields.minute != null) mutableValue.minute = fields.minute;
|
|
103
|
+
if (fields.second != null) mutableValue.second = fields.second;
|
|
104
|
+
if (fields.millisecond != null) mutableValue.millisecond = fields.millisecond;
|
|
105
|
+
constrainTime(mutableValue);
|
|
106
|
+
return mutableValue;
|
|
107
|
+
}
|
|
108
|
+
function balanceTime(time) {
|
|
109
|
+
time.second += Math.floor(time.millisecond / 1e3);
|
|
110
|
+
time.millisecond = nonNegativeMod(time.millisecond, 1e3);
|
|
111
|
+
time.minute += Math.floor(time.second / 60);
|
|
112
|
+
time.second = nonNegativeMod(time.second, 60);
|
|
113
|
+
time.hour += Math.floor(time.minute / 60);
|
|
114
|
+
time.minute = nonNegativeMod(time.minute, 60);
|
|
115
|
+
let days = Math.floor(time.hour / 24);
|
|
116
|
+
time.hour = nonNegativeMod(time.hour, 24);
|
|
117
|
+
return days;
|
|
118
|
+
}
|
|
119
|
+
function constrainTime(time) {
|
|
120
|
+
time.millisecond = Math.max(0, Math.min(time.millisecond, 1e3));
|
|
121
|
+
time.second = Math.max(0, Math.min(time.second, 59));
|
|
122
|
+
time.minute = Math.max(0, Math.min(time.minute, 59));
|
|
123
|
+
time.hour = Math.max(0, Math.min(time.hour, 23));
|
|
124
|
+
}
|
|
125
|
+
function nonNegativeMod(a, b) {
|
|
126
|
+
let result = a % b;
|
|
127
|
+
if (result < 0) result += b;
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
function addTimeFields(time, duration) {
|
|
131
|
+
time.hour += duration.hours || 0;
|
|
132
|
+
time.minute += duration.minutes || 0;
|
|
133
|
+
time.second += duration.seconds || 0;
|
|
134
|
+
time.millisecond += duration.milliseconds || 0;
|
|
135
|
+
return balanceTime(time);
|
|
136
|
+
}
|
|
137
|
+
function addTime(time, duration) {
|
|
138
|
+
let res = time.copy();
|
|
139
|
+
addTimeFields(res, duration);
|
|
140
|
+
return res;
|
|
141
|
+
}
|
|
142
|
+
function subtractTime(time, duration) {
|
|
143
|
+
return addTime(time, invertDuration(duration));
|
|
144
|
+
}
|
|
145
|
+
function cycleDate(value, field, amount, options) {
|
|
146
|
+
let mutable = value.copy();
|
|
147
|
+
switch (field) {
|
|
148
|
+
case "era": {
|
|
149
|
+
let eras = value.calendar.getEras();
|
|
150
|
+
let eraIndex = eras.indexOf(value.era);
|
|
151
|
+
if (eraIndex < 0) throw new Error("Invalid era: " + value.era);
|
|
152
|
+
eraIndex = cycleValue(eraIndex, amount, 0, eras.length - 1, options?.round);
|
|
153
|
+
mutable.era = eras[eraIndex];
|
|
154
|
+
constrain(mutable);
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
case "year":
|
|
158
|
+
if (mutable.calendar.isInverseEra?.(mutable)) amount = -amount;
|
|
159
|
+
mutable.year = cycleValue(value.year, amount, -Infinity, 9999, options?.round);
|
|
160
|
+
if (mutable.year === -Infinity) mutable.year = 1;
|
|
161
|
+
if (mutable.calendar.balanceYearMonth) mutable.calendar.balanceYearMonth(mutable, value);
|
|
162
|
+
break;
|
|
163
|
+
case "month":
|
|
164
|
+
mutable.month = cycleValue(value.month, amount, 1, value.calendar.getMonthsInYear(value), options?.round);
|
|
165
|
+
break;
|
|
166
|
+
case "day":
|
|
167
|
+
mutable.day = cycleValue(value.day, amount, 1, value.calendar.getDaysInMonth(value), options?.round);
|
|
168
|
+
break;
|
|
169
|
+
default: throw new Error("Unsupported field " + field);
|
|
170
|
+
}
|
|
171
|
+
if (value.calendar.balanceDate) value.calendar.balanceDate(mutable);
|
|
172
|
+
constrain(mutable);
|
|
173
|
+
return mutable;
|
|
174
|
+
}
|
|
175
|
+
function cycleTime(value, field, amount, options) {
|
|
176
|
+
let mutable = value.copy();
|
|
177
|
+
switch (field) {
|
|
178
|
+
case "hour": {
|
|
179
|
+
let hours = value.hour;
|
|
180
|
+
let min = 0;
|
|
181
|
+
let max = 23;
|
|
182
|
+
if (options?.hourCycle === 12) {
|
|
183
|
+
let isPM = hours >= 12;
|
|
184
|
+
min = isPM ? 12 : 0;
|
|
185
|
+
max = isPM ? 23 : 11;
|
|
186
|
+
}
|
|
187
|
+
mutable.hour = cycleValue(hours, amount, min, max, options?.round);
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
case "minute":
|
|
191
|
+
mutable.minute = cycleValue(value.minute, amount, 0, 59, options?.round);
|
|
192
|
+
break;
|
|
193
|
+
case "second":
|
|
194
|
+
mutable.second = cycleValue(value.second, amount, 0, 59, options?.round);
|
|
195
|
+
break;
|
|
196
|
+
case "millisecond":
|
|
197
|
+
mutable.millisecond = cycleValue(value.millisecond, amount, 0, 999, options?.round);
|
|
198
|
+
break;
|
|
199
|
+
default: throw new Error("Unsupported field " + field);
|
|
200
|
+
}
|
|
201
|
+
return mutable;
|
|
202
|
+
}
|
|
203
|
+
function cycleValue(value, amount, min, max, round = false) {
|
|
204
|
+
if (round) {
|
|
205
|
+
value += Math.sign(amount);
|
|
206
|
+
if (value < min) value = max;
|
|
207
|
+
let div = Math.abs(amount);
|
|
208
|
+
if (amount > 0) value = Math.ceil(value / div) * div;
|
|
209
|
+
else value = Math.floor(value / div) * div;
|
|
210
|
+
if (value > max) value = min;
|
|
211
|
+
} else {
|
|
212
|
+
value += amount;
|
|
213
|
+
if (value < min) value = max - (min - value - 1);
|
|
214
|
+
else if (value > max) value = min + (value - max - 1);
|
|
215
|
+
}
|
|
216
|
+
return value;
|
|
217
|
+
}
|
|
218
|
+
function addZoned(dateTime, duration) {
|
|
219
|
+
let ms;
|
|
220
|
+
if (duration.years != null && duration.years !== 0 || duration.months != null && duration.months !== 0 || duration.weeks != null && duration.weeks !== 0 || duration.days != null && duration.days !== 0) ms = toAbsolute(add(toCalendarDateTime(dateTime), {
|
|
221
|
+
years: duration.years,
|
|
222
|
+
months: duration.months,
|
|
223
|
+
weeks: duration.weeks,
|
|
224
|
+
days: duration.days
|
|
225
|
+
}), dateTime.timeZone);
|
|
226
|
+
else ms = epochFromDate(dateTime) - dateTime.offset;
|
|
227
|
+
ms += duration.milliseconds || 0;
|
|
228
|
+
ms += (duration.seconds || 0) * 1e3;
|
|
229
|
+
ms += (duration.minutes || 0) * 60 * 1e3;
|
|
230
|
+
ms += (duration.hours || 0) * 60 * 60 * 1e3;
|
|
231
|
+
return toCalendar(fromAbsolute(ms, dateTime.timeZone), dateTime.calendar);
|
|
232
|
+
}
|
|
233
|
+
function subtractZoned(dateTime, duration) {
|
|
234
|
+
return addZoned(dateTime, invertDuration(duration));
|
|
235
|
+
}
|
|
236
|
+
function cycleZoned(dateTime, field, amount, options) {
|
|
237
|
+
switch (field) {
|
|
238
|
+
case "hour": {
|
|
239
|
+
let min = 0;
|
|
240
|
+
let max = 23;
|
|
241
|
+
if (options?.hourCycle === 12) {
|
|
242
|
+
let isPM = dateTime.hour >= 12;
|
|
243
|
+
min = isPM ? 12 : 0;
|
|
244
|
+
max = isPM ? 23 : 11;
|
|
245
|
+
}
|
|
246
|
+
let plainDateTime = toCalendarDateTime(dateTime);
|
|
247
|
+
let minDate = toCalendar(setTime(plainDateTime, { hour: min }), new GregorianCalendar());
|
|
248
|
+
let minAbsolute = [toAbsolute(minDate, dateTime.timeZone, "earlier"), toAbsolute(minDate, dateTime.timeZone, "later")].filter((ms) => fromAbsolute(ms, dateTime.timeZone).day === minDate.day)[0];
|
|
249
|
+
let maxDate = toCalendar(setTime(plainDateTime, { hour: max }), new GregorianCalendar());
|
|
250
|
+
let maxAbsolute = [toAbsolute(maxDate, dateTime.timeZone, "earlier"), toAbsolute(maxDate, dateTime.timeZone, "later")].filter((ms) => fromAbsolute(ms, dateTime.timeZone).day === maxDate.day).pop();
|
|
251
|
+
let ms = epochFromDate(dateTime) - dateTime.offset;
|
|
252
|
+
let hours = Math.floor(ms / ONE_HOUR);
|
|
253
|
+
let remainder = ms % ONE_HOUR;
|
|
254
|
+
ms = cycleValue(hours, amount, Math.floor(minAbsolute / ONE_HOUR), Math.floor(maxAbsolute / ONE_HOUR), options?.round) * ONE_HOUR + remainder;
|
|
255
|
+
return toCalendar(fromAbsolute(ms, dateTime.timeZone), dateTime.calendar);
|
|
256
|
+
}
|
|
257
|
+
case "minute":
|
|
258
|
+
case "second":
|
|
259
|
+
case "millisecond": return cycleTime(dateTime, field, amount, options);
|
|
260
|
+
case "era":
|
|
261
|
+
case "year":
|
|
262
|
+
case "month":
|
|
263
|
+
case "day": return toCalendar(fromAbsolute(toAbsolute(cycleDate(toCalendarDateTime(dateTime), field, amount, options), dateTime.timeZone), dateTime.timeZone), dateTime.calendar);
|
|
264
|
+
default: throw new Error("Unsupported field " + field);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
function setZoned(dateTime, fields, disambiguation) {
|
|
268
|
+
let plainDateTime = toCalendarDateTime(dateTime);
|
|
269
|
+
let res = setTime(set(plainDateTime, fields), fields);
|
|
270
|
+
if (res.compare(plainDateTime) === 0) return dateTime;
|
|
271
|
+
return toCalendar(fromAbsolute(toAbsolute(res, dateTime.timeZone, disambiguation), dateTime.timeZone), dateTime.calendar);
|
|
272
|
+
}
|
|
273
|
+
//#endregion
|
|
274
|
+
export { add, addTime, addZoned, constrain, constrainTime, cycleDate, cycleTime, cycleZoned, set, setTime, setZoned, subtract, subtractTime, subtractZoned };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { CalendarDate, CalendarDateTime, DateValue, ZonedDateTime } from "./CalendarDate.js";
|
|
2
|
+
import { AnyCalendarDate, Calendar } from "./types.js";
|
|
3
|
+
|
|
4
|
+
//#region src/date/queries.d.ts
|
|
5
|
+
/** Returns whether the given dates occur on the same day, regardless of the time or calendar system. */
|
|
6
|
+
declare function isSameDay(a: DateValue, b: DateValue): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Returns whether the given dates occur in the same month, using the calendar system of the first
|
|
9
|
+
* date.
|
|
10
|
+
*/
|
|
11
|
+
declare function isSameMonth(a: DateValue, b: DateValue): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Returns whether the given dates occur in the same year, using the calendar system of the first
|
|
14
|
+
* date.
|
|
15
|
+
*/
|
|
16
|
+
declare function isSameYear(a: DateValue, b: DateValue): boolean;
|
|
17
|
+
/** Returns whether the given dates occur on the same day, and are of the same calendar system. */
|
|
18
|
+
declare function isEqualDay(a: DateValue, b: DateValue): boolean;
|
|
19
|
+
/** Returns whether the given dates occur in the same month, and are of the same calendar system. */
|
|
20
|
+
declare function isEqualMonth(a: DateValue, b: DateValue): boolean;
|
|
21
|
+
/** Returns whether the given dates occur in the same year, and are of the same calendar system. */
|
|
22
|
+
declare function isEqualYear(a: DateValue, b: DateValue): boolean;
|
|
23
|
+
/** Returns whether two calendars are the same. */
|
|
24
|
+
declare function isEqualCalendar(a: Calendar, b: Calendar): boolean;
|
|
25
|
+
/** Returns whether the date is today in the given time zone. */
|
|
26
|
+
declare function isToday(date: DateValue, timeZone: string): boolean;
|
|
27
|
+
type DayOfWeek = "sun" | "mon" | "tue" | "wed" | "thu" | "fri" | "sat";
|
|
28
|
+
/**
|
|
29
|
+
* Returns the day of week for the given date and locale. Days are numbered from zero to six,
|
|
30
|
+
* where zero is the first day of the week in the given locale. For example, in the United States,
|
|
31
|
+
* the first day of the week is Sunday, but in France it is Monday.
|
|
32
|
+
*/
|
|
33
|
+
declare function getDayOfWeek(date: DateValue, locale: string, firstDayOfWeek?: DayOfWeek): number;
|
|
34
|
+
/** Returns the current time in the given time zone. */
|
|
35
|
+
declare function now(timeZone: string): ZonedDateTime;
|
|
36
|
+
/** Returns today's date in the given time zone. */
|
|
37
|
+
declare function today(timeZone: string): CalendarDate;
|
|
38
|
+
/**
|
|
39
|
+
* Returns the number of hours in the given date and time zone.
|
|
40
|
+
* Usually this is 24, but it could be 23 or 25 if the date is on a daylight saving transition.
|
|
41
|
+
*/
|
|
42
|
+
declare function getHoursInDay(a: CalendarDate, timeZone: string): number;
|
|
43
|
+
/** Returns the time zone identifier for the current user. */
|
|
44
|
+
declare function getLocalTimeZone(): string;
|
|
45
|
+
/** Sets the time zone identifier for the current user. */
|
|
46
|
+
declare function setLocalTimeZone(timeZone: string): void;
|
|
47
|
+
/** Resets the time zone identifier for the current user. */
|
|
48
|
+
declare function resetLocalTimeZone(): void;
|
|
49
|
+
/** Returns the first date of the month for the given date. */
|
|
50
|
+
declare function startOfMonth(date: ZonedDateTime): ZonedDateTime;
|
|
51
|
+
declare function startOfMonth(date: CalendarDateTime): CalendarDateTime;
|
|
52
|
+
declare function startOfMonth(date: CalendarDate): CalendarDate;
|
|
53
|
+
declare function startOfMonth(date: DateValue): DateValue;
|
|
54
|
+
/** Returns the last date of the month for the given date. */
|
|
55
|
+
declare function endOfMonth(date: ZonedDateTime): ZonedDateTime;
|
|
56
|
+
declare function endOfMonth(date: CalendarDateTime): CalendarDateTime;
|
|
57
|
+
declare function endOfMonth(date: CalendarDate): CalendarDate;
|
|
58
|
+
declare function endOfMonth(date: DateValue): DateValue;
|
|
59
|
+
/** Returns the first day of the year for the given date. */
|
|
60
|
+
declare function startOfYear(date: ZonedDateTime): ZonedDateTime;
|
|
61
|
+
declare function startOfYear(date: CalendarDateTime): CalendarDateTime;
|
|
62
|
+
declare function startOfYear(date: CalendarDate): CalendarDate;
|
|
63
|
+
declare function startOfYear(date: DateValue): DateValue;
|
|
64
|
+
/** Returns the last day of the year for the given date. */
|
|
65
|
+
declare function endOfYear(date: ZonedDateTime): ZonedDateTime;
|
|
66
|
+
declare function endOfYear(date: CalendarDateTime): CalendarDateTime;
|
|
67
|
+
declare function endOfYear(date: CalendarDate): CalendarDate;
|
|
68
|
+
declare function endOfYear(date: DateValue): DateValue;
|
|
69
|
+
declare function getMinimumMonthInYear(date: AnyCalendarDate): number;
|
|
70
|
+
declare function getMinimumDayInMonth(date: AnyCalendarDate): number;
|
|
71
|
+
/** Returns the first date of the week for the given date and locale. */
|
|
72
|
+
declare function startOfWeek(date: ZonedDateTime, locale: string, firstDayOfWeek?: DayOfWeek): ZonedDateTime;
|
|
73
|
+
declare function startOfWeek(date: CalendarDateTime, locale: string, firstDayOfWeek?: DayOfWeek): CalendarDateTime;
|
|
74
|
+
declare function startOfWeek(date: CalendarDate, locale: string, firstDayOfWeek?: DayOfWeek): CalendarDate;
|
|
75
|
+
declare function startOfWeek(date: DateValue, locale: string, firstDayOfWeek?: DayOfWeek): DateValue;
|
|
76
|
+
/** Returns the last date of the week for the given date and locale. */
|
|
77
|
+
declare function endOfWeek(date: ZonedDateTime, locale: string, firstDayOfWeek?: DayOfWeek): ZonedDateTime;
|
|
78
|
+
declare function endOfWeek(date: CalendarDateTime, locale: string, firstDayOfWeek?: DayOfWeek): CalendarDateTime;
|
|
79
|
+
declare function endOfWeek(date: CalendarDate, locale: string, firstDayOfWeek?: DayOfWeek): CalendarDate;
|
|
80
|
+
declare function endOfWeek(date: DateValue, locale: string, firstDayOfWeek?: DayOfWeek): DateValue;
|
|
81
|
+
/** Returns the number of weeks in the given month and locale. */
|
|
82
|
+
declare function getWeeksInMonth(date: DateValue, locale: string, firstDayOfWeek?: DayOfWeek): number;
|
|
83
|
+
/** Returns the lesser of the two provider dates. */
|
|
84
|
+
declare function minDate<A extends DateValue, B extends DateValue>(a?: A | null, b?: B | null): A | B | null | undefined;
|
|
85
|
+
/** Returns the greater of the two provider dates. */
|
|
86
|
+
declare function maxDate<A extends DateValue, B extends DateValue>(a?: A | null, b?: B | null): A | B | null | undefined;
|
|
87
|
+
/** Returns whether the given date is on a weekend in the given locale. */
|
|
88
|
+
declare function isWeekend(date: DateValue, locale: string): boolean;
|
|
89
|
+
/** Returns whether the given date is on a weekday in the given locale. */
|
|
90
|
+
declare function isWeekday(date: DateValue, locale: string): boolean;
|
|
91
|
+
//#endregion
|
|
92
|
+
export { endOfMonth, endOfWeek, endOfYear, getDayOfWeek, getHoursInDay, getLocalTimeZone, getMinimumDayInMonth, getMinimumMonthInYear, getWeeksInMonth, isEqualCalendar, isEqualDay, isEqualMonth, isEqualYear, isSameDay, isSameMonth, isSameYear, isToday, isWeekday, isWeekend, maxDate, minDate, now, resetLocalTimeZone, setLocalTimeZone, startOfMonth, startOfWeek, startOfYear, today };
|