サマータイム付き世界時計を汎用化してみた
サマータイム対応時計をもっと簡単に作成したい…。HTMLのdata属性でタイムゾーンやサマータイムの設定を記述するだけで、量産可能にしてみます。
01南半球のサマータイム
南半球のサマータイムの開始と終了日時を取得
前回、NYのサマータイムの開始と終了日を取得しました。しかし、ちょっと待ってください。南半球のサマータイムを求める場合、果たしてそのままでうまくいくでしょうか。
それでは、試しにシドニーのサマータイムを取得してみます。
Date.prototype.setTimezone = function(tz){
var utc = new Date(this.getTime() + this.getTimezoneOffset() * 60 * 1000);
return new Date(utc.getTime() + tz / 100 * 60 * 60 * 1000);
};
// 第n週の日曜日を取得する関数
function getTheDay(year, month, num){
var first = new Date(year, (month - 1)),
firstDay = first.getDay(),
sun;
if(firstDay == 0){
sun = 1;
}else{
sun = 8 - firstDay;
}
sun += (num - 1)* 7;
return sun;
}
var now = new Date(),
dst = now.setTimezone('+1000'),
year = dst.getFullYear(),
start,
end;
// サマータイム開始日
start = getTheDay(year, 10, 1); // 10月1週目の日曜日の日付を取得
start = new Date(year+'/10/'+start+' 02:00');
// サマータイム終了日
end = getTheDay(year, 4, 1); // 4月1週目の日曜日の日付を取得
end = new Date(year+'/4/'+end+' 02:00');
console.log('開始:'+ start);
console.log('終了:'+ end);
上記のとおり取得できましたが、ここで注意したいのは、南半球の場合、季節が逆転しているということです。シドニーの例だと、サマータイムの2019年の開始日は10月6日、2019年の終了日は4月7日で、開始と終了が逆転していますね。これは、前シーズンのサマータイムが4月7日に終了し、今シーズンのサマータイムが10月6日に始まる、ということです。
ということは、通常時間とサマータイムの条件分岐を北半球の時と変える必要があるのです!
02イスラエルのサマータイム
最後の日曜日の直前の金曜日を取得する
前回、世界のサマータイムの実施状況を調べたところ、たいていの国は日曜日に切り替えを行っていたのに対し、イスラエルだけは金曜日にサマータイムを開始していました。
まったく困ったものですね。
なお、イスラエルのサマータイムは、3月最終日曜日直前の金曜日 午前2時に開始します。それでは、さっそく開始日時を取得してみましょう。
Date.prototype.setTimezone = function(tz){
var utc = new Date(this.getTime() + this.getTimezoneOffset() * 60 * 1000);
return new Date(utc.getTime() + tz / 100 * 60 * 60 * 1000);
};
// 最後の日曜日を取得する関数
function getLastDay(year, month){
var last = new Date(year,month,0),
lastDate = last.getDate(),
lastDay = last.getDay(),
sun = lastDate - lastDay;
return sun;
}
var now = new Date(),
dst = now.setTimezone('+0200'),
year = dst.getFullYear(),
start;
// サマータイム開始日
start = getLastDay(year, 3) - 2; // 最終日曜日から2を引く
start = new Date(year+'/3/'+start+' 02:00');
console.log('開始:' + start);
今回は、最終日曜日を起点に直前の金曜日の日付を取得するので、まず、6行目から最終日曜日を取得する関数を指定します。20行目で最終日曜日を取得し、そこから2を引くことで、直前の金曜日の日付を求めています。
これでイスラエルのサマータイム開始日を取得できました!
03量産可能なサマータイム対応時計
それでは、いよいよ、サマータイム対応時計の量産をしたいと思います!
data属性でHTMLタグにタイムゾーンやサマータイムの情報を付与する
まずは時計を出力するHTMLタグを用意します。
HTML
<!-- NYの時計 -->
<div class="clock" data-clock='{
"tz":"-0500",
"summer_tz":"-0400"
}'></div>
data属性の値を取得するには、下記のようにします。
javascript
$('.clock').each(function(){
var data = $(this).data('clock'),
tz = data.tz,
summerTz = data.summer_tz;
$(this).text('タイムゾーン:'+tz+',夏時間のタイムゾーン:'+summerTz);
});
データ属性に複数の値を指定し、そのうちのタイムゾーンの値を出力してみました。注意すべきは、data属性に値を複数設定するときは必ずシングルクォーテーションで囲んで、オブジェクトの文字列はダブルクォーテーションで囲う事です!これさえ守れば、無事、値を取得することができますね!
data属性を使って汎用的な世界時計を作る
今まで検証してきた内容を踏まえて、世界時計を汎用化してみたいと思います!
HTML
<p>上海:<span class="clock" data-clock='{"tz":"+0800"}'></span></p>
<p>ニューヨーク:
<span class="clock" data-clock='{
"tz":"-0500",
"summer_tz":"-0400",
"summer_s_m":"3",
"summer_s_w":"2",
"summer_s_t":"02:00",
"summer_e_m":"11",
"summer_e_w":"1",
"summer_e_t":"02:00"
}'></span></p>
<p>シドニー:
<span class="clock" data-clock='{
"tz":"+1000",
"summer_tz":"+1100",
"summer_s_m":"10",
"summer_s_w":"1",
"summer_s_t":"02:00",
"summer_e_m":"4",
"summer_e_w":"1",
"summer_e_t":"02:00"
}'></span></p>
<p>イスラエル:
<span class="clock" data-clock='{
"tz":"+0200",
"summer_tz":"+0300",
"summer_s_m":"3",
"summer_s_w":"fri_before_last_sun",
"summer_s_t":"02:00",
"summer_e_m":"10",
"summer_e_w":"last",
"summer_e_t":"02:00"
}'></span></p>
javascript
// タイムゾーンを設定する関数
Date.prototype.setTimezone = function(tz){
var utc = new Date(this.getTime() + this.getTimezoneOffset() * 60 * 1000);
return new Date(utc.getTime() + tz / 100 * 60 * 60 * 1000);
};
// 第n週の日曜日を取得する関数
function getTheDay(year, month, num){
var first = new Date(year, (month - 1)),
firstDay = first.getDay(),
sun;
if(firstDay == 0){
sun = 1;
}else{
sun = 8 - firstDay;
}
sun += (num - 1)* 7;
return sun;
}
// 最後の日曜日を取得する関数
function getLastDay(year, month){
var last = new Date(year,month,0),
lastDate = last.getDate(),
lastDay = last.getDay(),
sun = lastDate - lastDay;
return sun;
}
// 時計表示の関数
function setTime(time){
var h = ('0' + time.getHours()).slice(-2),
m = ('0' + time.getMinutes()).slice(-2),
s = ('0' + time.getSeconds()).slice(-2);
msg = h + ':' + m + ':' + s;
return msg;
}
// 開始・終了日時を求める関数
function getTheTime(year,month,week,time){
var t;
if(week == 'fri_before_last_sun'){
// 最終日曜日の前の金曜日を取得
t = getLastday(year, month) - 2;
}else if(week == 'last'){
// 最終日曜日を取得
t = getLastday(year, month);
}else{
// 第n週の日曜日を取得
t = getTheDay(year, month, week);
}
t = new Date(year+'/'+month+'/'+t+' '+time).getTime();
return t;
}
// 世界時計の表示
$('.clock').each(function(){
var data = $(this).data('clock'),
Tz = data.tz,
summerTz = data.summer_tz,
startMonth = data.summer_s_m,
startWeek = data.summer_s_w,
startTime = data.summer_s_t,
endMonth = data.summer_e_m,
endWeek = data.summer_e_w,
endTime = data.summer_e_t,
$target = $(this);
// 時計表示
setInterval(function(){
var now = new Date(),
dst = now.setTimezone(Tz),
dstTime = dst.getTime(),
year = dst.getFullYear(),
time = dst;
// サマータイム実施の場合ここから
if(summerTz != 'false'){
//サマータイム開始・終了日時取得
var start = getTheTime(year,startMonth,startWeek,startTime);
var end = getTheTime(year,endMonth,endWeek,endTime);
// 南半球と北半球で処理を分ける
if(start < end){
// 北半球の時刻表示
if(dstTime >= start && dstTime < end){
time = now.setTimezone(summerTz);
}
}else{
// 南半球の時刻表示
if(dstTime < end || dstTime >= start){
time = now.setTimezone(summerTz);
}
}
}
// サマータイム実施の場合ここまで
var msg = setTime(time);
$target.text(msg);
}, 1000);
});
出力結果
上海:
ニューヨーク:
シドニー:
イスラエル:
サマータイム導入している国も、していない国も、無事に時計を表示できました!
さて、詳しく見ていきたいと思います。
data-clockの中身
tz | 通常時のタイムゾーン |
---|---|
summer_tz | サマータイムのタイムゾーン |
summer_s_m | サマータイム開始月 |
summer_s_w | サマータイム開始週。最終週の場合は"last"、最終日曜の直前の金曜の場合は、"fri_before_last_sun"を指定。 |
summer_s_t | サマータイム開始時間(通常時の時間で) |
summer_e_m | サマータイム終了月 |
summer_e_w | サマータイム終了週。最終週の場合は"last"を指定。 |
summer_e_t | サマータイム終了時間(通常時の時間で) |
なお、summer_~は、サマータイム未実施の場合、指定する必要はありません。
javascriptの解説
1行目~51行目までは、今までの内容をもとに、必要な処理を関数化しています。35行目~の開始・終了日時を求める関数は、data属性で指定した、サマータイムの開始週と、終了週の内容をもとに、処理を分けています。
52行目からは時計表示の処理になります。53行目、時計はclockというクラスのついた要素に出力します。54~62行目では、data属性の中身を取得しています。
64行目からは時計の表示のため、setIntervalで1秒ごとに処理しています。まず、70行目のtime = dstで、通常時の現在時刻を変数timeに代入しています。そして、72行目のif分で、サマータイム実施国かどうかを判定し、74行目と75行目で開始日時と終了日時を求めています。77行目からは、南半球と北半球とで処理を分けています。南半球の場合、サマータイム終了日より前と、サマータイム開始以降とは、条件が等しくならないので、&&ではなく||で判定しています。そして、それぞれ現在時刻をtimeに代入して、最後に92行目で$('.clock')にテキストを挿入して完了です!
いかがでしたか?これで、かんたんに世界時計を量産できそうです。ちなみに、イスラエルがイレギュラーで例外的な処理になりましたね…。その他にもイレギュラーな国はありそうなので、その場合は今回のように例外処理を書き足す必要がありそうです。
上手く動くといいなぁ~。
この記事が役に立ったらシェアしてください!