mirror of
https://github.com/quantum5/qcal.git
synced 2025-04-24 09:41:57 -04:00
Add Julian calendar handling
This commit is contained in:
parent
17229a8c2e
commit
56cef40dba
|
@ -1,4 +1,4 @@
|
|||
import {gregorianJDN, jdnGregorian} from './gregorian';
|
||||
import {gregorianJDN, jdnDate, jdnGregorian, JulianDay, JulianMonth} from './gregorian';
|
||||
|
||||
describe('gregorianJDN', () => {
|
||||
it('works', () => {
|
||||
|
@ -15,25 +15,55 @@ describe('gregorianJDN', () => {
|
|||
expect(gregorianJDN(19720, 8, 14)).toBe(8923868);
|
||||
expect(gregorianJDN(7504, 7, 22)).toBe(4462042);
|
||||
});
|
||||
|
||||
it('transition to Julian works', () => {
|
||||
expect(gregorianJDN(2000, 1, 1, 2299161)).toBe(2451545);
|
||||
expect(gregorianJDN(1969, 7, 20, 2299161)).toBe(2440423);
|
||||
expect(gregorianJDN(1582, 10, 15, 2299161)).toBe(2299161);
|
||||
expect(gregorianJDN(1582, 10, 4, 2299161)).toBe(2299160);
|
||||
expect(gregorianJDN(1066, 10, 14, 2299161)).toBe(2110701);
|
||||
expect(gregorianJDN(0, 12, 25, 2299161)).toBe(1721417);
|
||||
expect(gregorianJDN(-4712, 1, 1, 2299161)).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('jdnGregorian', () => {
|
||||
it('works', () => {
|
||||
expect(jdnGregorian(0)).toEqual(new Date(-4713, 10, 24));
|
||||
expect(jdnGregorian(2299160)).toEqual(new Date(1582, 9, 14));
|
||||
expect(jdnGregorian(2299161)).toEqual(new Date(1582, 9, 15));
|
||||
expect(jdnGregorian(2361221)).toEqual(new Date(1752, 8, 13));
|
||||
expect(jdnGregorian(2361222)).toEqual(new Date(1752, 8, 14));
|
||||
expect(jdnGregorian(2451545)).toEqual(new Date(2000, 0, 1));
|
||||
expect(jdnGregorian(-8512316)).toEqual(new Date(-28019, 11, 20));
|
||||
expect(jdnGregorian(-8534852)).toEqual(new Date(-28080, 3, 8));
|
||||
expect(jdnGregorian(2653462)).toEqual(new Date(2552, 9, 30));
|
||||
expect(jdnGregorian(3271156)).toEqual(new Date(4244, 0, 8));
|
||||
expect(jdnGregorian(-666477)).toEqual(new Date(-6537, 1, 23));
|
||||
expect(jdnGregorian(2397854)).toEqual(new Date(1852, 11, 31));
|
||||
expect(jdnGregorian(-1211235)).toEqual(new Date(-8029, 7, 26));
|
||||
expect(jdnGregorian(-91680)).toEqual(new Date(-4964, 10, 20));
|
||||
expect(jdnGregorian(-5605876)).toEqual(new Date(-20061, 6, 14));
|
||||
expect(jdnGregorian(-295121)).toEqual(new Date(-5521, 10, 19));
|
||||
function checkJDN(jdn: number, year: number, month: JulianMonth, day: JulianDay) {
|
||||
expect(jdnGregorian(jdn)).toEqual([year, month, day]);
|
||||
expect(jdnDate(jdn)).toEqual(new Date(year, month - 1, day));
|
||||
}
|
||||
|
||||
checkJDN(0, -4713, 11, 24);
|
||||
checkJDN(2299160, 1582, 10, 14);
|
||||
checkJDN(2299161, 1582, 10, 15);
|
||||
checkJDN(2361221, 1752, 9, 13);
|
||||
checkJDN(2361222, 1752, 9, 14);
|
||||
checkJDN(2451545, 2000, 1, 1);
|
||||
checkJDN(-8512316, -28019, 12, 20);
|
||||
checkJDN(-8534852, -28080, 4, 8);
|
||||
checkJDN(2653462, 2552, 10, 30);
|
||||
checkJDN(3271156, 4244, 1, 8);
|
||||
checkJDN(-666477, -6537, 2, 23);
|
||||
checkJDN(2397854, 1852, 12, 31);
|
||||
checkJDN(-1211235, -8029, 8, 26);
|
||||
checkJDN(-91680, -4964, 11, 20);
|
||||
checkJDN(-5605876, -20061, 7, 14);
|
||||
checkJDN(-295121, -5521, 11, 19);
|
||||
});
|
||||
|
||||
it('transition to Julian works', () => {
|
||||
function checkJDN(jdn: number, year: number, month: JulianMonth, day: JulianDay) {
|
||||
expect(jdnGregorian(jdn, 2299161)).toEqual([year, month, day]);
|
||||
expect(jdnDate(jdn, 2299161)).toEqual(new Date(year, month - 1, day));
|
||||
}
|
||||
|
||||
checkJDN(2451545, 2000, 1, 1);
|
||||
checkJDN(2440423, 1969, 7, 20);
|
||||
checkJDN(2299161, 1582, 10, 15);
|
||||
checkJDN(2299160, 1582, 10, 4);
|
||||
checkJDN(2110701, 1066, 10, 14);
|
||||
checkJDN(1721417, 0, 12, 25);
|
||||
checkJDN(0, -4712, 1, 1);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,21 +1,69 @@
|
|||
export function gregorianJDN(year: number, month: number, day: number): number {
|
||||
export type JulianMonth = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
|
||||
export type JulianDay =
|
||||
| 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
|
||||
| 31;
|
||||
|
||||
export type JulianDate = [number, JulianMonth, JulianDay];
|
||||
|
||||
export function gregorianJDN(year: number, month: number, day: number, julian_before?: number): number {
|
||||
const g = year + 4716 - (month <= 2 ? 1 : 0);
|
||||
const f = (month + 9) % 12;
|
||||
const e = Math.floor(1461 * g / 4) + day - 1402;
|
||||
const J = e + Math.floor((153 * f + 2) / 5);
|
||||
|
||||
if (julian_before != null && J < julian_before)
|
||||
return J;
|
||||
|
||||
const dg = 38 - Math.floor(Math.floor((g + 184) / 100) * 3 / 4);
|
||||
return J + dg;
|
||||
}
|
||||
|
||||
export function dateJDN(date: Date) {
|
||||
return gregorianJDN(date.getFullYear(), date.getMonth() + 1, date.getDate());
|
||||
export function dateJDN(date: Date, julian_before?: number) {
|
||||
return gregorianJDN(date.getFullYear(), date.getMonth() + 1, date.getDate(), julian_before);
|
||||
}
|
||||
|
||||
export function jdnGregorian(jdn: number): Date {
|
||||
const e = 4 * (jdn + 1401 + Math.floor(Math.floor((4 * jdn + 274277) / 146097) * 3 / 4) - 38) + 3;
|
||||
export function jdnGregorian(jdn: number, julian_before?: number): JulianDate {
|
||||
const dg = julian_before == null || jdn >= julian_before ?
|
||||
Math.floor(Math.floor((4 * jdn + 274277) / 146097) * 3 / 4) - 38 :
|
||||
0;
|
||||
const e = 4 * (jdn + 1401 + dg) + 3;
|
||||
const h = 5 * Math.floor((e % 1461 + 1461) % 1461 / 4) + 2;
|
||||
const day = Math.floor((h % 153 + 153) % 153 / 5) + 1;
|
||||
const month = (Math.floor(h / 153) + 2) % 12 + 1;
|
||||
const year = Math.floor(e / 1461) - 4716 + Math.floor((14 - month) / 12);
|
||||
return [year, month as JulianMonth, day as JulianDay];
|
||||
}
|
||||
|
||||
export function jdnDate(jdn: number, julian_before?: number): Date {
|
||||
const [year, month, day] = jdnGregorian(jdn, julian_before);
|
||||
return new Date(year, month - 1, day);
|
||||
}
|
||||
|
|
25
common/src/julian.test.ts
Normal file
25
common/src/julian.test.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import {jdnJulian, julianJDN} from './julian';
|
||||
|
||||
describe('gregorianJDN', () => {
|
||||
it('works', () => {
|
||||
expect(julianJDN(2000, 1, 1)).toBe(2451558);
|
||||
expect(julianJDN(1969, 7, 20)).toBe(2440436);
|
||||
expect(julianJDN(1582, 10, 15)).toBe(2299171);
|
||||
expect(julianJDN(1582, 10, 4)).toBe(2299160);
|
||||
expect(julianJDN(1066, 10, 14)).toBe(2110701);
|
||||
expect(julianJDN(0, 12, 25)).toBe(1721417);
|
||||
expect(julianJDN(-4712, 1, 1)).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('jdnGregorian', () => {
|
||||
it('works', () => {
|
||||
expect(jdnJulian(2451558)).toEqual([2000, 1, 1]);
|
||||
expect(jdnJulian(2440436)).toEqual([1969, 7, 20]);
|
||||
expect(jdnJulian(2299171)).toEqual([1582, 10, 15]);
|
||||
expect(jdnJulian(2299160)).toEqual([1582, 10, 4]);
|
||||
expect(jdnJulian(2110701)).toEqual([1066, 10, 14]);
|
||||
expect(jdnJulian(1721417)).toEqual([0, 12, 25]);
|
||||
expect(jdnJulian(0)).toEqual([-4712, 1, 1]);
|
||||
});
|
||||
});
|
9
common/src/julian.ts
Normal file
9
common/src/julian.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import {gregorianJDN, jdnGregorian, JulianDate} from './gregorian';
|
||||
|
||||
export function julianJDN(year: number, month: number, day: number): number {
|
||||
return gregorianJDN(year, month, day, Infinity);
|
||||
}
|
||||
|
||||
export function jdnJulian(jdn: number): JulianDate {
|
||||
return jdnGregorian(jdn, Infinity);
|
||||
}
|
|
@ -80,8 +80,8 @@ class App extends React.Component<{}, AppState> {
|
|||
}
|
||||
|
||||
validYear() {
|
||||
return /^-?\d+$/.test(this.state.goYear) && startGregorian.getFullYear() <= +this.state.goYear &&
|
||||
+this.state.goYear <= endGregorian.getFullYear();
|
||||
return /^-?\d+$/.test(this.state.goYear) && startGregorian[0] <= +this.state.goYear &&
|
||||
+this.state.goYear <= endGregorian[0];
|
||||
}
|
||||
|
||||
validMonth() {
|
||||
|
@ -112,7 +112,7 @@ class App extends React.Component<{}, AppState> {
|
|||
|
||||
onDateChange = (todayJDN: number) => {
|
||||
this.setState({todayJDN});
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
return <>
|
||||
|
@ -130,7 +130,7 @@ class App extends React.Component<{}, AppState> {
|
|||
<span className="input-group-text">Gregorian<span className="hide-small"> Date</span></span>
|
||||
<input type="number" className={`form-control go-year ${this.validYear() ? '' : 'is-invalid'}`}
|
||||
onChange={this.changeField.bind(this, 'goYear')} value={this.state.goYear}
|
||||
min={startGregorian.getFullYear()} max={endGregorian.getFullYear()}/>
|
||||
min={startGregorian[0]} max={endGregorian[0]}/>
|
||||
<input type="number" className={`form-control go-month ${this.validMonth() ? '' : 'is-invalid'}`}
|
||||
onChange={this.changeField.bind(this, 'goMonth')} value={this.state.goMonth}
|
||||
min={1} max={12}/>
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
monthName,
|
||||
startYear,
|
||||
} from '@common/french';
|
||||
import {jdnGregorian} from '@common/gregorian';
|
||||
import {jdnDate} from '@common/gregorian';
|
||||
import {jdnLongCount} from '@common/longCount';
|
||||
|
||||
type MonthProps = {
|
||||
|
@ -31,7 +31,7 @@ function DecadeName({name}: { name: string }): JSX.Element {
|
|||
|
||||
function DayDetail({jdn}: { jdn: number }): JSX.Element {
|
||||
return <div className="DayDetail">
|
||||
<div className="DayDetail-gregorian">{jdnGregorian(jdn).toDateString()}</div>
|
||||
<div className="DayDetail-gregorian">{jdnDate(jdn).toDateString()}</div>
|
||||
<div className="DayDetail-lc">{jdnLongCount(jdn)}</div>
|
||||
</div>;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue