DEV Community

Cover image for Gemma got 3 of 22 contest deadlines right in Taiwan time. Now it only copies, and code does the math
Hua-I Yu
Hua-I Yu

Posted on AI-assisted

Gemma got 3 of 22 contest deadlines right in Taiwan time. Now it only copies, and code does the math

Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady Submission 🦥

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady

The Bound Jam page on itch.io has a schedule that says the jam ends Nov 1, 18:00 CET. The same page has a countdown timer, and the time behind that timer is 2026-11-01 17:55:25 UTC. In Taiwan, the first one is 01:00 on November 2. The second one is 01:55. I almost put the wrong one in my calendar.

I'm a 20-year-old information management student in Taiwan, and for the last month or so I've been entering online contests. My tracker says I've submitted 83. Almost every one of them had a deadline written for somebody else's clock: 11:59 PM PDT, 2:00pm PST, 23:59 UTC, "11:59pm Anywhere on Earth". For each one I opened a converter, checked whether daylight saving had ended in that country yet, typed the result into my notes, and then typed it again into Google Calendar.

This week's theme is laziness, so I built the thing I wanted: paste the rules page, get the deadlines in my own time, press one button to get a calendar file.

What I Built

Deadline Calendar is one web page. You paste a contest's rules page (or send it with a bookmark), and you get back every date on it, converted to your time zone, each with the line it came from. One button downloads an .ics file. Each event in it is a block from 30 minutes before the deadline to the deadline, with reminders 3 days and 3 hours before. Every row that passes the checks gets those reminders, except a start date when the same page has a later date. Each row also has an "Add to Google Calendar" link. Google's link has no field for reminders, so an event added that way gets your Google Calendar's default notification instead.

Deadline Calendar reading a Devpost page live: Gemma 4 runs on my GPU, the deadline

Gemma 4 E2B runs inside the page on your own GPU. It doesn't convert anything. It reads the lines with dates on them and copies out three pieces of text for each event: the date, the clock time and the time zone, exactly as the page writes them. Everything else is plain JavaScript:

  1. Every quote is looked up on the page. If the date isn't on the page in any form, it's thrown out and shown in a red box.
  2. A parser reads the date and time from the quote. A table maps zone words (PDT, CET, AoE, Pacific Time, 日本時間) to a fixed offset or a region.
  3. Luxon and the browser's time zone database do the conversion, so the tz database decides whether daylight saving applies on that exact date.
  4. If the page names no time zone at all, the date is listed but kept off the calendar instead of guessed.

That last rule is the Bound Jam case. Gemma found the countdown's 17:55:25 too, but nothing on that line says UTC, so the tool shows it as "zone not stated" and keeps it off the calendar. Two Bound Jam rows do go in. One is Oct 1, 18:00 CEST from the schedule, which Gemma called "Schedule". The other is the deadline, Nov 1, 18:00 CET, which Gemma titled "Build Your Game" and gave the kind "other". My first version only put reminders on rows of kind "deadline", so the one date I needed had none. Now every row that passes the checks gets them, and the Bound Jam deadline has its 3-day and 3-hour reminders.

Demo

Live: deadline-calendar-murex.vercel.app

  • Recorded runs (the default tab) has eight real pages from my test. The Gemma outputs were saved during the test run, and the quote checker and the time zone code run live on them in your browser. Change "Your time zone" and every row moves. Under each example you can also see what the same Gemma said when I asked it for the Taiwan time directly. This tab works on any browser, phones included.
  • Run Gemma 4 here downloads the model once (about 2.8 GB) and reads any page you paste. It needs Chrome or Edge with WebGPU. In my test the median reply took 11.6 seconds on my laptop's RTX 4050.

Most sites don't let another web page read them, so the address box usually can't fetch the page. You can press Ctrl+A, Ctrl+C on the rules page and paste. Or drag the "Send to Deadline Calendar" link to your bookmarks bar: clicking it on a rules page copies the page's text and opens the tool with it filled in.

Code

Deadline Calendar

Paste a contest rules page. Gemma 4 E2B runs in your browser and points at the dates. Plain code checks every quote against the page, converts the time zones with Luxon and writes an .ics file, or one Google Calendar link per date.

