v0.2.5: parse live-session date format so the countdown actually posts
All checks were successful
build-apk / build (push) Successful in 36m28s

The active-session endpoint (/api/ParkingSession) returns EndTime as
"MM/DD/YYYY HH:MM:SS" (slashes, 24h, seconds), but parseApiTime only matched
the past-session "MM-DD-YYYY hh:mm AM/PM" form. Hermes' Date() can't parse
either, so live sessions parsed to null, got filtered out, and
refreshSessionStatus cleared the notification instead of posting it (log
showed "active sessions raw" but never "show native=").

parseApiTime now accepts both: - or / separators, optional seconds, optional
AM/PM (24h when absent). Added a "[STATUS] parsed N future-end session(s)" log.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-15 22:49:34 +00:00
parent 2b973348bc
commit deb78bf952
2 changed files with 21 additions and 8 deletions

View file

@ -3,14 +3,14 @@
"name": "BigBrainParking", "name": "BigBrainParking",
"slug": "bigbrainparking", "slug": "bigbrainparking",
"scheme": "bigbrainparking", "scheme": "bigbrainparking",
"version": "0.2.4", "version": "0.2.5",
"orientation": "portrait", "orientation": "portrait",
"userInterfaceStyle": "automatic", "userInterfaceStyle": "automatic",
"newArchEnabled": true, "newArchEnabled": true,
"icon": "./assets/icon.png", "icon": "./assets/icon.png",
"android": { "android": {
"package": "top.mowden.bigbrainparking", "package": "top.mowden.bigbrainparking",
"versionCode": 14, "versionCode": 15,
"edgeToEdgeEnabled": true, "edgeToEdgeEnabled": true,
"adaptiveIcon": { "adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png", "foregroundImage": "./assets/adaptive-icon.png",

View file

@ -29,19 +29,31 @@ async function ensureExpoChannel(): Promise<void> {
}); });
} }
/** Parse the API's "MM-DD-YYYY hh:mm AM/PM" time into a Date. */ /**
* Parse a ParkSmarter date into a local Date. The API uses TWO formats:
* /api/Session (past): "07-15-2026 05:00 PM" dashes, 12h, AM/PM
* /api/ParkingSession (live): "07/15/2026 17:00:00" slashes, 24h, seconds
* Both are device-local wall-clock time. Hermes' Date() can't parse either, so
* we build the Date from explicit components.
*/
export function parseApiTime(s?: string | null): Date | null { export function parseApiTime(s?: string | null): Date | null {
if (!s) return null; if (!s) return null;
const m = String(s).match(/(\d{1,2})-(\d{1,2})-(\d{4})\s+(\d{1,2}):(\d{2})\s*(AM|PM)/i); const m = String(s).match(
/(\d{1,2})[-/](\d{1,2})[-/](\d{4})\s+(\d{1,2}):(\d{2})(?::(\d{2}))?\s*(AM|PM)?/i,
);
if (!m) { if (!m) {
const d = new Date(s); const d = new Date(s);
return Number.isNaN(+d) ? null : d; return Number.isNaN(+d) ? null : d;
} }
let hr = parseInt(m[4], 10); let hr = parseInt(m[4], 10);
const pm = /pm/i.test(m[6]); const ap = m[7];
if (ap) {
const pm = /pm/i.test(ap);
if (pm && hr !== 12) hr += 12; if (pm && hr !== 12) hr += 12;
if (!pm && hr === 12) hr = 0; if (!pm && hr === 12) hr = 0;
return new Date(+m[3], +m[1] - 1, +m[2], hr, +m[5]); }
const sec = m[6] ? parseInt(m[6], 10) : 0;
return new Date(+m[3], +m[1] - 1, +m[2], hr, +m[5], sec);
} }
function fmtLeft(min: number): string { function fmtLeft(min: number): string {
@ -123,6 +135,7 @@ export async function refreshSessionStatus(): Promise<void> {
.map((s: any) => ({ s, end: parseApiTime(s.EndTime ?? s.EndTimeDisplay) })) .map((s: any) => ({ s, end: parseApiTime(s.EndTime ?? s.EndTimeDisplay) }))
.filter((x) => x.end != null && x.end.getTime() > Date.now()) .filter((x) => x.end != null && x.end.getTime() > Date.now())
.sort((a, b) => a.end!.getTime() - b.end!.getTime()); .sort((a, b) => a.end!.getTime() - b.end!.getTime());
logLine(`[STATUS] parsed ${withEnd.length} future-end session(s) of ${(res.ParkingSession ?? []).length}`);
if (withEnd.length === 0) { if (withEnd.length === 0) {
await clearSessionStatus(); await clearSessionStatus();
return; return;