Skip to content

Instantly share code, notes, and snippets.

@mandel59
Created May 23, 2021 11:46
Show Gist options
  • Save mandel59/b5876891661fc1f7151884153b899042 to your computer and use it in GitHub Desktop.
Save mandel59/b5876891661fc1f7151884153b899042 to your computer and use it in GitHub Desktop.
日本の暦でカレンダーを表示する
import { parse } from "https://deno.land/std@0.95.0/flags/mod.ts"
import { TextDecoder } from 'https://cdn.skypack.dev/text-decoding'
const sjisDecoder = new TextDecoder("shift-jis")
const typeOptions = new Map([
[0, "西暦から和暦へ変換"],
[1, "和暦から西暦へ変換"],
[2, "太陰太陽暦の朔日"],
])
const gengoOptions = new Map([
["a000", "西暦 (換算)"],
["b019", "允恭天皇"],
["b020", "安康天皇"],
["b021", "雄略天皇"],
["b022", "清寧天皇"],
["b023", "顕宗天皇"],
["b024", "仁賢天皇"],
["b025", "武烈天皇"],
["b026", "継体天皇"],
["b027", "安閑天皇"],
["b028", "宣化天皇"],
["b029", "欽明天皇"],
["b030", "敏達天皇"],
["b031", "用明天皇"],
["b032", "崇峻天皇"],
["b033", "推古天皇"],
["b034", "舒明天皇"],
["b035", "皇極天皇"],
["b036", "大化"],
["b037", "白雉"],
["b038", "斉明天皇"],
["b039", "天智天皇"],
["b040", "天武天皇"],
["b041", "朱鳥"],
["b042", "持統天皇"],
["b043", "文武天皇"],
["b044", "大宝"],
["b045", "慶雲"],
["b046", "和銅"],
["b047", "霊亀"],
["b048", "養老"],
["b049", "神亀"],
["b050", "天平"],
["b051", "天平感宝"],
["b052", "天平勝宝"],
["b053", "天平宝字"],
["b054", "天平神護"],
["b055", "神護景雲"],
["b056", "宝亀"],
["b057", "天応"],
["b058", "延暦"],
["b059", "大同"],
["b060", "弘仁"],
["b061", "天長"],
["b062", "承和"],
["b063", "嘉祥"],
["b064", "仁寿"],
["b065", "斉衡"],
["b066", "天安"],
["b067", "貞観"],
["b068", "元慶"],
["b069", "仁和"],
["b070", "寛平"],
["b071", "昌泰"],
["b072", "延喜"],
["b073", "延長"],
["b074", "承平"],
["b075", "天慶"],
["b076", "天暦"],
["b077", "天徳"],
["b078", "応和"],
["b079", "康保"],
["b080", "安和"],
["b081", "天禄"],
["b082", "天延"],
["b083", "貞元"],
["b084", "天元"],
["b085", "永観"],
["b086", "寛和"],
["b087", "永延"],
["b088", "永祚"],
["b089", "正暦"],
["b090", "長徳"],
["b091", "長保"],
["b092", "寛弘"],
["b093", "長和"],
["b094", "寛仁"],
["b095", "治安"],
["b096", "万寿"],
["b097", "長元"],
["b098", "長暦"],
["b099", "長久"],
["b100", "寛徳"],
["b101", "永承"],
["b102", "天喜"],
["b103", "康平"],
["b104", "治暦"],
["b105", "延久"],
["b106", "承保"],
["b107", "承暦"],
["b108", "永保"],
["b109", "応徳"],
["b110", "寛治"],
["b111", "嘉保"],
["b112", "永長"],
["b113", "承徳"],
["b114", "康和"],
["b115", "長治"],
["b116", "嘉承"],
["b117", "天仁"],
["b118", "天永"],
["b119", "永久"],
["b120", "元永"],
["b121", "保安"],
["b122", "天治"],
["b123", "大治"],
["b124", "天承"],
["b125", "長承"],
["b126", "保延"],
["b127", "永治"],
["b128", "康治"],
["b129", "天養"],
["b130", "久安"],
["b131", "仁平"],
["b132", "久寿"],
["b133", "保元"],
["b134", "平治"],
["b135", "永暦"],
["b136", "応保"],
["b137", "長寛"],
["b138", "永万"],
["b139", "仁安"],
["b140", "嘉応"],
["b141", "承安"],
["b142", "安元"],
["b143", "治承"],
["b144", "養和"],
["b145", "寿永"],
["b146", "元暦"],
["b147", "文治"],
["b148", "建久"],
["b149", "正治"],
["b150", "建仁"],
["b151", "元久"],
["b152", "建永"],
["b153", "承元"],
["b154", "建暦"],
["b155", "建保"],
["b156", "承久"],
["b157", "貞応"],
["b158", "元仁"],
["b159", "嘉禄"],
["b160", "安貞"],
["b161", "寛喜"],
["b162", "貞永"],
["b163", "天福"],
["b164", "文暦"],
["b165", "嘉禎"],
["b166", "暦仁"],
["b167", "延応"],
["b168", "仁治"],
["b169", "寛元"],
["b170", "宝治"],
["b171", "建長"],
["b172", "康元"],
["b173", "正嘉"],
["b174", "正元"],
["b175", "文応"],
["b176", "弘長"],
["b177", "文永"],
["b178", "建治"],
["b179", "弘安"],
["b180", "正応"],
["b181", "永仁"],
["b182", "正安"],
["b183", "乾元"],
["b184", "嘉元"],
["b185", "徳治"],
["b186", "延慶"],
["b187", "応長"],
["b188", "正和"],
["b189", "文保"],
["b190", "元応"],
["b191", "元亨"],
["b192", "正中"],
["b193", "嘉暦"],
["b194", "元徳"],
["b195", "元弘"],
["b196", "建武"],
["b197", "延元"],
["b198", "興国"],
["b199", "正平"],
["b200", "建徳"],
["b201", "文中"],
["b202", "天授"],
["b203", "弘和"],
["b204", "元中"],
["b205", "明徳"],
["b206", "応永"],
["b207", "正長"],
["b208", "永享"],
["b209", "嘉吉"],
["b210", "文安"],
["b211", "宝徳"],
["b212", "享徳"],
["b213", "康正"],
["b214", "長禄"],
["b215", "寛正"],
["b216", "文正"],
["b217", "応仁"],
["b218", "文明"],
["b219", "長享"],
["b220", "延徳"],
["b221", "明応"],
["b222", "文亀"],
["b223", "永正"],
["b224", "大永"],
["b225", "享禄"],
["b226", "天文"],
["b227", "弘治"],
["b228", "永禄"],
["b229", "元亀"],
["b230", "天正"],
["b231", "文禄"],
["b232", "慶長"],
["b233", "元和"],
["b234", "寛永"],
["b235", "正保"],
["b236", "慶安"],
["b237", "承応"],
["b238", "明暦"],
["b239", "万治"],
["b240", "寛文"],
["b241", "延宝"],
["b242", "天和"],
["b243", "貞享"],
["b244", "元禄"],
["b245", "宝永"],
["b246", "正徳"],
["b247", "享保"],
["b248", "元文"],
["b249", "寛保"],
["b250", "延享"],
["b251", "寛延"],
["b252", "宝暦"],
["b253", "明和"],
["b254", "安永"],
["b255", "天明"],
["b256", "寛政"],
["b257", "享和"],
["b258", "文化"],
["b259", "文政"],
["b260", "天保"],
["b261", "弘化"],
["b262", "嘉永"],
["b263", "安政"],
["b264", "万延"],
["b265", "文久"],
["b266", "元治"],
["b267", "慶応"],
["b268", "明治"],
["b269", "大正"],
["b270", "昭和"],
["b271", "平成"],
["b272", "令和"],
["c000", "正慶"],
["c001", "建武"],
["c002", "暦応"],
["c003", "康永"],
["c004", "貞和"],
["c005", "観応"],
["c006", "文和"],
["c007", "延文"],
["c008", "康安"],
["c009", "貞治"],
["c010", "応安"],
["c011", "永和"],
["c012", "康暦"],
["c013", "永徳"],
["c014", "至徳"],
["c015", "嘉慶"],
["c016", "康応"],
["c017", "明徳"],
])
const jgOptions = new Map([
[0, "すべてユリウス暦"],
[1, "すべてグレゴリオ暦"],
[2, "デフォルト"],
])
function buildFormData(fields: {
type: number;
gengo: string;
year: number;
leap: boolean;
month: number;
day: number;
jg: number;
len: number;
}) {
if (!typeOptions.has(fields.type)) throw new RangeError()
if (!gengoOptions.has(fields.gengo)) throw new RangeError()
if (!jgOptions.has(fields.jg)) throw new RangeError()
// 間隔
const div = 1
// 間隔の単位: 3=日
const divu = 3
// 期間の単位: 3=日
const lenu = 3
// 年号の判断: 0=年単位, 1=日付単位
const gen = 1
const formData = new FormData()
formData.set("type", String(fields.type))
formData.set("gengo", fields.gengo)
formData.set("year", String(fields.year))
if (fields.leap) formData.set("leap", "1")
formData.set("month", String(fields.month))
formData.set("day", String(fields.day))
formData.set("jg", String(fields.jg))
formData.set("div", String(div))
formData.set("divu", String(divu))
formData.set("len", String(fields.len))
formData.set("lenu", String(lenu))
formData.set("gen", String(gen))
formData.set("csv", "CSV")
return formData
}
async function fetchCSV(year: number, leap: boolean, month: number, day: number) {
const body = buildFormData({
type: 1,
gengo: "a000",
year,
leap,
month,
day,
jg: 1,
len: 31,
})
const f = await fetch("https://eco.mtk.nao.ac.jp/cgi-bin/koyomi/caldb.cgi", {
method: "POST",
body
})
if (!f.ok) throw new Error()
const resBody = await f.arrayBuffer()
const resText = sjisDecoder.decode(resBody)
return resText
}
function* parseCSV(csv: string) {
for (const line of csv.split(/\r?\n/g).slice(1)) {
if (!line) continue
const [
西暦,
和暦,
神武紀元,
_年の干支,
_日の干支,
] = line.split(/,/g)
const date = 西暦.replace(/\//g, "-")
const weekday = new Date(date).getDay()
const m = /(?<jera>\D+)(?<jyear>\d+)年(?<jleap>閏?)(?<jmonth>\d+)月(?<jday>\d+)日/.exec(和暦)
if (!m) throw new Error()
const { jera, jyear, jleap, jmonth, jday } = m.groups!
yield {
date,
weekday,
jinmu: parseInt(神武紀元, 10),
jera,
jyear: parseInt(jyear, 10),
jleap: Boolean(jleap),
jmonth: parseInt(jmonth, 10),
jday: parseInt(jday, 10),
}
}
}
function monthlyCalendar(source: Generator<{
date: string;
weekday: number;
jinmu: number;
jera: string;
jyear: number;
jleap: boolean;
jmonth: number;
jday: number;
}>) {
let output = ""
const first = source.next()
if (first.done) throw new Error()
const { weekday, jera, jyear, jleap, jmonth } = first.value
output += `${jera}${jyear}年${jleap ? "閏" : ""}${jmonth}月\n`
output += `日 月 火 水 木 金 土\n`
let line = []
for (let i = 0; i < weekday; i++) {
line.push(" ")
}
line.push(" 1")
for (const row of source) {
if (row.jday === 1) break
if (line.length === 7) {
output += line.join(" ")
output += "\n"
line = []
}
line.push(String(row.jday).padStart(2, " "))
}
output += line.join(" ")
return output
}
const { _: args, leap } = parse(Deno.args, { boolean: ["leap"] })
if (args.length !== 2) throw new Error()
const year = Number(args[0])
const month = Number(args[1])
console.log(monthlyCalendar(parseCSV(await fetchCSV(year, leap, month, 1))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment