@phensley/cldr-core
Version:
Core library for @phensley/cldr
389 lines • 14.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var cldr_schema_1 = require("@phensley/cldr-schema");
var fields_1 = require("./fields");
var timezone_1 = require("./timezone");
var numbering_1 = require("../numbering");
var zeropad = function (n, w) { return numbering_1.INTERNAL_NUMBERING.formatString(n, false, w); };
/**
* Implementation order, based on calendar preference data and ease of implementation.
* https://github.com/unicode-cldr/cldr-core/blob/master/supplemental/calendarPreferenceData.json
*
* Complete:
* gregorian - widely used worldwide
* persian - primary in AF, IR
* japanese - secondary in JP, based on gregorian
* iso8601 - based on gregorian
* buddhist - primary in TH
*
* Next:
* islamic-umalqura - primary in SA
* chinese - secondary in CN, CX, HK, MO, SG, TW
* islamic - secondary in many locales
* dangi - secondary in KO, based on chinese
*
* Rest TBD
*
* Calendar calculations are compatible with those in the Unicode ICU project.
*/
// Indicates a null field to support computing on demand
var NULL = Number.MAX_SAFE_INTEGER;
var floor = Math.floor;
var differenceFields = [
[4 /* YEAR */, cldr_schema_1.DateTimePatternField.YEAR],
[7 /* MONTH */, cldr_schema_1.DateTimePatternField.MONTH],
[10 /* DAY_OF_MONTH */, cldr_schema_1.DateTimePatternField.DAY],
[14 /* AM_PM */, cldr_schema_1.DateTimePatternField.DAYPERIOD],
[16 /* HOUR */, cldr_schema_1.DateTimePatternField.HOUR],
[17 /* MINUTE */, cldr_schema_1.DateTimePatternField.MINUTE],
];
/**
* Base class for dates in supported calendars.
*
* @alpha
*/
var CalendarDate = /** @class */ (function () {
/**
* Minimal fields required to construct any calendar date.
*/
function CalendarDate(_type, _firstDay, _minDays) {
this._type = _type;
this._firstDay = _firstDay;
this._minDays = _minDays;
this._fields = fields_1.dateFields();
// Compute week fields on demand.
this._fields[6 /* WEEK_OF_YEAR */] = NULL;
this._fields[5 /* YEAR_WOY */] = NULL;
}
CalendarDate.prototype.type = function () {
return this._type;
};
/**
* Unix epoch with no timezone offset.
*/
CalendarDate.prototype.unixEpoch = function () {
return this._fields[0 /* LOCAL_MILLIS */] + this._zoneInfo.offset;
};
CalendarDate.prototype.firstDayOfWeek = function () {
return this._firstDay;
};
CalendarDate.prototype.minDaysInFirstWeek = function () {
return this._minDays;
};
/**
* Returns a floating point number representing the real Julian Day, UTC.
*/
CalendarDate.prototype.julianDay = function () {
var ms = (this._fields[13 /* MILLIS_IN_DAY */] + this._zoneInfo.offset) / 86400000 /* ONE_DAY_MS */;
return (this._fields[1 /* JULIAN_DAY */] - 0.5) + ms;
};
/**
* CLDR's modified Julian day used as the basis for all date calculations.
*/
CalendarDate.prototype.modifiedJulianDay = function () {
return this._fields[1 /* JULIAN_DAY */];
};
CalendarDate.prototype.era = function () {
return this._fields[2 /* ERA */];
};
CalendarDate.prototype.extendedYear = function () {
return this._fields[3 /* EXTENDED_YEAR */];
};
CalendarDate.prototype.year = function () {
return this._fields[4 /* YEAR */];
};
CalendarDate.prototype.relatedYear = function () {
return this._fields[3 /* EXTENDED_YEAR */];
};
CalendarDate.prototype.yearOfWeekOfYear = function () {
this.computeWeekFields();
return this._fields[5 /* YEAR_WOY */];
};
CalendarDate.prototype.weekOfYear = function () {
this.computeWeekFields();
return this._fields[6 /* WEEK_OF_YEAR */];
};
/**
* Ordinal month, one-based, e.g. Gregorian JANUARY = 1.
*/
CalendarDate.prototype.month = function () {
return this._fields[7 /* MONTH */];
};
/**
* Returns the week of the month computed using the locale's 'first day
* of week' and 'minimal days in first week' where applicable.
*
* For example, for the United States, weeks start on Sunday.
* Saturday 9/1/2018 would be in week 1, and Sunday 9/2/2018 would
* begin week 2.
*
* September
* Su Mo Tu We Th Fr Sa
* 1
* 2 3 4 5 6 7 8
* 9 10 11 12 13 14 15
* 16 17 18 19 20 21 22
* 23 24 25 26 27 28 29
* 30
*/
CalendarDate.prototype.weekOfMonth = function () {
this.computeWeekFields();
return this._fields[8 /* WEEK_OF_MONTH */];
};
CalendarDate.prototype.dayOfYear = function () {
return this._fields[9 /* DAY_OF_YEAR */];
};
/**
* Day of the week. 1 = SUNDAY, 2 = MONDAY, ..., 7 = SATURDAY
*/
CalendarDate.prototype.dayOfWeek = function () {
return this._fields[11 /* DAY_OF_WEEK */];
};
/**
* Ordinal day of the week. 1 if this is the 1st day of the week,
* 2 if the 2nd, etc. Depends on the local starting day of the week.
*/
CalendarDate.prototype.ordinalDayOfWeek = function () {
var weekday = this.dayOfWeek();
var firstDay = this.firstDayOfWeek();
return (7 - firstDay + weekday) % 7 + 1;
};
/**
* Ordinal number indicating the day of the week in the current month.
* The result of this method can be used to format messages like
* "2nd Sunday in August".
*/
CalendarDate.prototype.dayOfWeekInMonth = function () {
this.computeWeekFields();
return this._fields[12 /* DAY_OF_WEEK_IN_MONTH */];
};
CalendarDate.prototype.dayOfMonth = function () {
return this._fields[10 /* DAY_OF_MONTH */];
};
CalendarDate.prototype.isAM = function () {
return this._fields[14 /* AM_PM */] === 0;
};
/**
* Indicates the hour of the morning or afternoon, used for the 12-hour
* clock (0 - 11). Noon and midnight are 0, not 12.
*/
CalendarDate.prototype.hour = function () {
return this._fields[16 /* HOUR */];
};
/**
* Indicates the hour of the day, used for the 24-hour clock (0 - 23).
* Noon is 12 and midnight is 0.
*/
CalendarDate.prototype.hourOfDay = function () {
return this._fields[15 /* HOUR_OF_DAY */];
};
/**
* Indicates the minute of the hour (0 - 59).
*/
CalendarDate.prototype.minute = function () {
return this._fields[17 /* MINUTE */];
};
/**
* Indicates the second of the minute (0 - 59).
*/
CalendarDate.prototype.second = function () {
return this._fields[18 /* SECOND */];
};
CalendarDate.prototype.milliseconds = function () {
return this._fields[19 /* MILLIS */];
};
CalendarDate.prototype.millisecondsInDay = function () {
return this._fields[13 /* MILLIS_IN_DAY */];
};
CalendarDate.prototype.metaZoneId = function () {
return this._zoneInfo.metaZoneId;
};
CalendarDate.prototype.timeZoneId = function () {
return this._zoneInfo.timeZoneId;
};
CalendarDate.prototype.timeZoneOffset = function () {
return this._zoneInfo.offset;
};
CalendarDate.prototype.isLeapYear = function () {
return this._fields[21 /* IS_LEAP */] === 1;
};
CalendarDate.prototype.isDaylightSavings = function () {
return this._zoneInfo.dst;
};
/**
* Computes the field of greatest difference between the two dates.
* Note: This assumes the dates are of the same type and have the same
* timezone offset.
*/
CalendarDate.prototype.fieldOfGreatestDifference = function (other) {
var a = this._fields;
var b = other._fields;
for (var _i = 0, differenceFields_1 = differenceFields; _i < differenceFields_1.length; _i++) {
var pair = differenceFields_1[_i];
var key = pair[0], field = pair[1];
if (a[key] !== b[key]) {
return field;
}
}
return cldr_schema_1.DateTimePatternField.SECOND;
};
/**
* Compute a new Julian day and milliseconds UTC by updating one or more fields.
*/
CalendarDate.prototype._add = function (fields) {
// All day calculations will be relative to the current day of the month.
var dom = this._fields[10 /* DAY_OF_MONTH */] + (fields.day || 0) + ((fields.week || 0) * 7);
// Adjust the extended year and month.
// TODO: move month overflow into monthStart()
var month = (this._fields[7 /* MONTH */] - 1) + (fields.month || 0);
var yadd = floor(month / 12);
var year = this._fields[3 /* EXTENDED_YEAR */] + (fields.year || 0) + yadd;
month -= yadd * 12;
// Calculate days and milliseconds from the time-oriented fields.
var _a = this._addTime(fields), days = _a[0], ms = _a[1];
// Calculate the Julian day for the adjusted year/month then add back the days.
var jd = this.monthStart(year, month, false) + dom + days;
return [jd, ms];
};
/**
* Converts all time fields into [days, milliseconds].
*/
CalendarDate.prototype._addTime = function (fields) {
// Calculate the time difference in days and milliseconds
var msDay = this._fields[13 /* MILLIS_IN_DAY */] + this.timeZoneOffset();
msDay += ((fields.hour || 0) * 3600000 /* ONE_HOUR_MS */) +
((fields.minute || 0) * 60000 /* ONE_MINUTE_MS */) +
((fields.second || 0) * 1000 /* ONE_SECOND_MS */) +
((fields.millis || 0));
var oneDay = 86400000 /* ONE_DAY_MS */;
var days = floor(msDay / oneDay);
var ms = msDay - (days * oneDay);
return [days, ms];
};
CalendarDate.prototype.initFromUnixEpoch = function (ms, zoneId) {
if (zoneId === void 0) { zoneId = 'UTC'; }
zoneId = timezone_1.substituteZoneAlias(zoneId);
this._zoneInfo = timezone_1.zoneInfoCache.get(ms, zoneId);
jdFromUnixEpoch(ms - this._zoneInfo.offset, this._fields);
computeBaseFields(this._fields);
};
CalendarDate.prototype.initFromJD = function (jd, msDay, zoneId) {
if (zoneId === void 0) { zoneId = 'UTC'; }
var unixEpoch = unixEpochFromJD(jd, msDay);
this.initFromUnixEpoch(unixEpoch, zoneId);
};
CalendarDate.prototype._toString = function (type, year) {
return type + " " + (year || this.year()) + "-" + zeropad(this.month(), 2) + "-" + zeropad(this.dayOfMonth(), 2) + " " +
(zeropad(this.hourOfDay(), 2) + ":" + zeropad(this.minute(), 2) + ":" + zeropad(this.second(), 2)) +
("." + zeropad(this.milliseconds(), 3) + " " + this._zoneInfo.timeZoneId);
};
/**
* Compute WEEK_OF_YEAR and YEAR_WOY on demand.
*/
CalendarDate.prototype.computeWeekFields = function () {
var f = this._fields;
if (f[5 /* YEAR_WOY */] !== NULL) {
return;
}
var eyear = f[3 /* EXTENDED_YEAR */];
var dow = f[11 /* DAY_OF_WEEK */];
var dom = f[10 /* DAY_OF_MONTH */];
var doy = f[9 /* DAY_OF_YEAR */];
var ywoy = eyear;
var rdow = (dow + 7 - this._firstDay) % 7;
var rdowJan1 = (dow - doy + 7001 - this._firstDay) % 7;
var woy = floor((doy - 1 + rdowJan1) / 7);
if ((7 - rdowJan1) >= this._minDays) {
woy++;
}
if (woy === 0) {
var prevDay = doy + this.yearLength(eyear - 1);
woy = this.weekNumber(prevDay, prevDay, dow);
ywoy--;
}
else {
var lastDoy = this.yearLength(eyear);
if (doy >= (lastDoy - 5)) {
var lastRdow = (rdow + lastDoy - doy) % 7;
if (lastRdow < 0) {
lastRdow += 7;
}
if (((6 - lastRdow) >= this._minDays) && ((doy + 7 - rdow) > lastDoy)) {
woy = 1;
ywoy++;
}
}
}
f[8 /* WEEK_OF_MONTH */] = this.weekNumber(dom, dom, dow);
f[6 /* WEEK_OF_YEAR */] = woy;
f[5 /* YEAR_WOY */] = ywoy;
f[12 /* DAY_OF_WEEK_IN_MONTH */] = ((dom - 1) / 7 | 0) + 1;
};
CalendarDate.prototype.yearLength = function (y) {
return this.monthStart(y + 1, 0, false) - this.monthStart(y, 0, false);
};
CalendarDate.prototype.weekNumber = function (desiredDay, dayOfPeriod, dayOfWeek) {
var psow = (dayOfWeek - this._firstDay - dayOfPeriod + 1) % 7;
if (psow < 0) {
psow += 7;
}
var weekNo = floor((desiredDay + psow - 1) / 7);
return ((7 - psow) >= this._minDays) ? weekNo + 1 : weekNo;
};
return CalendarDate;
}());
exports.CalendarDate = CalendarDate;
/**
* Compute Julian day from timezone-adjusted Unix epoch milliseconds.
*/
var jdFromUnixEpoch = function (ms, f) {
var oneDayMS = 86400000 /* ONE_DAY_MS */;
var days = floor(ms / oneDayMS);
var jd = days + 2440588 /* JD_UNIX_EPOCH */;
var msDay = ms - (days * oneDayMS);
f[1 /* JULIAN_DAY */] = jd;
f[13 /* MILLIS_IN_DAY */] = msDay;
};
/**
* Given a Julian day and local milliseconds (in UTC), return the Unix
* epoch milliseconds UTC.
*/
var unixEpochFromJD = function (jd, msDay) {
var days = jd - 2440588 /* JD_UNIX_EPOCH */;
return (days * 86400000 /* ONE_DAY_MS */) + msDay;
};
/**
* Compute fields common to all calendars. Before calling this, we must
* have the JULIAN_DAY and MILLIS_IN_DAY fields set. Every calculation
* is relative to these.
*/
var computeBaseFields = function (f) {
var jd = f[1 /* JULIAN_DAY */];
checkJDRange(jd);
var msDay = f[13 /* MILLIS_IN_DAY */];
var ms = msDay + ((jd - 2440588 /* JD_UNIX_EPOCH */) * 86400000 /* ONE_DAY_MS */);
f[0 /* LOCAL_MILLIS */] = ms;
f[1 /* JULIAN_DAY */] = jd;
f[13 /* MILLIS_IN_DAY */] = msDay;
f[19 /* MILLIS */] = msDay % 1000;
msDay = msDay / 1000 | 0;
f[18 /* SECOND */] = msDay % 60;
msDay = msDay / 60 | 0;
f[17 /* MINUTE */] = msDay % 60;
msDay = msDay / 60 | 0;
f[15 /* HOUR_OF_DAY */] = msDay;
f[14 /* AM_PM */] = msDay / 12 | 0;
f[16 /* HOUR */] = msDay % 12;
var dow = (jd + 2 /* MONDAY */) % 7;
if (dow < 1 /* SUNDAY */) {
dow += 7;
}
f[11 /* DAY_OF_WEEK */] = dow;
};
var checkJDRange = function (jd) {
if (jd < 0 /* JD_MIN */ || jd > 4881503 /* JD_MAX */) {
throw new Error("Julian day " + jd + " is outside the supported range of this library: " +
("Mon Jan 1 4713 B.C." /* JD_MIN */ + " to " + "Fri Dec 31 8652 A.D." /* JD_MAX */));
}
};
//# sourceMappingURL=calendar.js.map