Live: https://deadline-calendar-murex.vercel.app

How it works

  1. src/core/lines.js keeps only the lines that contain a date, plus the short label above each one. Both the reader and the baseline read exactly this excerpt.
  2. Gemma 4 E2B (gemma-4-E2B-it-q4f16_1-MLC, WebLLM 0.2.86) copies each date, time and zone exactly as written. The answer is held to a grammar (src/core/prompts.js).
  3. src/core/pipeline.js looks every quote up on the page. A date that isn't there is thrown out. If Gemma rewrote a date that is on the page in other words ("October 29, 2026" for "29 October 2026"), the page's own words are used and the row says so.
  4. …

MIT licensed. src/core/ is the part that matters: the line picker, the date and time parser, the zone table, the conversion, the quote checker and the .ics writer, with 38 unit tests. eval/ has the test set and every raw model reply.

How I Built It

The stack: Gemma 4 E2B (4-bit, gemma-4-E2B-it-q4f16_1-MLC) on WebLLM 0.2.86, Luxon for dates, Vite, and a static site on Vercel.

Gemma copies, code converts

Last week the Best Use of Gemma winner, Pakka, split the work between Gemma and code like this for the Hindi word "kal". Time zones need the same split for a different reason. "Is it summer time in California on November 2?" depends on a rule that changes by country and by year, and the tz database already knows the answer. A 2-billion-parameter model only remembers it sometimes.

So Gemma gets a narrow job. The prompt asks for each event's name, a kind (deadline, start, judging, results, event, other), and three quotes copied character for character. WebLLM holds the reply to a grammar I wrote, and the grammar makes every line of the reply one complete event in this shape:

{"name": "Submission Deadline", "kind": "deadline", "date": "Nov 2, 2026", "time": "2:00pm", "zone": "PST"}
Enter fullscreen mode Exit fullscreen mode

If the reply hits the token limit partway through, the half-written last line is dropped and the complete lines are kept. Bound Jam, further down, is where that mattered. Gemma's own words are only used for the event name.

The page is too long for the model

Gemma 4 E2B in WebLLM has a 4,096-token window, and the Devpost page in the GIF is 262 lines. Before the model sees anything, code keeps only the lines that contain a date, plus the short label above each one ("Submissions", "Judging"). For that page Gemma reads 4 lines. For the RenderJuice contest page, 11,601 characters became 604.

The test

I wanted a number before I trusted this with my own deadlines. I went through my contest folders and took every deadline where my notes had the time zone as the organizer wrote it and the Taiwan time I'd worked out back then. That gave me 22 dates from 19 contests: Devpost, itch.io, DEV, Desall, lablab, Kaggle, Zindi and a few contest sites. 16 of the 22 are a saved page or the page's own sentence pasted into my notes. The other 6 are a line I wrote in my notes myself: the official date, time and zone copied in, with my own label around them (in Chinese for four of them). testset.json marks which is which. My earlier Taiwan times are the answer key, and the line picker gives both setups the same text.

  • Gemma alone: told today's date and that Taiwan is UTC+8 with no daylight saving, and asked for every date in Taiwan time. Its answer was held to a grammar too, so every time it gave was in the right format.
  • Deadline Calendar: Gemma copies, code converts.

Same model, temperature 0, one run each.

Right Taiwan time Wrong time for a date it found Nothing near the right time
Gemma alone 3 / 22 18 1
Deadline Calendar, first run 20 / 22 0 2

"Right" means the correct Taiwan time, to the minute, shows up on one of the output rows. That row doesn't have to be labeled "deadline". "Wrong" means no row has the right time but one is within 36 hours of it, or within 36 hours of it a year off. "Nothing near" means no row is within 36 hours.

The three Gemma got right on its own were all UTC deadlines with the year written out. Each of the 18 wrong answers was 4 to 20 hours too early, or a year off. A few of them show what went wrong:

  • October 25: Submissions due at 11:59 PM PDT (this challenge) came back as 2026-10-25 23:59. That's the page's own clock time, labeled as Taiwan time.
  • 11:59pm Anywhere on Earth on October 31, 2026 came back as 07:59 on November 1, which is what you get if AoE were UTC. AoE is UTC−12, so the answer is 19:59.
  • January 31 — 9:00 AM ET came back as January 2026, which had already passed when I read the page. Code picks the next January after the date you read it.
  • For Bound Jam it said 09:55 on November 1, fifteen hours before the jam closes.

