Add the time converter utility

ElementalAlchemist 2 weeks ago
parent ea438c73db
commit 1c842d9d16

@ -0,0 +1,96 @@
import { l } from "vite/dist/node/types.d-aGj9QkWt";
import { DateTime } from "../external/luxon.min";
export function dateTimeFromWubloaderTime(wubloaderTime: string): DateTime | null {
const dt = DateTime.fromISO(wubloaderTime);
if (dt.isValid) {
return dt;
}
return null;
}
export function wubloaderTimeFromDateTime(dateTime: DateTime): string {
// Not using ISO here because Luxon doesn't give us a quick way to print an ISO8601 string with no offset.
return dateTime.toFormat("yyyy-LL-dd'T'HH:mm:ss.SSS");
}
class DateTimeMathObject {
hours: number;
minutes: number;
seconds: number;
}
function dateTimeMathObjectFromBusTime(busTime: string): DateTimeMathObject | null {
// We need to handle inputs like "-0:10:15" in a way that consistently makes the time negative.
// Since we can't assign the negative sign to any particular part, we'll check for the whole thing here.
let direction = 1;
if (busTime.startsWith("-")) {
busTime = busTime.slice(1);
direction = -1;
}
const parts = busTime.split(":", 3);
const hours = parseInt(parts[0], 10) * direction;
const minutes = parts.length > 1 ? parseInt(parts[1], 10) * direction : 0;
const seconds = parts.length > 2 ? parseInt(parts[2], 10) * direction : 0;
return { hours: hours, minutes: minutes, seconds: seconds };
}
export function dateTimeFromBusTime(busStartTime: DateTime, busTime: string): DateTime | null {
const busMathObject = dateTimeMathObjectFromBusTime(busTime);
if (busMathObject === null) {
return null;
}
return busStartTime.plus(busMathObject);
}
export function busTimeFromDateTime(busStartTime: DateTime, time: DateTime): string {
const diff = time.diff(busStartTime);
if (diff.milliseconds < 0) {
const negativeInterval = diff.negate();
return `-${negativeInterval.toFormat("hh:mm:ss.SSS")}`;
}
return diff.toFormat("hh:mm:ss.SSS");
}
export function dateTimeFromTimeAgo(timeAgo: string): DateTime | null {
const parts = timeAgo.split(":");
const properties = ["hours", "minutes", "seconds"];
const mathObj = {};
while (parts.length > 0) {
const nextPart = parts.pop();
if (properties.length === 0) {
return null;
}
const nextProp = properties.pop();
const partNumber = parseInt(nextPart, 10);
if (isNaN(partNumber)) {
return null;
}
mathObj[nextProp] = partNumber;
}
const now = DateTime.utc();
return now.plus(mathObj);
}
export function timeAgoFromDateTime(dateTime: DateTime): string {
const currentTime = DateTime.utc();
const interval = currentTime.diff(dateTime, "seconds");
let timeAgoSeconds = interval.seconds;
let negative = "";
if (timeAgoSeconds < 0) {
negative = "-";
timeAgoSeconds = -timeAgoSeconds;
}
const seconds = (((timeAgoSeconds % 60) * 1000) | 0) / 1000
const secondsString = seconds < 10 ? `0${seconds}` : seconds.toString();
const minutes = (timeAgoSeconds / 60) % 60 | 0;
const minutesString = minutes < 10 ? `0${minutes}` : minutes.toString();
const hours = Math.floor(timeAgoSeconds / 3600);
return `${negative}${hours}:${minutesString}:${secondsString}`;
}

