日付のデータを取り扱う - JavaScript プログラミング
PROGRAM
日付のデータを取り扱う。
目次
- 日付と時刻 … 日付の情報を取り扱うための基礎知識です。
- 現在の日付を取得する … パソコンに設定されている時刻をもらってみます。
- 日付データを操作する … 日付データをいろいろと更新してみるお話です。
日付と時刻
日付と時刻といえば、普通に、"2004/05/10 01:21" というようなものの事を言います。ただし JavaScript の世界では、 1970/01/01 からの経過ミリ秒数で、今がいつであるのかを記憶します。ミリ秒というのは、1秒の 1,000 分の 1 のことです。
なぜそうなのかというと…、おそらく単純演算を一瞬でこなすパソコンにとってはそのほうが何かと都合がいいからです。人間からしてみれば、1970 年から 10,000,000 ミリ秒後といわれてもさっぱりですけど、パソコンならば瞬時に現在の日付を割り出せます。
そもそも実際には、パソコンからしてみると、今日が何月であろうが何日であろうが、どうでもいいことだったりするのですけどね。パソコンにとって一番肝心なことというと、過去か未来かを人の手を借りずに瞬時に判断できるかどうか、そこが重要ではないかと思います。
たとえば年と月と日を別々に記録していたとしましょう。そのとき、過去か未来かを判断するためには面倒な手法が必要になってきます。
年が先であればそれは未来であるのは間違いないですけど、年が一緒であったら月の大小関係を比べ、また月が一緒だったら日の大小関係を比べる…。未来であるかを調べるために、このような手間をかけなくてはいけなくなってしまいます。もっとも、この手間を担うのもプログラマの役割ですので、そっくりそのまま、面倒が自分に帰ってくるのですけどね。
それが、経過秒数として取り扱っていれば、経過秒数が多いほど未来である、これは紛れもない事実。これなら一瞬で新しいものか古いものかを判断することが出来てしまうのでした。他にも、1分後なら 60,000 を足せばいいわけですし、1時間後なら 3600,000 を足すという、桁は少し大きめですけどそれでも簡単な方法で時刻が進められます。
このように、パソコンで日付を取り扱うのは何かと厄介な場合が多いのですけど、JavaScript の場合は便利な機能を備えた "日付オブジェクト" というものが存在しますので、意外と簡単に日付情報を取り扱うことができるのでした。
なお取り扱える時刻は、ローカル時刻 (日本時間) と世界標準時ですが、JavaScript 1.3 からは世界協定時刻 (UTC) というものも取り扱うことが出来るようになっているそうです。
現在の日付を取得する
JavaScript において日付を操作するには、まず "日付オブジェクト" を作成する必要があります。日付オブジェクトを作成する際に引数を渡すことで、作成する日付オブジェクトのデータを調整することが出来ます。
// 日付オブジェクトを用意します(現在時刻)
var objDate = new Date;
// 日付オブジェクトを用意します(時間指定)【2例】
var objDate = new Date("Jun 30, 2004");
var objDate = new Date("2004/06/30 19:08");
日付オブジェクト作成時に設定される時刻は、基本的にローカル時刻 (日本時間) として取り扱われるようです。国際標準時 (GMT) として指定したい場合には、文字列を渡す際にそれを次のような感じで明記する必要があるようです。
// 日付オブジェクトを用意します(国際標準時 GMT の場合)
var objDate = new Date("2004/06/30 01:12 GMT");
また、年月日時分秒 の順番に数値を並べることによっても設定することが出来ます。ただし、月の指定は 1 月を 0 とした通し番号で指定しないといけないので気をつけましょう。
// 日付オブジェクトを用意します(要素を数値で与える)
var objDate = new Date(2004, 05, 30, 22, 49, 01);
さて、これらによって正常に時刻が取得できたかどうかを確認するには、日付オブジェクトの下記のメソッドを呼び出すことで確認できます。
.getDate() というものはローカル時刻として、.getUTCDate() というように UTC が挟まっているものは国際協定時として時刻を取得します。念のため、ローカル時刻 2004/06/30 19:35:16 +0900 の場合の例も挙げておきます。なお +0900 というのは日本標準時間を表す記号のようなものです。
.getDate() | 日にちを取得します。 | 30 |
---|---|---|
.getUTCDate() | 30 | |
.getDay() | 曜日番号を取得します。0 を日曜日とした通し番号で、6 が土曜日となります。 | 3 |
.getUTCDay() | 3 | |
.getFullYear() | 西暦の年数を 4 桁で取得します。 | 2004 |
.getUTCFullYear() | 2004 | |
.getYear() | 西暦の年数を 2 桁で取得できるはずなのですが、Windows XP + IE6.SP1 では 4 桁が取得できてしまいました。このメソッドは UTC 版は用意されていないようです。 | 2004 |
- | - | |
.getMonth() | 月を取得します。これは 0 から始まる通し番号となるため、日本で馴染みの呼び方である1月は 0 となります。 | 5 |
.getUTCMonth() | 5 | |
.getHours() | 時を取得します。 | 19 |
.getUTCHours() | 10 | |
.getMinutes() | 分を取得します。 | 35 |
.getUTCMinutes() | 35 | |
.getSeconds() | 秒を取得します。 | 16 |
.getUTCSeconds() | 16 | |
.getMilliseconds() | ミリ秒を取得します。古いブラウザでは 0 が返ることがあるそうですけど、JavaScript でミリ秒の誤差が致命的となることもないでしょうから、さほど気にしなくてもよさそうです。 | 401 |
.getUTCMilliseconds() | 401 |
単純な方法は、たとえばブラウザで確認するならば、HTML ファイルの中で document.write をつかって、これらのメソッドの結果を表示します。たとえば経過ミリ秒と、実際の時刻 (文字列) とを確認したい場合は次のような感じになります。
<html>
<head></head>
<body>
<script language="JavaScript">
// 日付オブジェクトの作成
var objDate = new Date;
// 1970/01/01 から現在までの経過ミリ秒数を表示します。
document.writeln("経過ミリ秒数: " + objDate.getTime() + "<br>");
// 実際の日付文字列を表示します。(ローカル時刻)
document.writeln("日時: " + objDate.toLocaleString() + "<br>");
</script>
</body>
</html>
上記は人間から見た時刻を取り扱う上で便利なメソッドでしたけど、日付オブジェクトが内部で持っている、1970 年 01 月 01 日から今までの経過 ミリ秒数を取得することも出来ます。
// 1970/01/01 からの経過ミリ秒数を取得する。
objDate.getTime();
たとえば上記の結果を document.write などで表示してみると 1088591716401 というような数値が取得できます。これがその 日付オブジェクトに設定されている現在の時刻です。
なおこの値は、ローカル時刻ではなくて世界標準時の 1970/01/01 を 0 としているようです。ちなみに日本時間で 1970/01/01 を設定した場合には経過ミリ秒数は -32,400,000 という値となりました。
さて上までで紹介したメソッドだけでも時刻を表示することに差し支えはないのですけど、日付オブジェクトはもっと簡単に日付文字列を取得することが出来るようになっています。メソッドを呼び出すだけで自動的に日付情報が生成されるので、体裁などを気にしない場合などは次のものを使うといいかもしれないです。
.toLocaleString() | 日付情報をローカル時刻として取得します。 | 2004年6月30日 19:35:16 |
---|---|---|
.toGMTString() | 日付情報を世界標準時 (GMT) として取得します。 | Wed, 30 Jun 2004 10:35:16 UTC |
.toUTCString() | 日付情報を国際協定時 (UTC) として取得します。 | Wed, 30 Jun 2004 10:35:16 UTC |
ところで、GMT 時刻と UTC 時刻とが同じ表示、しかも GMT の方でも UTC として表示されているのは正しいのでしょうか…。
そこで念のため、世界協定時刻 (UTC) について調べてみました。すると、世界標準時 (GMT) を基にして国際協定によって人工的に維持されている世界共通の標準時刻とのことでした。
国際協定時はセシウムという原子の振動回数を基準に決められていて、世界標準時は地球の自転を観測して決められる。けれど地球の自転というものは海の潮汐運動によって次第に長くなっていくらしく、世界標準時とのずれが生じてくるのだとか。そして世界標準時と比べて 0.9 秒より大きいずれが生じたときに閏秒として 1 秒が付け加えられ時刻が整えられる、そんな時刻なのだとか…。
パソコンにとっては原子の周期的な振動数の方があっているでしょうからそういうことになったのかもしれないですけど、それならば GMT か UTC のどちらかはかならず、パソコンでは誤差交じりで使い物にならないように思えるのですけど…。いえ、天文学系にはぜんぜん詳しくないのであくまでも勘なのですけどね。
自転周期が長くなるといっても規則的なのか…、そうだとするならば、原子の振動周期と計算して、どれくらいの間隔で 1 秒加えていけば良いかが算出できるかもしれないですね。そうだとすれば UTC が正確そうですね、逆に GMT だと誤差が生じることになるはずなのですけど。
調べたところによると UTC は約 1 年で 1 秒加えられるということらしいので、そうすると、パソコンの時刻は 1970 年からが基準となっているので、もし GMT がずれていたとするならば、2004 年現在で 30 秒ほど差が出てきているということなのでしょうか…。JavaScript では、というか今回の実験ではどちらも UTC っぽく出てしまっているようなのでなんともいえないのですけど。
それでも一応、ためしに "Wed, 30 Jun 2004 10:35:16 UTC" と "Wed, 30 Jun 2004 10:35:16 GMT" の二つの文字列から日付オブジェクトを作って .getTime() の値を比べてみましたが、これはまったく同じ値でした。
日付データを操作する
日付オブジェクトのデータを調整する
JavaScript の日付オブジェクトには、取得済みの日付データをいろいろと調整するメソッドも用意されています。
なので比較的簡単に、1ヵ月後などといったデータを作ることが可能となります。調整するのに使用するメソッドは次のとおりです。これについてもローカル時刻と国際協定時の二つが存在します。
.setTime() | 1970/01/01 GMT を 0 とした経過ミリ秒数を設定します。なお実験してみたところ、1970/01/01 JST は -32400000 でした。 |
---|---|
.setDate() | 日にちを設定します。普通に1日を 1 とします。 |
.setUTCDate() | |
.setFullYear() | 西暦の年数を 4 桁で設定します。2 桁で設定してみると、本当にその 2 桁の年で設定されるようでした。そのときの getTime() の値を見るとすごい負の値となります。 |
.setFullUTCYear() | |
.setYear() | 西暦の年数を 2 桁で取得できるはずなのですが、Windows XP + IE6.SP1 では 4 桁でも問題なく設定可能でした。2 桁の場合は 19xx となるようです。このメソッドは UTC 版は用意されていないようです。 |
- | |
.setMonth() | 月を設定します。これは 0 から始まる通し番号となるため、日本で馴染みの呼び方である1月は 0 となります。 |
.setUTCMonth() | |
.setHours() | 時を設定します。 |
.setUTCHours() | |
.setMinutes() | 分を設定します。 |
.setUTCMinutes() | |
.setSeconds() | 秒を設定します。 |
.setUTCSeconds() | |
.setMilliseconds() | ミリ秒を設定します。古い PC の場合は設定できないこともあるそうですが、その場合にエラーとなるかどうかは確認していません。 |
.setUTCMilliseconds() |
さて、この中で実験していて気になったことがあるのですけど、.setDate() メソッド、いえそれに限らず .setMonth() などもそうなのですけど、これらはありえない数値が与えられた場合でも問題なく動作するようです。たとえば setDate にてありえない日付、たとえば 40 日などを設定すると、しっかりと次の月へ溢れた分が繰り越されるようでした。もちろん月の値も次の月へ繰り上がっています。逆にマイナスの値を設定すれば、その分だけ戻された日付となりました。
調べてみると逆に 0-31 までというように範囲を明記しているところもあるので一概には言えないですけど、多くのサイトで当たり前のように語られ、しかも議論の題材となっているようですので、おそらくはこの動作が正常なのでしょうね。
だとすると、100 日後などというときも次のようにすればいいでしょうから、非常に便利ですね。
// 現在日時の 100 日後を取得する。
objDate.setDate(objDate.getDate() + 100);
表示桁数を整える
日付のデータはシステム固有の書式かまたは数字として取得できます。それらを表示する際に、気にしなければどうでもいいのですけど、たとえば日付を表示したいときに月と日の表示を 2 桁で統一したい場合もあるかと思います。
そんなときは substring 関数などをつかって調整してあげるといいかもしれません。もっと自然な方法があるかもしれませんけど、とりあえず思いつくのがこの方法でしたのでこれを例としてあげておくことにします。少し複雑になってしまうため、関数という形で用意してみることにします。
// 現在時刻を生成する関数
function DateToString(objDate)
{
var result = "";
var temp;
// 年はそのまま 4 桁を取得します。
result += objDate.getFullYear();
result += "/";
// 月は 2 桁になるように調整します。月は 0 から始まるので +1 を忘れずに。
// 調整は文字列として頭に "0" を付加して、後ろ 2 文字を切り出します。
temp = "0" + (objDate.getMonth() + 1);
temp = temp.substr(temp.length - 2, temp.length);
result += temp;
result += "/";
// 日も同様に調整します。
temp = "0" + objDate.getDate();
temp = temp.substr(temp.length - 2, temp.length);
result += temp;
// result に蓄えた値を返却します。
return result;
}
// 関数によって調整した文字列を表示します。
document.writeln("書式を調整して表示: " + DateToString(objDate) + "<br>");
こうすることで、表示結果は次のようになります。
書式を調整して表示: 2004/06/30
曜日を文字で表示する
曜日の情報を文字として表示させたい場合は、あらかじめその文字情報を配列として用意します。そして getDay メソッドによって該当する曜日文字列を取得します。
// あらかじめ、曜日文字列を用意します。
var week_label = new Array('SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT');
// 文字列に直したものを表示します。
document.writeln("曜日: " + week_label[objDate.getDay()] + "<br>");
このような感じで、曜日番号から曜日を取得することが出来ます。
曜日: WED
経過ミリ秒数を取得するメソッド
上で getTime() について触れましたが、これに似たメソッドとして parse メソッドと UTC メソッドというものが存在します。
これらも getTime() 同様に 1970/01/01 を 0 とした経過ミリ秒数を取得するメソッドなのですけど、使い方が異なって、日付オブジェクトに設定されているデータではなく、指定した日時までの経過ミリ秒数を取得することができます。
parse と UTC との違いは、parse では "2004/06/30 22:41:03" というような日付文字列を指定するのに対して、UTC の方は (2004, 5, 30, 22, 42, 06) というように、年月日時分秒 という順番の数値で指定します。UTC の方はまた、月の指定が 0 から始まる値である必要があるので注意が必要です。
実際にどのように使うかを見てみましょう。調べたときには次のように使用するものだとあったのですけど、実際にやってみたところエラーとなってしまいました。
// parse の場合(間違いらしい)
var pass_msec = (new Date()).parse("2004/06/30 22:41:03");
// UTC の場合(間違いらしい)
var pass_msec = (new Date()).UTC(2004, 5, 30, 22, 42, 06);
たしかに、日付オブジェクトの値に左右されないのにオブジェクトを作成してから使用するというのは不自然ですよね。C++ で言うならば静的関数として実装されるのが普通であるから…、と調べてみたところ次のように使用するのが正しいようです。
// parse の場合(正しいらしい)
var pass_msec = Date.parse("2004/06/30 22:41:03");
// UTC の場合(正しいらしい)
var pass_msec = Date.UTC(2004, 5, 30, 22, 42, 06);
2つともを一度に挙げましたが、このような感じに new を用いることなくいきなり Date を指定して呼び出すことで pass_msec に 1970/01/01 から指定した引数までの経過ミリ秒数を取得することが出来ます。
実際にどんな感じで使えるかを知るために、あくまでも一例ですけど、引数に渡された日付から今までの経過時間 (分) を計算する関数を作ってみることにします。
作成する関数は passtime というもので、引数として "2004/06/30 23:03" というような日付文字列を受け取るものとします。そして受け取った時刻から今 (現在時刻) に至るまでに何分経過したかというものを計算します。
function passtime(time_string)
{
// result は、経過分数を記録する変数です。ミリ秒で格納し、最後に分にします。
var result = 0;
// 日付オブジェクト objDate を現在時刻として作成します。
var objDate = new Date();
// 現在時刻の経過ミリ秒数から、渡された日付文字列の経過ミリ秒数を引いて、それを result へ格納します。
result = objDate.getTime() - Date.parse(time_string);
// 経過ミリ秒数を経過分数にして返却します。
return parseInt(result / 1000 / 60);
}
これを、たとえば passtime("2004/06/30 23:03") というように呼び出せば、その引数に渡された時刻から現在までに経過した通算の分数が取得できます。
[ もどる ]