Build NapCat Artifacts / Windows Loader Test (push) Canceled after 0s
Build NapCat Artifacts / Type Check & Test (push) Canceled after 0s
Build NapCat Artifacts / Build NapCat.Framework (push) Canceled after 0s
Build NapCat Artifacts / Build NapCat.Shell (push) Canceled after 0s
197 lines
5.9 KiB
Plaintext
197 lines
5.9 KiB
Plaintext
/*
|
|
* Copyright 2020 Adobe. All rights reserved.
|
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License. You may obtain a copy
|
|
* of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
* governing permissions and limitations under the License.
|
|
*/
|
|
|
|
// Portions of the code in this file are based on code from ICU.
|
|
// Original licensing can be found in the NOTICE file in the root directory of this source tree.
|
|
|
|
import {AnyCalendarDate, Calendar} from '../types';
|
|
import {CalendarDate} from '../CalendarDate';
|
|
import {Mutable} from '../utils';
|
|
|
|
const ETHIOPIC_EPOCH = 1723856;
|
|
const COPTIC_EPOCH = 1824665;
|
|
|
|
// The delta between Amete Alem 1 and Amete Mihret 1
|
|
// AA 5501 = AM 1
|
|
const AMETE_MIHRET_DELTA = 5500;
|
|
|
|
function ceToJulianDay(epoch: number, year: number, month: number, day: number): number {
|
|
return (
|
|
epoch // difference from Julian epoch to 1,1,1
|
|
+ 365 * year // number of days from years
|
|
+ Math.floor(year / 4) // extra day of leap year
|
|
+ 30 * (month - 1) // number of days from months (1 based)
|
|
+ day - 1 // number of days for present month (1 based)
|
|
);
|
|
}
|
|
|
|
function julianDayToCE(epoch: number, jd: number) {
|
|
let year = Math.floor((4 * (jd - epoch)) / 1461);
|
|
let month = 1 + Math.floor((jd - ceToJulianDay(epoch, year, 1, 1)) / 30);
|
|
let day = jd + 1 - ceToJulianDay(epoch, year, month, 1);
|
|
return [year, month, day];
|
|
}
|
|
|
|
function getLeapDay(year: number) {
|
|
return Math.floor((year % 4) / 3);
|
|
}
|
|
|
|
function getDaysInMonth(year: number, month: number) {
|
|
// The Ethiopian and Coptic calendars have 13 months, 12 of 30 days each and
|
|
// an intercalary month at the end of the year of 5 or 6 days, depending whether
|
|
// the year is a leap year or not. The Leap Year follows the same rules as the
|
|
// Julian Calendar so that the extra month always has six days in the year before
|
|
// a Julian Leap Year.
|
|
if (month % 13 !== 0) {
|
|
// not intercalary month
|
|
return 30;
|
|
} else {
|
|
// intercalary month 5 days + possible leap day
|
|
return getLeapDay(year) + 5;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The Ethiopic calendar system is the official calendar used in Ethiopia.
|
|
* It includes 12 months of 30 days each, plus 5 or 6 intercalary days depending
|
|
* on whether it is a leap year. Two eras are supported: 'AA' and 'AM'.
|
|
*/
|
|
export class EthiopicCalendar implements Calendar {
|
|
identifier = 'ethiopic';
|
|
|
|
fromJulianDay(jd: number): CalendarDate {
|
|
let [year, month, day] = julianDayToCE(ETHIOPIC_EPOCH, jd);
|
|
let era = 'AM';
|
|
if (year <= 0) {
|
|
era = 'AA';
|
|
year += AMETE_MIHRET_DELTA;
|
|
}
|
|
|
|
return new CalendarDate(this, era, year, month, day);
|
|
}
|
|
|
|
toJulianDay(date: AnyCalendarDate) {
|
|
let year = date.year;
|
|
if (date.era === 'AA') {
|
|
year -= AMETE_MIHRET_DELTA;
|
|
}
|
|
|
|
return ceToJulianDay(ETHIOPIC_EPOCH, year, date.month, date.day);
|
|
}
|
|
|
|
getDaysInMonth(date: AnyCalendarDate): number {
|
|
return getDaysInMonth(date.year, date.month);
|
|
}
|
|
|
|
getMonthsInYear(): number {
|
|
return 13;
|
|
}
|
|
|
|
getDaysInYear(date: AnyCalendarDate): number {
|
|
return 365 + getLeapDay(date.year);
|
|
}
|
|
|
|
getYearsInEra(date: AnyCalendarDate): number {
|
|
// 9999-12-31 gregorian is 9992-20-02 ethiopic.
|
|
// Round down to 9991 for the last full year.
|
|
// AA 9999-01-01 ethiopic is 4506-09-30 gregorian.
|
|
return date.era === 'AA' ? 9999 : 9991;
|
|
}
|
|
|
|
getEras() {
|
|
return ['AA', 'AM'];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The Ethiopic (Amete Alem) calendar is the same as the modern Ethiopic calendar,
|
|
* except years were measured from a different epoch. Only one era is supported: 'AA'.
|
|
*/
|
|
export class EthiopicAmeteAlemCalendar extends EthiopicCalendar {
|
|
identifier = 'ethioaa'; // also known as 'ethiopic-amete-alem' in ICU
|
|
|
|
fromJulianDay(jd: number): CalendarDate {
|
|
let [year, month, day] = julianDayToCE(ETHIOPIC_EPOCH, jd);
|
|
year += AMETE_MIHRET_DELTA;
|
|
return new CalendarDate(this, 'AA', year, month, day);
|
|
}
|
|
|
|
getEras() {
|
|
return ['AA'];
|
|
}
|
|
|
|
getYearsInEra(): number {
|
|
// 9999-13-04 ethioaa is the maximum date, which is equivalent to 4506-09-29 gregorian.
|
|
return 9999;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The Coptic calendar is similar to the Ethiopic calendar.
|
|
* It includes 12 months of 30 days each, plus 5 or 6 intercalary days depending
|
|
* on whether it is a leap year. Two eras are supported: 'BCE' and 'CE'.
|
|
*/
|
|
export class CopticCalendar extends EthiopicCalendar {
|
|
identifier = 'coptic';
|
|
|
|
fromJulianDay(jd: number): CalendarDate {
|
|
let [year, month, day] = julianDayToCE(COPTIC_EPOCH, jd);
|
|
let era = 'CE';
|
|
if (year <= 0) {
|
|
era = 'BCE';
|
|
year = 1 - year;
|
|
}
|
|
|
|
return new CalendarDate(this, era, year, month, day);
|
|
}
|
|
|
|
toJulianDay(date: AnyCalendarDate) {
|
|
let year = date.year;
|
|
if (date.era === 'BCE') {
|
|
year = 1 - year;
|
|
}
|
|
|
|
return ceToJulianDay(COPTIC_EPOCH, year, date.month, date.day);
|
|
}
|
|
|
|
getDaysInMonth(date: AnyCalendarDate): number {
|
|
let year = date.year;
|
|
if (date.era === 'BCE') {
|
|
year = 1 - year;
|
|
}
|
|
|
|
return getDaysInMonth(year, date.month);
|
|
}
|
|
|
|
isInverseEra(date: AnyCalendarDate): boolean {
|
|
return date.era === 'BCE';
|
|
}
|
|
|
|
balanceDate(date: Mutable<AnyCalendarDate>) {
|
|
if (date.year <= 0) {
|
|
date.era = date.era === 'BCE' ? 'CE' : 'BCE';
|
|
date.year = 1 - date.year;
|
|
}
|
|
}
|
|
|
|
getEras() {
|
|
return ['BCE', 'CE'];
|
|
}
|
|
|
|
getYearsInEra(date: AnyCalendarDate): number {
|
|
// 9999-12-30 gregorian is 9716-02-20 coptic.
|
|
// Round down to 9715 for the last full year.
|
|
// BCE 9999-01-01 coptic is BC 9716-06-15 gregorian.
|
|
return date.era === 'BCE' ? 9999 : 9715;
|
|
}
|
|
}
|