亀の歩みでプログラミング

2021年3月25日木曜日

JavaScript

昨日投稿した記事の続きを書こうかな。MLBの各球団の本拠地の現在時刻を表示するページを自分のブログに作成・設置するためにあれこれ苦労した話です。勉強も兼ねて多少は汎用性のあるコードを目指してプログラムを組み始めたわけですが、組んでみると次から次へと問題が出てきて大変。リアルに一日一バグ修正という亀の歩みでした。


キーボードと亀


その中でも一つ勉強になったことがあります。もしかしたら僕と同じようなミスをするひとがいるかもしれないので書いておこうと思います。他のプログラミング言語でも大体同じだと思いますが、JavaScript(以下JS)では安全に扱える整数の上限があります。それは253-1。僕はブログをいじるくらいしかしていないので、そんなに大きい数字なんて気にしなくても大丈夫!と考えていました。しかし…今回作成したコードでオーバーフローを起こすことに。そこまで大きな数字は扱っていないはずだったのでビックリ。原因を調べてみると、なにやらsetTimeout()の遅延時間は32ビット符号付整数値で保存されているみたいで。こちらのMDNの解説で説明されています。そんなに大きな数字で設置することは早々ないだろうけれど、使う際はお気を付けを。


注意喚起する男


僕的には253近い数値は扱っていないつもりだったので、最初は原因が分からず不思議でした。プログラミングに慣れていないのでコードを打ち間違えたかな?と確かめたり。というかエラーを吐いてくれれば分かりやすいのに、普通に動作するだけに不具合箇所を見つけるのに余計な時間をとられた…。自分の考え方が間違っているのか?と頭の中が段々とゴチャゴチャしてきて。特定の条件で不具合が出たり出なかったりとなるのも発見が遅れた原因ですね。コードの動作確認をして大丈夫!と思っていても、あとで別の条件で確認したときに動作が変になったりするのでなんでやねん!というツッコミがとまらなかった。


苛立つ男


サマータイムは国によって年をまたいで行われているところがあるので、そこも考慮したコードにすると余計に頭がこんがらがります。自分のできる範囲でコードを長くし過ぎずに…というのを意識して考えていたので余計に。ただ、同じことに時間をかけ過ぎ段々と飽きてきたので妥協ラインも下がっていきました。そうこうして完成したコードがこちら↓



<div class="test1">日時表示</div><!--サマータイムあり-->
<div class="test2">日時表示</div><!--サマータイムあり-->
<div class="test3">日時表示</div><!--サマータイムなし-->

<script>
{
const timeZone = [-5,-6];//サマータイムのある地域のタイムゾーン
const options = {weekday:'long', year:'numeric', month:'long', day:'numeric', hour:'2-digit', minute:'2-digit', second:'2-digit', timeZone:'UTC'};
const elem1 = document.querySelectorAll(".test1");  
const elem2 = document.querySelectorAll(".test2");
const elem3 = document.querySelectorAll(".test3");  
const elemArray = [elem1,elem2,elem3];

timeZone.forEach((elem,i) =>{setTimeZone(2,2,0,10,1,0,2,2,elem,i);});
timeZone.push(-7);//サマータイムのない地域のタイムゾーン追加
setInterval(()=>clock(elemArray,timeZone),500);

//サマータイムを考慮したタイムゾーンの決定
function setTimeZone(month1,nth1,dayOfWeek1,month2,nth2,dayOfWeek2,st1,st2,tz,i){
 const nowDate = new Date();
 const stBegin = summerTime(month1,nth1,dayOfWeek1,nowDate,st1,tz);
 const stEnd = summerTime(month2,nth2,dayOfWeek2,nowDate,st2,tz);

 if((nowDate>=stBegin && nowDate<stEnd) || (stBegin>stEnd && !(nowDate<stBegin && nowDate>=stEnd))){
  timeZone[i]=tz + 1;
  if((stEnd > nowDate) && (stEnd - nowDate < 24*60*60*1000)){
    setTimeout(()=>timeZone[i]=tz,stEnd - nowDate);}
 }
 else {
  timeZone[i]=tz;
  if((stBegin > nowDate) && (stBegin - nowDate < 24*60*60*1000)){
   setTimeout(()=>timeZone[i]=tz + 1,stBegin - nowDate);}
 }
}
//サマータイム開始・終了日時の計算
function summerTime(month,nth,day,nd,st,tz){
 const nthDayDate = 1+(7+day-new Date(nd.getFullYear(),month,1).getDay())%7+7*(nth-1);
 const summerTime = new Date(Date.UTC(nd.getFullYear(),month,nthDayDate,st-tz,13));
 if(summerTime.getMonth() !== month){return alert(`第${nth}曜日は存在しません`);}
 return summerTime;
}
//日時表示
function clock(displayElem,timeZone) {
 for(let i=0;i<timeZone.length;i++){
  const currentTime =  new Date(Date.now()+timeZone[i]*60*60*1000);
  displayElem[i].forEach(elem => {elem.innerHTML = currentTime.toLocaleString(undefined,options);});
 }
}

}
</script>


たぶんネットで検索すればもっとまともなコードがいっぱい出てくると思うので説明は省かせていただきます。なんか汚いコード書いてるなぁという感じで苦笑いでもしてもらえれば。コードの書き方にも色々ルールがあるらしいので少しは意識して書こうかな?と思っていたのですが…途中で面倒臭くなってきて。変数名や引数名に情報を詰め込む必要性は分かるのですが、いざ自分でやろうとすると「だるい…」という思いが強い。面倒臭がりの僕には不向きです。


面倒臭がるパンダ


ちなみに僕はタイムゾーンのセットを24時間に設定してあるので、サマータイム期間の終了・開始日時の24時間以上前からページを開きっぱなしにされると正しく更新されません。そんな変わり者にまで対処していられない…。もしかしたら他にも不具合が出る可能性もありますが、とりあえず面倒になったのでここで妥協しました。他に試してみたいこともありましたが疲れましたので。ページに表示するHTML・CSSに関しては適当に。タブの切り替えに関してはJS使用が手っ取り早いのですが、勉強がてらJSを使わない方法を公開している方からコピペさせていただきました。デザインを凝ってやろう!という程のヤル気は残っていなかったなぁ。まぁ気が向いたらデザインもコードも修正しよう。しかし短いコード書くのにやたらと時間がかかってしまった…。

最新の投稿

このブログを検索

ブログ アーカイブ

自己紹介

ひきこもっていたらお爺さんになりました…嘘です。プロフ写真はFaceAppで老化したものです。本人はもう少しだけ若いです。
ブログ管理者は15年程ひきこもっている、長期ひきこもりのオッサンです。現在ブログは休止中。再開は未定です。 詳細なプロフィール

QooQ