|
| 1 | +<!DOCTYPE html> |
| 2 | +<html> |
| 3 | +<head> |
| 4 | +<title>JAL先得カレンダー色分け</title> |
| 5 | +<script type="text/javascript" src="https://code.jquery.com/jquery-3.6.0.min.js"></script> |
| 6 | +<script type="text/javascript"> |
| 7 | +var DEBUG = false; |
| 8 | +$(function(){ |
| 9 | + const now = new Date(); |
| 10 | + const $calendars = $("#calendars"); |
| 11 | + const sample_pairs = [[now.getFullYear(), now.getMonth() + 1]]; |
| 12 | + while ( sample_pairs.length <= 11 ) { |
| 13 | + sample_pairs.push( get_next_ym(...sample_pairs[sample_pairs.length - 1] ) ); |
| 14 | + } |
| 15 | + console.log(sample_pairs); |
| 16 | + for ( const [year, month] of sample_pairs ) { |
| 17 | + $calendars.append(render_calendar(year, month)); |
| 18 | + } |
| 19 | +}); |
| 20 | +const LAST_DAY = [undefined, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; |
| 21 | +function get_lastday(year, month) { |
| 22 | + if ( month !== 2 ) { |
| 23 | + return LAST_DAY[month]; |
| 24 | + } |
| 25 | + // 2000年の例外 (400) は考慮していない |
| 26 | + return year % 4 === 0 ? 29 : 28; |
| 27 | +} |
| 28 | +function get_next_ym(year, month) { |
| 29 | + return month === 12 ? [year + 1, 1] : [year, month + 1]; |
| 30 | +} |
| 31 | +function range(start, end) { |
| 32 | + const array = []; |
| 33 | + for ( let i = start ; i <= end ; i++ ) { |
| 34 | + array.push(i); |
| 35 | + } |
| 36 | + return array; |
| 37 | +} |
| 38 | +function get_calendar_matrix(year, month) { |
| 39 | + const day1 = new Date(year, month - 1, 1); |
| 40 | + const week1 = day1.getDay(); |
| 41 | + const lastday = get_lastday(year, month); |
| 42 | + const month_sequence = range(1, lastday); |
| 43 | + if ( week1 > 0 ) { |
| 44 | + month_sequence.unshift( ...Array(week1) ); |
| 45 | + } |
| 46 | + const calendar_matrix = []; |
| 47 | + while( month_sequence.length > 0 ) { |
| 48 | + const current_week = month_sequence.splice(0, 7); |
| 49 | + if ( current_week.length < 7 ) { |
| 50 | + current_week.push(...Array( 7 - current_week.length )); |
| 51 | + } |
| 52 | + calendar_matrix.push(current_week); |
| 53 | + } |
| 54 | + return calendar_matrix; |
| 55 | +} |
| 56 | +function get_days_after(year, month, day) { |
| 57 | + const date = new Date(year, month-1, day); |
| 58 | + const now = new Date(); |
| 59 | + for ( const key of ["Hours", "Minutes", "Seconds", "Milliseconds"] ) { |
| 60 | + now["set"+key](0) |
| 61 | + } |
| 62 | + const diff = date.getTime() - now.getTime(); |
| 63 | + const diffdate = diff / 1000 / 86400; |
| 64 | + return diffdate; |
| 65 | +} |
| 66 | +function render_calendar(year, month) { |
| 67 | + const matrix = get_calendar_matrix(year, month); |
| 68 | + const lines = []; |
| 69 | + lines.push(`<caption>${year}年${month}月</caption>`); |
| 70 | + lines.push( |
| 71 | + `<thead><tr>` + |
| 72 | + `<th class="sunday">日</th>` + |
| 73 | + "月 火 水 木 金".split(/ /).map( w => `<th>${w}</th>`).join("") + |
| 74 | + `<th class="saturday">土</th>` + |
| 75 | + `</tr></thead>` |
| 76 | + ); |
| 77 | + lines.push(`<tbody>`); |
| 78 | + for ( const row of matrix ) { |
| 79 | + // 何日前か判定して、色分けする |
| 80 | + // 21 28 45 55 75 ~330 |
| 81 | + // TODO: 休日APIで休日を赤く表示させたい |
| 82 | + const row2 = row.map( d => [d, get_days_after(year, month, d)]); |
| 83 | + row2.forEach( ar => ar.push(get_jal_days_after(ar[1])) ); |
| 84 | + lines.push( `<tr>` + |
| 85 | + row2.map( ([d, da, jda]) => `<td class="jal_days_after_${jda || "other"} ${da === 0 ? "today" : ""}">${d || "-"}</td>` ).join("") + `</tr>`); |
| 86 | + } |
| 87 | + lines.push(`</tbody>`); |
| 88 | + return `<table id="calendar_${year}_${month}" class="calendar"> |
| 89 | +${lines.join("\n")} |
| 90 | +</table>`; |
| 91 | +} |
| 92 | +function get_jal_days_after( days_after ) { |
| 93 | + if ( days_after < 21 ) { |
| 94 | + return undefined; |
| 95 | + } else if ( days_after < 28 ) { |
| 96 | + return 21; |
| 97 | + } else if ( days_after < 45 ) { |
| 98 | + return 28; |
| 99 | + } else if ( days_after < 55 ) { |
| 100 | + return 45; |
| 101 | + } else if ( days_after < 75 ) { |
| 102 | + return 55; |
| 103 | + } else if ( days_after <= 330 ) { |
| 104 | + return 75; |
| 105 | + } else { |
| 106 | + return undefined; |
| 107 | + } |
| 108 | +} |
| 109 | +// https://www.jal.co.jp/dom/sakitoku/index.html?sta=HND&ena=OBO&y=2022&m=1 |
| 110 | +</script> |
| 111 | +<style type="text/css"> |
| 112 | +.sunday { color: red } |
| 113 | +.saturday { color: blue } |
| 114 | +table.calendar { |
| 115 | + border: 2px solid black; |
| 116 | + border-collapse: collapse; |
| 117 | + display: inline-table; |
| 118 | + margin: 0.5em; |
| 119 | +} |
| 120 | +table.calendar td, |
| 121 | +table.calendar th { |
| 122 | + border: 1px solid black; |
| 123 | + text-align: center; |
| 124 | + width: 2em; |
| 125 | + height: 2em; |
| 126 | +} |
| 127 | +table.calendar td.today { |
| 128 | + font-weight: bold; |
| 129 | + color: darkorange |
| 130 | +} |
| 131 | +table.calendar thead tr { |
| 132 | + border-bottom: 2px solid black; |
| 133 | + background: lightgray; |
| 134 | +} |
| 135 | +.jal_days_after_21 { background-color: rgb(250, 250, 54) } |
| 136 | +.jal_days_after_28 { background-color: rgb(128, 233, 119) } |
| 137 | +.jal_days_after_45 { background-color: rgb(154, 227, 240) } |
| 138 | +.jal_days_after_55 { background-color: rgb(116, 164, 219) } |
| 139 | +.jal_days_after_75 { background-color: rgb(216, 119, 119) } |
| 140 | +</style> |
| 141 | +</head> |
| 142 | +<body> |
| 143 | + |
| 144 | +<p>詳細は<a href="https://www.jal.co.jp/dom/sakitoku/index.html">先得カレンダー</a>を参照。</p> |
| 145 | +<p>凡例: |
| 146 | +<span class="jal_days_after_21">21日前</span>、 |
| 147 | +<span class="jal_days_after_28">28日前</span>、 |
| 148 | +<span class="jal_days_after_45">45日前</span>、 |
| 149 | +<span class="jal_days_after_55">55日前</span>、 |
| 150 | +<span class="jal_days_after_75">75日前</span> |
| 151 | +</p> |
| 152 | + |
| 153 | +<div id="calendars"> |
| 154 | +</div> |
| 155 | + |
| 156 | +</body> |
| 157 | +</html> |
0 commit comments