@ -1,19 +1,17 @@
import { Component, createSignal, onCleanup, onMount } from "solid-js"; import { Accessor, Component, createSignal, onCleanup, onMount } from "solid-js";
import { DateTime, Interval } from "../external/luxon.min"; import { DateTime, Interval } from "../external/luxon.min";
const Clock: Component = () => { interface ClockProps {
busStartTime: Accessor<DateTime | null>;
}
const Clock: Component<ClockProps> = (props) => {
const [delay, setDelay] = createSignal<number>(10); const [delay, setDelay] = createSignal<number>(10);
const [time, setTime] = createSignal<DateTime>(DateTime.utc()); const [time, setTime] = createSignal<DateTime>(DateTime.utc());
const [busStartTime, setBusStartTime] = createSignal<DateTime | null>(null); const busStartTime = props.busStartTime;
const timer = setInterval(() => setTime(DateTime.utc()), 250); const timer = setInterval(() => setTime(DateTime.utc()), 250);
onMount(async () => {
const dataResponse = await fetch("/thrimshim/defaults");
const data = await dataResponse.json();
setBusStartTime(DateTime.fromISO(data.bustime_start));
});
onCleanup(() => { onCleanup(() => {
clearInterval(timer); clearInterval(timer);
}); });

@ -0,0 +1,136 @@
import { Accessor, Component, createSignal } from "solid-js";
import { DateTime } from "../external/luxon.min";
import {
dateTimeFromWubloaderTime,
dateTimeFromBusTime,
dateTimeFromTimeAgo,
wubloaderTimeFromDateTime,
busTimeFromDateTime,
timeAgoFromDateTime,
} from "../common/convertTime";
interface TimeConverterProps {
busStartTime: Accessor<DateTime | null>;
}
enum TimeType {
UTC,
BusTime,
TimeAgo,
}
const TimeConverter: Component<TimeConverterProps> = (props) => {
const [enteredTime, setEnteredTime] = createSignal<string>("");
const [startTimeType, setStartTimeType] = createSignal<TimeType>(TimeType.UTC);
const [outputTimeType, setOutputTimeType] = createSignal<TimeType>(TimeType.UTC);
const outputString = (): string => {
const busStartTime = props.busStartTime();
if (busStartTime === null) {
return "";
}
const startType = startTimeType();
let dateTime: DateTime | null = null;
if (startType === TimeType.UTC) {
dateTime = dateTimeFromWubloaderTime(enteredTime());
} else if (startType === TimeType.BusTime) {
dateTime = dateTimeFromBusTime(busStartTime, enteredTime());
} else if (startType === TimeType.TimeAgo) {
dateTime = dateTimeFromTimeAgo(enteredTime());
}
if (dateTime === null) {
return "";
}
const outputType = outputTimeType();
if (outputType === TimeType.UTC) {
return wubloaderTimeFromDateTime(dateTime);
}
if (outputType === TimeType.BusTime) {
return busTimeFromDateTime(busStartTime, dateTime);
}
if (outputType === TimeType.TimeAgo) {
return timeAgoFromDateTime(dateTime);
}
return "";
};
return (
<form>
<h1>Convert Times</h1>
<input
type="text"
placeholder="Time to convert"
value={enteredTime()}
onInput={(event) => {
setEnteredTime(event.currentTarget.value);
}}
/>
<div>
From:
<label>
<input
name="time-converter-from"
type="radio"
value={TimeType.UTC}
checked={true}
onClick={(event) => setStartTimeType(TimeType.UTC)}
/>
UTC
</label>
<label>
<input
name="time-converter-from"
type="radio"
value={TimeType.BusTime}
onClick={(event) => setStartTimeType(TimeType.BusTime)}
/>
Bus Time
</label>
<label>
<input
name="time-converter-from"
type="radio"
value={TimeType.TimeAgo}
onClick={(event) => setStartTimeType(TimeType.TimeAgo)}
/>
Time Ago
</label>
</div>
<div>
To:
<label>
<input
name="time-converter-to"
type="radio"
checked={true}
value={TimeType.UTC}
onClick={(event) => setOutputTimeType(TimeType.UTC)}
/>
UTC
</label>
<label>
<input
name="time-converter-to"
type="radio"
value={TimeType.BusTime}
onClick={(event) => setOutputTimeType(TimeType.BusTime)}
/>
Bus Time
</label>
<label>
<input
name="time-converter-to"
type="radio"
value={TimeType.TimeAgo}
onClick={(event) => setOutputTimeType(TimeType.TimeAgo)}
/>
Time Ago
</label>
</div>
<div>Converted Time: {outputString()}</div>
</form>
);
};
export default TimeConverter;

@ -1,10 +1,21 @@
import { Component } from "solid-js"; import { Component, createSignal, onMount } from "solid-js";
import { DateTime } from "../external/luxon.min";
import Clock from "./Clock"; import Clock from "./Clock";
import TimeConverter from "./TimeConverter";
const Utilities: Component = () => { const Utilities: Component = () => {
const [busStartTime, setBusStartTime] = createSignal<DateTime | null>(null);
onMount(async () => {
const dataResponse = await fetch("/thrimshim/defaults");
const data = await dataResponse.json();
setBusStartTime(DateTime.fromISO(data.bustime_start));
});
return ( return (
<> <>
<Clock /> <Clock busStartTime={busStartTime} />
<TimeConverter busStartTime={busStartTime} />
</> </>
); );
}; };

@ -11,6 +11,7 @@ export default defineConfig({
}, },
build: { build: {
target: "esnext", target: "esnext",
// minify: false, // Uncomment this line if you need to debug unminified code
rollupOptions: { rollupOptions: {
input: { input: {
index: fileURLToPath(new URL("index.html", import.meta.url)), index: fileURLToPath(new URL("index.html", import.meta.url)),

Loading…
Cancel
Save