UNPKG

abushakir

Version:

Ethiopian Datetime and Calendar Reckoning system. COMPUTUS.

426 lines (425 loc) 15.5 kB
"use strict"; // Copyright 2012 (2020 GC) Nabute. All rights reserved. // Use of this source code is governed by MIT license, which can be found // in the LICENSE file. var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var constants_1 = require("../utils/constants"); var duration_1 = __importDefault(require("../utils/duration")); var EtDatetime = /** @class */ (function () { /** * Constructs an EtDatetime instance. * * @param args Either: * - No arguments → initializes to current time * - One number → milliseconds since Unix epoch OR Ethiopic year * - Multiple positional Ethiopic components: (year, month, day, hour?, minute?, second?, millisecond?) */ function EtDatetime() { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } if (args.length >= 2) { this.fixed = this.fixedFromEthiopic(this.toNumber(args[0]), this.toNumber(args[1]), this.toNumber(args[2])); this.moment = this.dateToEpoch(this.toNumber(args[0]), this.toNumber(args[1]), this.toNumber(args[2]), this.toNumber(args[3]), this.toNumber(args[4]), this.toNumber(args[5]), this.toNumber(args[6])); if (this.fixed === null) throw new Error('ARGUMENT ERROR: Unacceptable argument.'); } if (args.length === 1) { var value = this.toNumber(args[0]); if (Math.abs(value) > 9999) { this.fromMillisecondsSinceEpoch(value); } else { this.fixed = this.fixedFromEthiopic(value, 1, 1); this.moment = this.dateToEpoch(value, 1, 1, 0, 0, 0, 0); if (this.fixed === null) throw new Error('ARGUMENT ERROR: Unacceptable argument.'); } } if (args.length === 0) { this.fixed = this.fixedFromUnix(Date.now()); this.moment = Date.now(); } if (!this.fixed) { this.fixed = 0; } } /** * Sets the current datetime using a Unix timestamp in milliseconds. * * @param millisecondsSinceEpoch Timestamp in milliseconds since the Unix epoch */ EtDatetime.prototype.fromMillisecondsSinceEpoch = function (millisecondsSinceEpoch) { this.moment = millisecondsSinceEpoch; this.fixed = this.fixedFromUnix(millisecondsSinceEpoch); if (this.fixed === null) throw new Error('ARGUMENT ERROR: Unacceptable argument.'); if (Math.abs(millisecondsSinceEpoch) >= constants_1.constants.maxMillisecondsSinceEpoch) throw new Error("Calendar outside valid range " + constants_1.constants.maxMillisecondsSinceEpoch); }; /** * Updates the EtDatetime to the current system time. */ EtDatetime.prototype.now = function () { this.fixed = this.fixedFromUnix(Date.now()); this.moment = Date.now(); }; Object.defineProperty(EtDatetime.prototype, "year", { /** Ethiopic year */ get: function () { return Math.floor((4 * (this.fixed - constants_1.constants._ethiopicEpoch) + 1463) / 1461); }, enumerable: true, configurable: true }); Object.defineProperty(EtDatetime.prototype, "month", { /** Ethiopic month (1-13) */ get: function () { return Math.floor((this.fixed - this.fixedFromEthiopic(this.year, 1, 1)) / 30) + 1; }, enumerable: true, configurable: true }); Object.defineProperty(EtDatetime.prototype, "monthGeez", { /** Ethiopic month name in Geez */ get: function () { return constants_1.constants._months[(this.month - 1) % 13]; }, enumerable: true, configurable: true }); Object.defineProperty(EtDatetime.prototype, "day", { /** Ethiopic day of the month (1-30) */ get: function () { return this.fixed + 1 - this.fixedFromEthiopic(this.year, this.month, 1); }, enumerable: true, configurable: true }); Object.defineProperty(EtDatetime.prototype, "dayGeez", { /** Day of the month in Geez numeral format */ get: function () { return constants_1.constants._dayNumbers[(this.day - 1) % 30]; }, enumerable: true, configurable: true }); Object.defineProperty(EtDatetime.prototype, "hour", { /** Hour of the day (0-23) */ get: function () { return Math.floor(this.moment / constants_1.constants.hourMilliSec) % 24; }, enumerable: true, configurable: true }); Object.defineProperty(EtDatetime.prototype, "minute", { /** Minute of the hour (0-59) */ get: function () { return Math.floor(this.moment / constants_1.constants.minMilliSec) % 60; }, enumerable: true, configurable: true }); Object.defineProperty(EtDatetime.prototype, "second", { /** Second of the minute (0-59) */ get: function () { return Math.floor((this.moment / constants_1.constants.secMilliSec) % 60); }, enumerable: true, configurable: true }); Object.defineProperty(EtDatetime.prototype, "millisecond", { /** Millisecond of the second (0-999) */ get: function () { return this.moment % 1000; }, enumerable: true, configurable: true }); Object.defineProperty(EtDatetime.prototype, "isLeap", { /** Whether this year is a leap year in the Ethiopian calendar */ get: function () { return this.year % 4 === 3; }, enumerable: true, configurable: true }); Object.defineProperty(EtDatetime.prototype, "yearFirstDay", { /** The weekday index of the first day of the year (0-6, Sunday–Saturday) */ get: function () { return this._yearFirstDay(); }, enumerable: true, configurable: true }); Object.defineProperty(EtDatetime.prototype, "weekday", { /** Weekday index of the current date */ get: function () { return (this.yearFirstDay + (this.month - 1) * 2) % 7; }, enumerable: true, configurable: true }); Object.defineProperty(EtDatetime.prototype, "date", { /** Date object: { year, month, day } */ get: function () { return { year: this.year, month: this.month, day: this.day }; }, enumerable: true, configurable: true }); Object.defineProperty(EtDatetime.prototype, "time", { /** Time object: { h, m, s } */ get: function () { return { h: this.hour, m: this.minute, s: this.second }; }, enumerable: true, configurable: true }); /** * Returns a formatted string representation: `yyyy-MM-ddTHH:mm:ss.sss` */ EtDatetime.prototype.toString = function () { return this.toIso8601String(); }; /** * Returns a formatted JSON-friendly object representation */ EtDatetime.prototype.toJson = function () { return { year: this.fourDigits(this.year), month: this.twoDigits(this.month), date: this.twoDigits(this.day), hour: this.twoDigits(this.hour), min: this.twoDigits(this.minute), sec: this.twoDigits(this.second), ms: this.threeDigits(this.millisecond), }; }; /** * Returns ISO-8601 formatted string. */ EtDatetime.prototype.toIso8601String = function () { var y = this.year >= -9999 && this.year <= 9999 ? this.fourDigits(this.year) : this.sixDigits(this.year); var m = this.twoDigits(this.month); var d = this.twoDigits(this.day); var h = this.twoDigits(this.hour); var min = this.twoDigits(this.minute); var sec = this.twoDigits(this.second); var ms = this.threeDigits(this.millisecond); return y + "-" + m + "-" + d + "T" + h + ":" + min + ":" + sec + "." + ms; }; /** * Returns true if this date is before the other. */ EtDatetime.prototype.isBefore = function (other) { return this.fixed < other.fixed || this.moment < other.moment; }; /** * Returns true if this date is after the other. */ EtDatetime.prototype.isAfter = function (other) { return this.fixed > other.fixed || this.moment > other.moment; }; /** * Returns true if this date is at the same moment as the other. */ EtDatetime.prototype.isAtSameMomentAs = function (other) { return this.fixed === other.fixed && this.moment === other.moment; }; /** * Compares this instance with another EtDatetime. * Returns -1 if earlier, 1 if later, or 0 if equal. */ EtDatetime.prototype.compareTo = function (other) { if (this.isBefore(other)) return -1; else if (this.isAtSameMomentAs(other)) return 0; else return 1; }; /** * Adds a Duration to this date. */ EtDatetime.prototype.add = function (duration) { return new EtDatetime(this.moment + duration.inMilliseconds); }; /** * Subtracts a Duration from this date. */ EtDatetime.prototype.subtract = function (duration) { return new EtDatetime(this.moment - duration.inMilliseconds); }; /** * Returns the Duration between this and another EtDatetime. */ EtDatetime.prototype.difference = function (other) { return new duration_1.default(Math.abs(this.fixed - other.fixed), 0, 0, 0, 0, 0); }; /** * Gets the fixed date from Ethiopic calendar date. */ EtDatetime.prototype.fixedFromEthiopic = function (year, month, day) { return Math.floor(constants_1.constants._ethiopicEpoch - 1 + 365 * (year - 1) + year / 4 + 30 * (month - 1) + day); }; /** * Gets the fixed date from Unix timestamp (in ms). */ EtDatetime.prototype.fixedFromUnix = function (ms) { return constants_1.constants._unixEpoch + Math.floor(ms / 86400000); }; /** * Converts Ethiopic date-time to Unix epoch milliseconds. */ EtDatetime.prototype.dateToEpoch = function (year, month, date, hour, minute, second, millisecond) { return ((this.fixedFromEthiopic(year, month, date) - constants_1.constants._unixEpoch) * constants_1.constants.dayMilliSec + (hour ? hour * constants_1.constants.hourMilliSec : 0) + (minute ? minute * constants_1.constants.minMilliSec : 0) + (second ? second * constants_1.constants.secMilliSec : 0) + (millisecond !== null && millisecond !== void 0 ? millisecond : 0)); }; /** * Returns the weekday of the first day of the year. */ EtDatetime.prototype._yearFirstDay = function () { var ameteAlem = constants_1.constants.ameteFida + this.year; var rabeet = Math.floor(ameteAlem / 4); return (ameteAlem + rabeet) % 7; }; /** Formats a year as 4-digit string (e.g., 2012) */ EtDatetime.prototype.fourDigits = function (n) { var abs = Math.abs(n); var sign = n < 0 ? '-' : ''; if (abs >= 1000) return "" + n; if (abs >= 100) return sign + "0" + abs; if (abs >= 10) return sign + "00" + abs; return sign + "000" + abs; }; /** Formats a year as 6-digit string (for extreme years) */ EtDatetime.prototype.sixDigits = function (n) { if (n < -9999 || n > 9999) throw new Error('Year out of scope'); var abs = Math.abs(n); var sign = n < 0 ? '-' : '+'; if (abs >= 100000) return "" + sign + abs; return sign + "0" + abs; }; /** Pads a number to 3 digits */ EtDatetime.prototype.threeDigits = function (n) { if (n >= 100) return "" + n; if (n >= 10) return "0" + n; return "00" + n; }; /** Pads a number to 2 digits */ EtDatetime.prototype.twoDigits = function (n) { return n >= 10 ? "" + n : "0" + n; }; /** * Converts various types to a number. * Throws if the type is invalid (symbol, object). */ EtDatetime.prototype.toNumber = function (value) { if (value === undefined) return NaN; if (value === null) return 0; if (typeof value === 'boolean') return value ? 1 : 0; if (typeof value === 'string') return parseInt(value, 10); if (typeof value === 'symbol' || typeof value === 'object') throw new Error('TYPE ERROR: Unexpected operand type.'); return value; }; /** Returns the timestamp in milliseconds */ EtDatetime.prototype.valueOf = function () { return this.moment; }; /** Alias of `toIso8601String()` */ EtDatetime.prototype.toJSON = function () { return this.toIso8601String(); }; /** Alias of `toIso8601String()` */ EtDatetime.prototype.toISOString = function () { return this.toIso8601String(); }; /** Returns Ethiopic year */ EtDatetime.prototype.getFullYear = function () { return this.year; }; /** Returns Ethiopic month (0-indexed) */ EtDatetime.prototype.getMonth = function () { return this.month - 1; }; /** Returns Ethiopic day */ EtDatetime.prototype.getDate = function () { return this.day; }; /** Returns hour */ EtDatetime.prototype.getHours = function () { return this.hour; }; /** Returns minute */ EtDatetime.prototype.getMinutes = function () { return this.minute; }; /** Returns second */ EtDatetime.prototype.getSeconds = function () { return this.second; }; /** Returns millisecond */ EtDatetime.prototype.getMilliseconds = function () { return this.millisecond; }; /** * Static method that returns the current EtDatetime. */ EtDatetime.now = function () { return new EtDatetime(Date.now()); }; Object.defineProperty(EtDatetime.prototype, Symbol.toStringTag, { /** Customizes output of Object.prototype.toString.call() */ get: function () { return 'EtDatetime'; }, enumerable: true, configurable: true }); /** * Enables primitive coercion: * - String context → ISO string * - Number context → timestamp */ EtDatetime.prototype[Symbol.toPrimitive] = function (hint) { if (hint === 'string' || hint === 'default') return this.toISOString(); if (hint === 'number') return this.valueOf(); return this.toISOString(); }; /** * Returns timestamp in ms (same as valueOf). */ EtDatetime.prototype.getTime = function () { return this.valueOf(); }; /** * Converts EtDatetime to native JavaScript Date. */ EtDatetime.prototype.toDate = function () { return new Date(this.moment); }; return EtDatetime; }()); exports.default = EtDatetime;