diff --git a/src/App.tsx b/src/App.tsx index f2749fd..b1a5f10 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,7 @@ import React, {FormEvent} from 'react'; import {Calendar} from './Calendar'; import {endGregorian, endJD, frSupportedYear, gregorianJDN, jdnFrench, Month, startGregorian, startJD} from './dates'; +import {TimeOfDay} from './TimeOfDay'; type YearMonth = { year: number; @@ -101,6 +102,10 @@ class App extends React.Component<{}, AppState> { }); } + onDateChange = (todayJDN: number) => { + this.setState({todayJDN}); + } + render() { return <> { this.setState({year, month}); }}/> + +

Go to a date

diff --git a/src/TimeOfDay.scss b/src/TimeOfDay.scss new file mode 100644 index 0000000..87e4ef4 --- /dev/null +++ b/src/TimeOfDay.scss @@ -0,0 +1,33 @@ +@import 'bootstrap/scss/functions'; +@import 'bootstrap/scss/variables'; +@import 'bootstrap/scss/mixins'; +@import 'bootstrap/scss/forms'; +@import 'bootstrap/scss/grid'; +@import 'bootstrap/scss/buttons'; +@import './consts'; + +.TimeOfDay { + @include make-container(); +} + +.TimeOfDay-Rows { + @include make-row(); + + > * { + @include make-col-ready(); + } +} + +.TimeOfDay-Style { + strong::after { + content: ' '; + } + + @include make-col(); +} + +@include media-breakpoint-up(lg) { + .TimeOfDay-Rows { + display: block; + } +} diff --git a/src/TimeOfDay.tsx b/src/TimeOfDay.tsx new file mode 100644 index 0000000..abc086e --- /dev/null +++ b/src/TimeOfDay.tsx @@ -0,0 +1,125 @@ +import React from 'react'; +import './TimeOfDay.scss'; +import {gregorianJDN} from './dates'; + +type TimeStamp = { + hour: number, + minute: number, + second: number, +}; + +type DecimalTimeStamp = TimeStamp; +type NormalTimeStamp = TimeStamp; + +function currentDayMs(): number { + const now = new Date(); + return now.getHours() * 3_600_000 + now.getMinutes() * 60_000 + now.getSeconds() * 1000 + now.getMilliseconds(); +} + +export function dayMsToDecimal(dayMs: number): DecimalTimeStamp { + const dayFrac = dayMs / 86_400_000; + const hour = Math.floor(dayFrac * 10); + const minute = Math.floor(dayFrac * 10 % 1 * 100); + const second = Math.floor(dayFrac * 1000 % 1 * 100); + return {hour, minute, second}; +} + +export function decimalToDayMs({hour, minute, second}: DecimalTimeStamp): number { + return 864 * (hour * 10_000 + minute * 100 + second); +} + +function timePad(value: number): string { + return value.toString().padStart(2, '0'); +} + +type TimeOfDayProps = { + onDateChange?: (jdn: number) => void, +}; + +type TimeOfDayState = { + decimal: DecimalTimeStamp, + decimalTimer: number, + normal: NormalTimeStamp, + normalTimer: number, + jdn: number, +}; + +export class TimeOfDay extends React.Component { + constructor(props: TimeOfDayProps) { + super(props); + const zero = {hour: 0, minute: 0, second: 0}; + this.state = { + decimal: zero, + decimalTimer: 0, + normal: zero, + normalTimer: 0, + jdn: 0, + }; + } + + componentDidMount() { + this.updateDecimalTime(); + this.updateNormalTime(); + } + + componentWillUnmount() { + if (this.state.decimalTimer) { + clearTimeout(this.state.decimalTimer); + } + if (this.state.normalTimer) { + clearTimeout(this.state.normalTimer); + } + this.setState({decimalTimer: 0, normalTimer: 0}); + } + + updateDecimalTime = () => { + const now = currentDayMs(); + const {hour, minute, second} = dayMsToDecimal(now); + const nextTick = decimalToDayMs({hour, minute, second: second + 1}); + const decimalTimer = window.setTimeout(this.updateDecimalTime, nextTick - now); + this.setState({decimal: {hour, minute, second}, decimalTimer}); + } + + updateNormalTime = () => { + const now = new Date(); + const jdn = gregorianJDN(now.getFullYear(), now.getMonth() + 1, now.getDate()); + if (this.props.onDateChange && jdn !== this.state.jdn) { + this.props.onDateChange(jdn); + } + + const normalTimer = window.setTimeout(this.updateNormalTime, 1000 - now.getMilliseconds()); + this.setState({ + normal: { + hour: now.getHours(), + minute: now.getMinutes(), + second: now.getSeconds() + }, + normalTimer, + jdn, + }); + } + + render() { + return
+

Time of Day

+
+
+ Decimal time: + + {this.state.decimal.hour}: + {timePad(this.state.decimal.minute)}: + {timePad(this.state.decimal.second)} + +
+
+ 24-hour time: + + {timePad(this.state.normal.hour)}: + {timePad(this.state.normal.minute)}: + {timePad(this.state.normal.second)} + +
+
+
; + } +}