/* * 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, CalendarIdentifier} from '../types'; import {CalendarDate} from '../CalendarDate'; import {fromExtendedYear, GregorianCalendar, gregorianToJulianDay, isLeapYear} from './GregorianCalendar'; // Starts in 78 AD, const INDIAN_ERA_START = 78; // The Indian year starts 80 days later than the Gregorian year. const INDIAN_YEAR_START = 80; /** * The Indian National Calendar is similar to the Gregorian calendar, but with * years numbered since the Saka era in 78 AD (Gregorian). There are 12 months * in each year, with either 30 or 31 days. Only one era identifier is supported: 'saka'. */ export class IndianCalendar extends GregorianCalendar { identifier: CalendarIdentifier = 'indian'; fromJulianDay(jd: number): CalendarDate { // Gregorian date for Julian day let date = super.fromJulianDay(jd); // Year in Saka era let indianYear = date.year - INDIAN_ERA_START; // Day number in Gregorian year (starting from 0) let yDay = jd - gregorianToJulianDay(date.era, date.year, 1, 1); let leapMonth: number; if (yDay < INDIAN_YEAR_START) { // Day is at the end of the preceding Saka year indianYear--; // Days in leapMonth this year, previous Gregorian year leapMonth = isLeapYear(date.year - 1) ? 31 : 30; yDay += leapMonth + (31 * 5) + (30 * 3) + 10; } else { // Days in leapMonth this year leapMonth = isLeapYear(date.year) ? 31 : 30; yDay -= INDIAN_YEAR_START; } let indianMonth: number; let indianDay: number; if (yDay < leapMonth) { indianMonth = 1; indianDay = yDay + 1; } else { let mDay = yDay - leapMonth; if (mDay < (31 * 5)) { indianMonth = Math.floor(mDay / 31) + 2; indianDay = (mDay % 31) + 1; } else { mDay -= 31 * 5; indianMonth = Math.floor(mDay / 30) + 7; indianDay = (mDay % 30) + 1; } } return new CalendarDate(this, indianYear, indianMonth, indianDay); } toJulianDay(date: AnyCalendarDate): number { let extendedYear = date.year + INDIAN_ERA_START; let [era, year] = fromExtendedYear(extendedYear); let leapMonth: number; let jd: number; if (isLeapYear(year)) { leapMonth = 31; jd = gregorianToJulianDay(era, year, 3, 21); } else { leapMonth = 30; jd = gregorianToJulianDay(era, year, 3, 22); } if (date.month === 1) { return jd + date.day - 1; } jd += leapMonth + Math.min(date.month - 2, 5) * 31; if (date.month >= 8) { jd += (date.month - 7) * 30; } jd += date.day - 1; return jd; } getDaysInMonth(date: AnyCalendarDate): number { if (date.month === 1 && isLeapYear(date.year + INDIAN_ERA_START)) { return 31; } if (date.month >= 2 && date.month <= 6) { return 31; } return 30; } getYearsInEra(): number { // 9999-12-31 gregorian is 9920-10-10 indian. // Round down to 9919 for the last full year. return 9919; } getEras(): string[] { return ['saka']; } balanceDate(): void {} }