%
/* ---- Next occurrence -------------------------------------------------
All arithmetic happens on a UTC Date that carries the *Eastern calendar
date*, never a wall-clock instant. That keeps day-of-week and day-adding
correct across DST without needing a timezone library. public/js/main.js
runs the same rule so the live countdown agrees with this render and can
roll itself over without a reload. */
const TZ = site.timezone || "America/New_York";
const now = new Date();
const V = site.venue;
const todayISO = new Intl.DateTimeFormat("en-CA", {
timeZone: TZ, year: "numeric", month: "2-digit", day: "2-digit",
}).format(now);
const hourET = Number(
new Intl.DateTimeFormat("en-US", { timeZone: TZ, hour: "2-digit", hourCycle: "h23" }).format(now)
) % 24;
const toDate = (iso) => { const [y, m, d] = iso.split("-").map(Number); return new Date(Date.UTC(y, m - 1, d)); };
const isoOf = (dt) => dt.toISOString().slice(0, 10);
let next = toDate(todayISO);
const first = toDate(site.firstEvent);
if (next < first) next = first;
while (next.getUTCDay() !== site.weekday) next.setUTCDate(next.getUTCDate() + 1);
if (isoOf(next) === todayISO && hourET >= (site.endHour24 || 21)) next.setUTCDate(next.getUTCDate() + 7);
// Keep the FIRST skipped date: with two cancellations in a row the notice
// should name the soonest one people were expecting, not the last one.
const cancelled = site.cancelled || [];
let skippedWeek = null;
while (cancelled.includes(isoOf(next))) {
if (!skippedWeek) skippedWeek = isoOf(next);
next.setUTCDate(next.getUTCDate() + 7);
}
const nextISO = isoOf(next);
const isTonight = nextISO === todayISO;
const fmtDate = (opts) => new Intl.DateTimeFormat("en-US", Object.assign({ timeZone: "UTC" }, opts)).format(next);
const nextLong = fmtDate({ weekday: "long", month: "long", day: "numeric" });
const nextShort = fmtDate({ weekday: "short", month: "short", day: "numeric" });
const weekdayName = new Intl.DateTimeFormat("en-US", { timeZone: "UTC", weekday: "long" }).format(next);
// Eastern UTC offset on the event date, so the countdown target is a real instant.
const offLabel = new Intl.DateTimeFormat("en-US", { timeZone: TZ, timeZoneName: "shortOffset" })
.format(new Date(`${nextISO}T12:00:00Z`));
const offHours = Number((offLabel.match(/GMT([+-]?\d{1,2})/) || [, "-5"])[1]);
const pad = (n) => String(n).padStart(2, "0");
const offStr = `${offHours < 0 ? "-" : "+"}${pad(Math.abs(offHours))}:00`;
const startISO = `${nextISO}T${pad(site.startHour24)}:00:00${offStr}`;
const endISO = `${nextISO}T${pad(site.endHour24)}:00:00${offStr}`;
const heroLine = isTonight
? `Tonight at ${V.name}, ${site.startTime} to ${site.endTime}. Grab a cue and meet the people building things in ${V.city}.`
: `Every ${weekdayName} at ${V.name}, ${site.startTime} to ${site.endTime}. The next one is ${nextLong}.`;
const details = [
{ label: "When", value: `Every ${weekdayName}` },
{ label: "Time", value: `${site.startTime} to ${site.endTime}` },
{ label: "Where", value: `${V.name}, ${V.street}`, href: V.mapUrl },
{ label: "Entry", value: site.entry },
];
%>
<%= isTonight ? "The Break is tonight" : "Until the next Break" %>
-days
-hours
-min
-sec
<%= nextLong %>, <%= site.startTime %> at <%= V.name %>
<% if (skippedWeek) { %>
No Break on <%= new Intl.DateTimeFormat("en-US", { timeZone: "UTC", month: "long", day: "numeric" }).format(toDate(skippedWeek)) %>. Back on <%= nextLong %>.
We are building Gainesville's startup culture, one terrible pool shot at a time.
Whether you are an engineer, a designer, a business strategist, or just an ambitious person driven to build things from the ground up, this is your crowd.
Zero pool skills required. Seriously. We are here to build startups, not run the table.
Not required, but it helps us know how many tables to hold. We will email you a reminder the day before.
Point a phone at this.
It opens straight to the RSVP. Screenshot it and send it to whoever should be there.
You are on the list.
Check your inbox for a confirmation. See you <%= isTonight ? "tonight" : nextLong %> at <%= V.name %>, <%= V.street %>, <%= site.startTime %>. Bring your ideas and a valid ID.