Early is the safer direction to be wrong in, but my calendar would have had those deadlines 4 to 20 hours earlier than the real ones, and the year mistake would have told me Hack-Nation was already over.

What the first run missed

Deadline Calendar gave no wrong times in that run. It missed two deadlines, and both were my code's fault.

Desall. The page says 29 October 2026 (1:59 PM UTC). Gemma copied it as "October 29, 2026". The checker did what I told it to and threw the quote out, so only the start date survived. Now, when a quote isn't on the page word for word, code reads the date out of Gemma's version and looks for the same calendar date on the page. If it finds it, it uses the page's own words and says so on the row. A date that isn't on the page in any form is still thrown out.

Bound Jam, again. Gemma listed the right line, Nov 1, 18:00 CET, as its fifth event. Then it got stuck writing "Game Creation Window" over and over until it hit the 900-token limit, the JSON never closed, and my parser threw the whole reply away. The grammar puts one event per line, so now code keeps every line that is a complete event and shows a note that the answer was cut off.

With those two fixes, the same saved replies score 22 of 22. I wrote both fixes after looking at this test set, so 20 of 22 is the number I'd quote. The first-run scores come from the code at commit f96ac25, and eval/results.json has both.

Smaller things code handles

  • "PST" written in summer. Plenty of pages say PST in August. Code compares the abbreviation with what Pacific clocks actually show on that date. If they disagree, the row says one of the two is a typo and the calendar gets the earlier time.
  • No year. "December 20 at 9:00pm PST" with no year becomes the first December 20 that isn't more than 60 days in the past, and the row says the year was assumed.
  • Japanese pages with no zone. Japanese contest pages often give 2026å¹´11月7日(土)23時59分 and nothing else. If the page is in Japanese, code assumes Japan time and says so on the row.
  • The calendar file. Times are written in UTC with a Z, so any calendar app shows them in its own zone. Long lines are folded at 75 bytes, as the iCalendar spec asks.

The Lazy Payoff

Before: open the rules, find the deadline, look up whether that country has changed its clocks yet, convert, write it in my notes, make a calendar event, add a reminder. Do that for every contest, and do it twice when the page and the timer disagree.

Now: paste, check the highlighted line, press one button. Gemma reads 1 to 13 lines instead of the whole page, and the rows that matter come with the original sentence next to them, so checking takes one look. The part I'd actually get wrong when tired, the daylight saving date and the AoE offset, is no longer something I do in my head.

Why Does Open Innovation Matter?

It runs where the data is. Rules pages aren't secret, but my list of what I'm entering and when is my business, and pasting it into a hosted chatbot every day would make it someone else's. Here nothing you paste leaves the tab. The only downloads are the page, WebLLM's runtime and the model weights.

I could change how the model answers. The grammar that forces three plain quotes per event runs inside WebLLM, token by token. That only works because the weights and the runtime are open. Because of it, each line Gemma writes is one complete event in a fixed shape, and when a reply gets cut off, only the half-written last line is lost.

The test is something anyone can rerun for free. All 44 replies, 22 items with two prompts each, ran on my laptop, and every raw reply is in the repo next to the scoring script.

The time zone rules are open too. The IANA tz database is a public record, kept by hand for decades, of every daylight saving rule change, country by country, and the browser ships a copy that Luxon reads. That is why the program doesn't depend on a model remembering whether California has changed its clocks by November 2. The test above shows how a small model does when it has to remember.

What a closed model would do better: a larger hosted model would probably get more of the Taiwan times right on its own, and it would work on phones without a 2.8 GB download. It would still be doing date math from memory, though, and I'd still want code checking it.

Prize Categories

Best Use of Gemma. Gemma 4 E2B is the only model in the project. It runs locally in the browser through WebLLM and is held to a custom grammar. I compared it with itself on 22 real contest deadlines: asked for the Taiwan time directly it got 3 right, and copying quotes for code to convert it got 20 right on the first run with no wrong times. Every raw output is in the repo.

Top comments (0)