Implement handling of complementary days

This commit is contained in:
Quantum 2022-02-12 16:58:32 -05:00
parent 2c3657248b
commit dc435b7870
4 changed files with 66 additions and 5 deletions

View file

@ -64,6 +64,24 @@
}
}
@include media-breakpoint-up(lg) {
.ComplementaryDays {
@include make-row();
> * {
@include make-col-ready();
}
}
.ComplementaryDay {
@include make-col($columns: 2);
}
.ComplementaryDays-splitter {
width: 100%;
}
}
.Day, .DecadeName {
margin: 0.5em;
@include make-col($columns: 10);

View file

@ -1,6 +1,6 @@
import React from 'react';
import './Calendar.scss';
import {Day, decadeNames, frJDN, jdnGregorian, jdnLongCount, Month, monthName} from './dates';
import {dateName, Day, decadeNames, frIsLeap, frJDN, jdnGregorian, jdnLongCount, Month, monthName} from './dates';
type MonthProps = {
year: number;
@ -53,9 +53,26 @@ function NormalMonth({year, month, todayJDN}: MonthProps & { todayJDN: number })
</div>;
}
function ComplementaryDay({year, month, day, todayJDN}: DateProps & { todayJDN: number }): JSX.Element {
const jdn = frJDN(year, month, day);
return <div className={`Day ComplementaryDay ${jdn === todayJDN ? 'Day-today' : ''}`}>
<div className="Day-name">{dateName(month, day)}</div>
<DayDetail jdn={jdn}/>
</div>;
}
function ComplementaryDays({year, todayJDN}: {year: number, todayJDN: number}): JSX.Element {
return <div className="ComplementaryDays">{
Array.from(Array(frIsLeap(year) ? 6 : 5).keys()).map(i => <>
<ComplementaryDay year={year} month={13} day={i + 1 as Day} todayJDN={todayJDN}/>
{i % 2 === 1 && <div className="ComplementaryDays-splitter"/>}
</>)
}</div>;
}
export class Calendar extends React.Component<CalendarProps, CalendarState> {
private goToNormalized(year: number, month: number) {
if (month < 0) {
if (month < 1) {
--year;
month += 13;
}
@ -95,7 +112,9 @@ export class Calendar extends React.Component<CalendarProps, CalendarState> {
onClick={this.prevMonth.bind(this)}>
</button>
</div>
<div className="Calendar-month-name">{monthName(this.props.month)} {this.props.year}</div>
<div className="Calendar-month-name">
{this.props.month < 13 && monthName(this.props.month)} {this.props.year}
</div>
<div className="Calendar-next">
<button type="button" className="btn btn-secondary" title="Next month"
onClick={this.nextMonth.bind(this)}>
@ -105,7 +124,8 @@ export class Calendar extends React.Component<CalendarProps, CalendarState> {
</button>
</div>
</div>
<NormalMonth year={this.props.year} month={this.props.month} todayJDN={this.props.todayJDN}/>
{this.props.month < 13 && <NormalMonth year={this.props.year} month={this.props.month} todayJDN={this.props.todayJDN}/>}
{this.props.month === 13 && <ComplementaryDays year={this.props.year} todayJDN={this.props.todayJDN}/>}
</div>;
}
}

View file

@ -1,4 +1,4 @@
import {dateName, frJDN, gregorianJDN, jdnFrench, jdnGregorian, jdnLongCount, monthName} from './dates';
import {dateName, frIsLeap, frJDN, gregorianJDN, jdnFrench, jdnGregorian, jdnLongCount, monthName} from './dates';
describe('gregorianJDN', () => {
it('works', () => {
@ -30,6 +30,25 @@ describe('frJDN', () => {
});
});
describe('frIsLeap', () => {
it('works for sample dates', () => {
expect(frIsLeap(1)).toBeFalsy();
expect(frIsLeap(8)).toBeFalsy();
expect(frIsLeap(3)).toBeTruthy();
expect(frIsLeap(7)).toBeTruthy();
expect(frIsLeap(11)).toBeTruthy();
});
it('works in years starting/ending near midnight', () => {
expect(frIsLeap(110)).toBeTruthy();
expect(frIsLeap(205)).toBeTruthy();
expect(frIsLeap(2489)).toBeFalsy();
expect(frIsLeap(111)).toBeFalsy();
expect(frIsLeap(206)).toBeFalsy();
expect(frIsLeap(2490)).toBeTruthy();
});
});
describe('jdnFrench', () => {
it('works for sample dates', () => {
expect(jdnFrench(2375840)).toEqual({year: 1, month: 1, day: 1});

View file

@ -87,6 +87,10 @@ export function frJDN(year: number, month: Month, day: Day): number {
return startJD + 365 * dy + leaps[dy] + dd;
}
export function frIsLeap(year: number): boolean {
return !!data.leap[year - startYear];
}
export function jdnGregorian(jdn: number): Date {
const e = 4 * (jdn + 1401 + Math.floor(Math.floor((4 * jdn + 274277) / 146097) * 3 / 4) - 38) + 3;
const h = 5 * Math.floor((e % 1461 + 1461) % 1461 / 4) + 2;