Stop hand-coding the Japanese Rokuyo calendar: LLM-generated lunar logic silently breaks A developer has identified a critical flaw in LLM-generated code for the Japanese Rokuyo calendar: while the lunar date calculation formula is correct, the underlying lunar date conversion is frequently wrong, causing silent date shifts that cascade through an entire year. The developer recommends abandoning hand-coded or LLM-generated lunar conversion functions in favor of the Shirabe Calendar API, which provides accurate Rokuyo, rekichu, and per-purpose date judgments with a free tier of 10,000 calls per month. Originally published in Japanese on Qiita . This is the English edition. curl / fetch / requests . Rokuyo 六曜 is a six-day cycle Taian / Tomobiki / Sensho / Senbu / Butsumetsu / Shakko still used across Japan to decide auspicious dates — weddings, funerals, ground-breakings, store openings. If you build anything for the Japanese market that recommends or scores dates , you will eventually need it. It looks trivial. It is not. Ask a coding assistant for "a function that tells me whether a given date is Taian" and you'll usually get something shaped like this: // The "naive Rokuyo" an LLM tends to propose function getRokuyo gregorianDate: Date : string { // 1 Convert Gregorian - lunar year / month / day const lunar = convertToLunar gregorianDate ; // <- this is where accidents live // 2 Rokuyo = lunar month + lunar day mod 6 const index = lunar.month + lunar.day % 6; return "Taian", "Shakko", "Sensho", "Tomobiki", "Senbu", "Butsumetsu" index ; } Step 2 is genuinely correct — that mapping is right. The bug is always in 1 , convertToLunar . convertToLunar is written all wrong lunar-javascript .This is the silent-failure class — the most common kind of bug in the era of letting an LLM write the code. The Rokuyo rule lunar month + lunar day mod 6 is deterministic and always correct once the lunar date is right . The hard part is the lunar date. Japan's old calendar Tenpō requires: Doing this properly means computing solar and lunar ecliptic longitude at astronomical precision VSOP87 and friends . Use an approximation and, on days where the new moon falls near midnight, you shift by one day — and every subsequent lunar date that year dominoes by one day . A widely cited reference implementation is QREKI by Hideaki Takano : hundreds of lines of AWK computing apparent ecliptic longitudes via series expansion. Hand-porting that is, both in volume and in principle, not the kind of task you should hand to an LLM . Drop the self-implementation and hand it to an API designed for AI agents — you win on accuracy, maintenance cost, and ease of AI integration. The examples below use Shirabe Calendar API https://shirabe.dev . The free tier is 10,000 calls/month and you can try it without an API key . The fetch / requests examples below still pass X-API-Key — it's optional, used to track usage and raise limits. php One date - Rokuyo, rekichu auspicious days , kanshi, solar term, all in one response curl https://shirabe.dev/api/v1/calendar/2026-04-15 The JSON looks like: { "date": "2026-04-15", "rokuyo": { "name": "大安", "reading": "Taian", "timeSlots": { "morning": "good", "noon": "good", "afternoon": "good", "evening": "good" } }, "rekichu": { "name": "一粒万倍日", "type": "auspicious" } , "context": { "wedding": { "judgment": "excellent", "score": 9, "note": "Taian x Ichiryu-manbai-bi. An excellent day for a wedding." } }, "summary": "Reiwa 8 2026 -04-15 Wed Taian / Ichiryu-manbai-bi. Excellent for weddings and openings." } The key fields are context and summary . Instead of a bare "Taian" label, you get a per-purpose judgment 8 categories, each scored 1–10 and a one-line summary. An AI agent can drop that summary straight into its answer to the user. js const res = await fetch "https://shirabe.dev/api/v1/calendar/2026-04-15", { headers: { "X-API-Key": process.env.SHIRABE API KEY } } ; const data = await res.json ; console.log data.rokuyo.name ; // "大安" Taian console.log data.summary ; // "Reiwa 8 2026 -04-15 Wed Taian ..." python import os, requests r = requests.get "https://shirabe.dev/api/v1/calendar/2026-04-15", headers={"X-API-Key": os.environ "SHIRABE API KEY" }, timeout=10, print r.json "rokuyo" "name" You're not limited to a single date. All Taian/Tomobiki days in April up to 93 days curl "https://shirabe.dev/api/v1/calendar/range?start=2026-04-01&end=2026-04-30&filter rokuyo=大安,友引" Top 5 best wedding days from April to December, by score curl "https://shirabe.dev/api/v1/calendar/best-days?purpose=wedding&start=2026-04-01&end=2026-12-31&limit=5" best-days is built so an AI agent can externalize the judgment itself . Pass a date range and a purpose wedding / moving / business and 8 categories total and you get a ranked list of top-scoring days with the reasoning e.g. Taian × Tensha-bi .Publish an OpenAPI 3.1 spec and this kind of API can be called in one shot from ChatGPT GPTs Actions, Claude tool use, Gemini function calling, LangChain, or LlamaIndex. Shirabe serves it directly at https://shirabe.dev/openapi.yaml https://shirabe.dev/openapi.yaml . In the GPT Builder, "Create new action" → paste the OpenAPI URL into Import URL: https://shirabe.dev/openapi.yaml Choose API Key auth header name X-API-Key . That's all it takes for a custom GPT to call Shirabe automatically. Feed the same URL to an OpenAPI loader and it's turned into tools. operationId becomes the function name by design, so no glue code is needed. | Dimension | Self-implementation / LLM-generated code | Japanese calendar API Shirabe etc. | |---|---|---| | Lunar accuracy | Approximations slip by a day at new-moon boundaries | Astronomical precision | | Rekichu coverage | Implementing the ~13 auspicious-day types is a separate big job | 13+ types out of the box | | Per-purpose judgment | Hard to spec and to build | Provided via context.wedding.score etc. | | Maintenance | Versioning the saku-calculation library, etc. | Zero on the caller side | | AI integration | Write your own tool/function definitions | One OpenAPI URL | | Initial cost | Looks like zero — but a single wrong-date liability sits behind it | Free tier, 10,000/month | "Free because I built it myself" is only superficially free. Priced with the business risk of a failure, it usually doesn't pay off in this domain. fetch .Sample code is also collected under the examples in https://shirabe.dev/openapi.yaml https://shirabe.dev/openapi.yaml . The same URL works whether you're calling from ChatGPT GPTs Actions, Claude tool use, or Gemini function calling.