FOT.Time(時間変換) - fairy.ouchi.to


ソース


警告

この取説は現状の FOT.Time の仕様に基づくものです。
今後 FOT.Time の仕様が変更される可能性があります。


概要

入力した時刻を、別の形式に変換します。

概念的には、JavaScript の Date クラスの類似品だと考えてください。
Date では setTime(ミリ秒) で時刻を設定し、getFullYear() や toUTCString() で時刻を取り出しますが、 このクラスも同様に、unix(秒) で時刻を設定して、year() や toString("UTC") で取り出すといった操作をします。

Date と違うのは、Date が UNIX時間( getTime )、西暦の世界時( getUTCFullYear, getUTCMonth ... )、 西暦の地方時( getFullYear, getMonth ... ) の3つの時間形式を扱うのに対して、 こちらはその他にいくつかの入出力が可能となっています。
また、設定可能な時刻の範囲が実用上十分な程度(*1)に広いです。なお、ミリ秒は扱えません。

入出力可能な形式は、西暦(グレゴリオ暦)の世界時/地方時、旧西暦(ユリウス暦)の世界時/地方時、 基準時刻からの秒数(UNIX時間/環境依存)、ユリウス日/修正ユリウス日、天晶暦(FINAL FANTASY XI)です。

基本的には「日付の変換(*2)」を行うクラスなので、 「日付の演算(*3)」は用意していませんが、一部、日付操作用のメソッドが存在します。
その他、ごく単純な書式化出力が可能です。

(*1) 限界値は環境依存。現在の一般的なブラウザであれば±1億8千万年は保証。詳細は後述。

(*2) 「日本時間○○日○○時はドイツで何時?」などの、時刻→時刻の変換。

(*3) 「○○日○○時の○○時間後は?」などの、時刻+時間量や時間量+時間量の計算。


基本的な使い方


// time.js を読み込んで、FOT.Time を使えるようにしておきます。
// ※ 変数 FOT 以外の名前空間への汚染はありません。

let time = FOT.Time();

// 世界時1970年1月1日0時のUNIX時間を取得
// ( sec = 0 )
let sec = time.ce([1970, 1, 1, 0, 0, 0], "UTC").unix();

// 修正ユリウス日0日の世界時を取得
// ( date = [1858, 11, 17, 0, 0, 0] )
let date = time.mjd(0).ce("UTC");

// 日本時間2001年2月3日4時5分6秒のアメリカ太平洋標準時間を取得
// ( pst = [2001, 2, 2, 11, 5, 6] )
let pst = time.ce([2001, 2, 3, 4, 5, 6], "JST").ce("PST");

メソッド一覧

コンストラクタ
FOT.Time
基本入出力メソッド
set
get
ce, gc, jc, unix, time, jd, mjd, ffxi
特定時刻設定メソッド
setNowTime
setToday, setYesterday, setTomorrow
setThisMonth, setLastMonth, setNextMonth
setThisYear, setLastYear, setNextYear
書式化出力メソッド
format
date
year, month, day, hour, min, sec, wday
toString
tzString
状態変更メソッド
ceType
tz
コピー・比較メソッド
clone
cmp

やたら多いように見えますが、最も基本になるのが set / get / format で、 他の大半は構文糖(基本メソッドに特定引数を渡す場合の別名)です。


コンストラクタ

FOT.Time のインスタンスを生成します。引数がない場合は現在時刻が設定されます。
引数として set メソッドと同じ引数を受け取ることができ、その場合は引数を set メソッドに渡して実行した上で返します。 詳細は set メソッドの項目を参照して下さい。

time = FOT.Time();
time = FOT.Time( mixed value [, string time_name = this.ceType() [, mixed time_zone = this.tz() ]] );

// 以下の3つの動作は全て等価です。
time = FOT.Time( value [, time_name [, time_zone ]] );
time = FOT.Time().set( value [, time_name [, time_zone ]] );
time = FOT.Time().time_name( value [, time_zone ] );


基本入出力メソッド

set (時刻の設定)

特定の時間名文字列と、各時間名ごとの引数を渡して時刻を設定します。
戻り値として、(時刻が設定された)インスタンス自身が返ります。

time = time.set( mixed value [, string time_name = this.ceType() [, mixed time_zone = this.tz() ]] );

value:設定する時間の値。
実際に渡すものは第2引数に渡す時間名によって異なります。

第2引数が "ce", "gc", "jc", "ffxi" の場合
[年, 月, 日, 時, 分, 秒] の6要素の数値配列(*1)。全て整数のみ。
第2引数が "unix", "time" の場合
数値(秒)。整数のみ。
第2引数が "jd", "mjd" の場合
数値(日)。小数可。

time_name:時間名。以下のいずれかの文字列です。

"ce"
西暦(グレゴリオ暦 / ユリウス暦)
※ ce は christian era (C.E.) のこと。
※ 実際の動作は ceType() で設定されている値によって gc か jc のいずれかになる。
"gc"
西暦(グレゴリオ暦)
※ gc は gregorian calendar (英: New Style / N.S.) のこと。
"jc"
旧西暦(ユリウス暦)
※ jc は julian calendar (英: Old Style / O.S.) のこと。
"unix"
UNIX時間
※ 1970-01-01 00:00:00 からの通算秒数
"time"
環境依存の秒数(*2)
"jd"
ユリウス日
※ jd は julian day のこと。
"mjd"
修正ユリウス日
※ mjd は modified julian day のこと。
"ffxi"
天晶暦(FINAL FANTASY XI)
※ MMORPG「FINAL FANTASY XI」のゲーム内時間

time_zone:時間帯。時間名に西暦/旧西暦( "ce", "gc", "jc" )を指定した場合のみ入力します。
世界時との時差を、数値(秒単位), UTC±hh:mm, UTC±h, 時間帯名("JST"など)のいずれかで指定します。

戻り値time:時刻が設定された FOT.Time。

(*1) 全て「その時刻そのもの」を入力します。 たとえば、1998年4月3日20時5分33秒を設定する場合、[1998, 4, 3, 20, 5, 33] を渡します。 西暦4ケタを下2ケタ入力で認識したりはできません。 また、月は 1~12 です。0~11 ではありません。 0を入力すると、前年12月と解釈されます。
紀元前の年を入力する場合は、単純に通算年数で数えます。つまり紀元前1年が0、紀元前2年が-1となります。

(*2) 現在はUNIX時間と全く同じです。この仕様は変更される可能性があります。非推奨。


get (時刻の取得)

特定の時間名文字列を渡して時刻を取得します。

mixed value = time.get( [ string time_name = this.ceType() [, mixed time_zone = this.tz() ]] );

time_name:時間名。set メソッドと全く同じです。

time_zone:時間帯。set メソッドと全く同じです。

戻り値value:それぞれの時間名での時刻。
戻り値の形式は set メソッドの第1引数の形式と同じです。 たとえば時間名が "ce" の場合、戻り値として6要素を持つ配列 [年,月,日,時,分,秒] が返ります。


時間名メソッド (時刻の取得/設定)

set / get メソッドは、引数として時間名を受け取りますが、各時間名と同名のメソッドが存在します。

これらのメソッドは、引数に応じて set / get のいずれかになります。
つまり、time.set( value, time_name [, time_zone ] ) は、 time.time_name( value [, time_zone ] ) として記述でき、 time.get( time_name [, time_zone ] ) は、 time.time_name( [ time_zone ] ) として記述できるわけです。

set メソッドの場合

time = time.ce( array value [, mixed time_zone = this.tz() ] ); // 西暦(グレゴリオ暦 / ユリウス暦)
time = time.gc( array value [, mixed time_zone = this.tz() ] ); // 西暦(グレゴリオ暦)
time = time.jc( array value [, mixed time_zone = this.tz() ] ); // 旧西暦(ユリウス暦)
time = time.unix( number value ); // UNIX時間
time = time.time( number value ); // 環境依存の秒数
time = time.jd( number value ); // ユリウス日
time = time.mjd( number value ); // 修正ユリウス日
time = time.ffxi( array value ); // 天晶暦(FINAL FANTASY XI)

get メソッドの場合

array value = time.ce( [ mixed time_zone = this.tz() ] ); // 西暦(グレゴリオ暦 / ユリウス暦)
array value = time.gc( [ mixed time_zone = this.tz() ] ); // 西暦(グレゴリオ暦)
array value = time.jc( [ mixed time_zone = this.tz() ] ); // 旧西暦(ユリウス暦)
number value = time.unix(); // UNIX時間
number value = time.time(); // 環境依存の秒数
number value = time.jd(); // ユリウス日
number value = time.mjd(); // 修正ユリウス日
array value = time.ffxi(); // 天晶暦(FINAL FANTASY XI)


特定時刻メソッド

現在設定されている時刻を元にして、引数で指定された特定の時刻を設定します。

これらのメソッドは全て、内部で set を呼んで、自身に設定されている時刻を再設定します。
また、戻り値として set と同様に、インスタンス自身を返します。

setNowTime 以外の9つのメソッドは、 [年,月,日,時,分,秒] の概念がある時間名("ce", "gc", "jc", "ffxi")でのみ利用可能です。 特定時刻メソッドにこれ以外の時間名を渡した場合、設定は行われず戻り値が undefined になります。


setNowTime (現在時刻の設定)

実行された時点の( JavaScript の実行環境の )現在時刻を設定します。

time = time.setNowTime();

戻り値time:時刻が設定された FOT.Time。


setToday / setYesterday / setTomorrow (今日/昨日/明日の0時を設定)

それぞれ、引数で指定された暦における、今日/昨日/明日の0時0分0秒に設定します。

time = time.setToday( [ string time_name = this.ceType() [, mixed time_zone = this.tz() ]] );
time = time.setYesterday( [ string time_name = this.ceType() [, mixed time_zone = this.tz() ]] );
time = time.setTomorrow( [ string time_name = this.ceType() [, mixed time_zone = this.tz() ]] );

time_name:時間名。"ce", "gc", "jc", "ffxi" のいずれかの文字列です。

time_zone:時間帯。set メソッドと全く同じです。

戻り値time:時刻が設定された FOT.Time。


setThisMonth / setLastMonth / setNextMonth (今月/先月/来月の1日0時を設定)

それぞれ、引数で指定された暦における、今月/先月/来月の1日0時0分0秒に設定します。

time = time.setThisMonth( [ string time_name = this.ceType() [, mixed time_zone = this.tz() ]] );
time = time.setLastMonth( [ string time_name = this.ceType() [, mixed time_zone = this.tz() ]] );
time = time.setNextMonth( [ string time_name = this.ceType() [, mixed time_zone = this.tz() ]] );

time_name:時間名。"ce", "gc", "jc", "ffxi" のいずれかの文字列です。

time_zone:時間帯。set メソッドと全く同じです。

戻り値time:時刻が設定された FOT.Time。


setThisYear / setLastYear / setNextYear (今年/去年/来年の1月1日0時を設定)

それぞれ、引数で指定された暦における、今年/去年/来年の1月1日0時0分0秒に設定します。

time = time.setThisYear( [ string time_name = this.ceType() [, mixed time_zone = this.tz() ]] );
time = time.setLastYear( [ string time_name = this.ceType() [, mixed time_zone = this.tz() ]] );
time = time.setNextYear( [ string time_name = this.ceType() [, mixed time_zone = this.tz() ]] );

time_name:時間名。"ce", "gc", "jc", "ffxi" のいずれかの文字列です。

time_zone:時間帯。set メソッドと全く同じです。

戻り値time:時刻が設定された FOT.Time。


書式化出力メソッド

設定されている時間を、引数に基づいて文字列(一部は数値)として返すメソッドです。

これらのメソッドは全て、内部で get を呼んで、自身に設定されている時刻から文字列を組み立てて返します。 呼び出しによって設定されている時刻が書き換わることはありません。

いずれも、引数として時間名を受け取りますが、 [年,月,日,時,分,秒] の概念がある時間名("ce", "gc", "jc", "ffxi")でのみ利用可能です。
書式化出力メソッドに無効な時間名を渡した場合、戻り値は undefined になります。


format (設定時刻の文字列化)

第1引数に "%Y年%M月%D日(%jW) %2h:%2m:%2d" といった文字列を渡して、それを元に組み立てた文字列を返します。
置換部分の処理がかなり適当なので、複雑な文字列を組み立てると予期せぬ置換を行うかもしれません。

string value = time.format( string value_template [, string time_name = this.ceType() [, mixed time_zone = this.tz() ]] );

value_template:書式化文字列。
文字列中に専用の置換文字が含まれていると、それぞれ置換されます。 書式化文字列の中に "%" を記述する場合は "%%" としてください。

置換文字:%Y (年)、%M (月)、%D (日)、%h (時)、%m (分)、%s (秒)、%W (曜日)、%% (%)

% と後続文字の間にオプション1文字を指定することができます。
オプションがない場合は数値に置換されます。

"1" ~ "9" : オプションとして数値1文字を指定すると、数値がそのケタ数に足りなければ前方0埋めされ、 ケタ数が多すぎる場合は上位ケタを切り詰めます。

"e" : %M / %W のみ指定可能です。英名に置換されます。
"s" : %M / %W のみ指定可能です。英名短縮に置換されます。
"j" : %M / %W のみ指定可能です。日本語名に置換されます。

time_name:時間名。"ce", "gc", "jc", "ffxi" のいずれかの文字列です。

time_zone:時間帯。set メソッドと全く同じです。

戻り値value:置換された文字列


date (設定時刻の特定の値を返す)

format の内部で呼んでいる関数を直接呼ぶためのメソッドです。
format で使用可能なオプションを指定して値を取りだすことができます。

mixed value = time.date( string time_type [, mixed value_type = "n" [, string time_name = this.ceType() [, mixed time_zone = this.tz() ]]] );

time_type:時間種類。以下のいずれかの文字列です。

"year"
"month"
"day"
"hour"
"min"
"sec"
"wday"
曜日

value_type:戻り値の形式
ケタ数を表す数値 1 ~ 9 を指定するか、または以下のいずれかの文字です。
format で "e", "s", "j" のオプションが指定できるのは %M / %W のみです。 このメソッドでも同じなので注意して下さい。 "n" を指定した(または省略した)場合は、文字列ではなく数値を返します。

"n"
数値
1 ~ 9
指定ケタ数になるよう前方0埋めした文字列
"e"
英名
"s"
英名短縮
"j"
日本語名

time_name:時間名。"ce", "gc", "jc", "ffxi" のいずれかの文字列です。

time_zone:時間帯。set メソッドと全く同じです。

戻り値value:文字列あるいは数値


時間種類メソッド (設定時刻の特定の値を返す)

date メソッドは、第1引数として時間種類を受け取りますが、各時間種類と同名のメソッドが存在します。

これらのメソッドは、date メソッドと同等です。
つまり、time.date( time_type [, value_type [, time_name [, time_zone ]]] ) は、 time.time_type( [ value_type [, time_name [, time_zone ]]] ) として記述できるわけです。

mixed value = time.year( [ mixed value_type = "n" [, string time_name = this.ceType() [, mixed time_zone = this.tz() ]]] );
mixed value = time.month( [ mixed value_type = "n" [, string time_name = this.ceType() [, mixed time_zone = this.tz() ]]] );
mixed value = time.day( [ mixed value_type = "n" [, string time_name = this.ceType() [, mixed time_zone = this.tz() ]]] );
mixed value = time.hour( [ mixed value_type = "n" [, string time_name = this.ceType() [, mixed time_zone = this.tz() ]]] );
mixed value = time.min( [ mixed value_type = "n" [, string time_name = this.ceType() [, mixed time_zone = this.tz() ]]] );
mixed value = time.sec( [ mixed value_type = "n" [, string time_name = this.ceType() [, mixed time_zone = this.tz() ]]] );
mixed value = time.wday( [ mixed value_type = "n" [, string time_name = this.ceType() [, mixed time_zone = this.tz() ]]] );


toString (設定時刻の特定文字列化)

設定されている時刻を元に、文字列化したものを返します。時間名は常に西暦(グレゴリオ暦)になります。
JavaScript の Date.toUTCString とほぼ同じです。

string value = time.toString( [ string time_zone_name = "GMT" ] );

time_zone_name:時間帯名。"UTC", "GMT", "JST"など。

戻り値value:文字列


tzString (時間帯を文字列にして返す)

時間帯を "UTC±hh:mm" 形式の文字列にして返します。

このメソッドには、他のメソッドと同様にインスタンスから呼び出すメソッドの他に、同名の静的メソッドが存在します。
前者は引数を取らず、tz() で設定されている時間帯を文字列にして返しますが、 後者は引数として時間帯を受け取り、それを文字列にして返します。
戻り値の文字列は、他のメソッドの引数に指定する時間帯として有効な UTC±hh:mm 形式の文字列です。

string value = time.tzString();
string value = FOT.Time.tzString( mixed time_zone );

time_zone:時間帯。set メソッドと全く同じです。

戻り値value:"UTC±hh:mm" 形式の時間帯文字列


省略値変更メソッド

時間名に ce を指定、または時間名を省略した場合、ceType() に設定されている値が時間名の省略値となります。
同様に、時間帯を省略した場合は tz() に設定されている値が時間帯の省略値となります。

これらのメソッドは必ずしも使用する必要はありません。
時間名/時間帯を受け取る全ての操作において、値を直接指定することで、これらの省略値に関わり無くメソッドを利用できます。

これらのメソッドは、FOT.Time クラスの使い方を十分に理解した上で、 毎回同じ引数を指定する煩雑さを軽減するために、省略値を設定できるようにしたものです。


ceType (時間名の省略値)

setter として扱うか getter として扱うかで挙動が変わります。

getter として扱う場合、このメソッドは現在 ceType に設定されている時間名を返します。
初期値は "gc" です。

setter として扱う場合、このメソッドは引数として "gc" と "jc" のどちらかを受け取り、 戻り値としてインスタンス自身を返します。


tz (時間帯の省略値)

setter として扱うか getter として扱うかで挙動が変わります。

getter として扱う場合、このメソッドは現在 tz に設定されている時間帯を秒単位で返します。
初期値は (JavaScriptの) Date.getTimezoneOffset() * -60 です。
(※ JavaScript の実行環境の時間帯が設定されるということです。)

setter として扱う場合、このメソッドは引数として時間帯(set メソッドと全く同じ形式)を受け取り、 戻り値としてインスタンス自身を返します。


コピー・比較メソッド


clone (インスタンスのコピー)

同じ時刻を設定した別のインスタンスを生成して返します。

time2 = time.clone();

戻り値time2:時刻が設定された FOT.Time。

動作としては以下のようになります。


// 日本時間 2001-01-01 00:00:00 でインスタンスを作成
let time_a = FOT.Time([2001, 1, 1, 0, 0, 0], "gc", "JST");

// 同じ時刻を設定した別のインスタンスを生成する
let time_b = time_a.clone();

// 以下とほぼ同等(*)
// let time_b = FOT.Time(time_a.unix(), "unix").ceType(time_a.ceType()).tz(time_a.tz());

(*) 厳密には、後述する限界値の関係で、実行環境における数値の限界を超えた範囲の時間を扱っている場合に限って、 このサンプルの操作ではズレが生じます。clone メソッドは、このクラスで維持可能な最大精度での複製を行います。


cmp (時刻の比較)

2つの時刻を比較して、-1 / 0 / 1 のいずれかを返します。
Perlにある <=> 演算子のようなものです。

number value = time.cmp( time2 );

time2:比較対象の FOT.Time。

戻り値value:比較結果(-1 / 0 / 1 のいずれか)


// 日本時間 2001-01-01 00:00:00 でインスタンスを作成
let time_a = FOT.Time([2001, 1, 1, 0, 0, 0], "gc", "JST");

// 日本時間 2000-01-02 00:00:00 でインスタンスを作成
let time_b = FOT.Time([2000, 1, 2, 0, 0, 0], "gc", "JST");

let x = time_a.cmp(time_b);

if (x < 0)
{
    // time_a の方が早い(時間が前)
}
else if (x > 0)
{
    // time_a の方が遅い(時間が後)
    // このサンプルではここが実行される
}
else
{
    // 2つは同じ時刻
}

ce / gc / jc で渡すことが可能な時間帯

"ce", "gc", "jc" の時間帯(time_zone)は、下記のいずれかの形式で指定します。
tz() の戻り値は数値(秒単位)、tzString() の戻り値は UTC±hh:mm です。範囲外の値は全て0として扱われます。

数値
秒単位。-71940 ~ 71940
※ 入力は秒単位だが、秒部分は切り捨てされる。事実上分単位でのみ入力可。
UTC±hh:mm
分単位。UTC+00:00 ~ UTC+19:59、UTC-00:00 ~ UTC-19:59
UTC±h
時単位。UTC+0 ~ UTC+19、UTC-0 ~ UTC-19
時間帯名
次項の表の文字列。

時間帯名の一覧

時間帯名は、原則としてPostgreSQLのマニュアルを元にしています(*)。

文字列 時差 地域名 英名
GMT00:00グリニッジ標準時Greenwich Mean Time
UT00:00世界時Universal Time
UTC00:00協定世界時Coordinated Universal Time
ZULU00:00ZuluUTC ISO-8601
Z00:00ZuluUTC ISO-8601
IDLE+12:00国際日付変更線(東側)International Date Line, East
IDLW-12:00国際日付変更線(西側)International Date Line, West
JST+09:00日本標準時間Japan Standard Time
KST+09:00韓国標準時間Korea Standard Time
CCT+08:00中国湾岸時間China Coastal Time
MMT+06:30ミャンマー時間Myanmar Time
JT+07:30ジャワ島時間Java Time
MT+08:30モルッカ諸島時間Moluccas Time
IOT+05:00インドチャゴス時間Indian Chagos Time
MVT+05:00モルディブ島時間Maldives Island Time
IRT+03:30イラン時間Iran Time
IT+03:30イラン時間Iran Time
BT+03:00バグダッド時間Baghdad Time
IST+02:00イスラエル標準時間Israel Standard Time
AFT+04:30アフガニスタン時間Afganistan Time
EET+02:00東ヨーロッパ時間Eastern Europe Time
CET+01:00中央ヨーロッパ時間Central European Time
MET+01:00中央ヨーロッパ時間Middle Europe Time
WET00:00西ヨーロッパ時間Western Europe Time
EETDST+03:00東ヨーロッパ夏時間Eastern Europe Daylight Savings Time
CETDST+02:00中央ヨーロッパ夏時間Central European Daylight Savings Time
METDST+02:00中央ヨーロッパ夏時間Middle Europe Daylight Time
WETDST+01:00西ヨーロッパ夏時間Western Europe Daylight Savings Time
CEST+02:00中央ヨーロッパ夏時間Central European Daylight Savings Time
MEWT+01:00中央ヨーロッパ冬時間Middle Europe Winter Time
MEST+02:00中央ヨーロッパ夏時間Middle Europe Summer Time
MEZ+01:00中央ヨーロッパ地域時間Middle Europe Zone
BST+01:00イギリス夏時間British Summer Time
BDST+02:00イギリス二重標準時間British Double Standard Time
FWT+02:00フランス冬時間French Winter Time
FST+01:00フランス夏時間French Summer Time
HMT+03:00ギリシャ/ヘラ地中海時間Hellas Mediterranean Time
DST+01:00デンマーク標準時間Dansk Standard Time
DNT+01:00デンマーク時間Dansk Normal Time
SWT+01:00スウェーデン冬時間Swedish Winter Time
SST+02:00スウェーデン夏時間Swedish Summer Time
NOR+01:00ノルウェー標準時間Norway Standard Time
ALMT+06:00アルマトイ時間Almaty Time
ALMST+07:00アルマトイ夏時間Almaty Summer Time
EAT+03:00アンタナナリボ、コモロ時間Antananarivo, Comoro Time
SCT+04:00マーヘ島時間Mahe Island Time
RET+04:00レユニオン島時間Reunion Island Time
MUT+04:00モーリシャス島時間Mauritius Island Time
SET+01:00セイシェル時間Seychelles Time
WAT-01:00西アフリカ時間West Africa Time
EST-05:00アメリカ東部標準時間Eastern Standard Time
CST-06:00アメリカ中部標準時間Central Standard Time
MST-07:00アメリカ山岳部標準時間Mountain Standard Time
PST-08:00アメリカ太平洋標準時間Pacific Standard Time
EDT-04:00アメリカ東部夏時間Eastern Daylight Time
CDT-05:00アメリカ中部夏時間Central Daylight Time
MDT-06:00アメリカ山岳部夏時間Mountain Daylight Time
PDT-07:00アメリカ太平洋夏時間Pacific Daylight Time
NST-03:30ニューファンドランド標準時間Newfoundland Standard Time
NFT-03:30ニューファンドランド時間Newfoundland Time
NDT-02:30ニューファンドランド夏時間Newfoundland Daylight Time
YST-09:00ユーコン標準時間Yukon Standard Time
YDT-08:00ユーコン夏時間Yukon Daylight Time
AKST-09:00アラスカ標準時間Alaska Standard Time
AKDT-08:00アラスカ夏時間Alaska Daylight Time
CAT-10:00中央アラスカ時間Central Alaska Time
AHST-10:00アラスカ-ハワイ標準時間Alaska-Hawaii Standard Time
BRT-03:00ブラジリア時間Brasilia Time
BRST-02:00ブラジリア夏時間Brasilia Summer Time
FNT-02:00フェルナンド・デ・ノローニャ時間Ferdinand De Norornya Time
FNST-01:00フェルナンド・デ・ノローニャ夏時間Ferdinand De Norornya Summer Time
HST-10:00ハワイ標準時間Hawaii Standard Time
HDT-09:00ハワイ夏時間Hawaii Daylight Time
GST+10:00グアム標準時間Guam Standard Time
AEST+10:00オーストラリア東部標準時間Australia Eastern Standard Time
ACST+09:30オーストラリア中部標準時間Australia Central Standard Time
AWST+08:00オーストラリア西部標準時間Australia Western Standard Time
AESST+11:00オーストラリア東部夏時間Australia Eastern Summer Standard Time
ACSST+10:30オーストラリア中部夏時間Australia Central Summer Standard Time
AWSST+09:00オーストラリア西部夏時間Australia Western Summer Standard Time
EAST+10:00オーストラリア東部標準時間East Australian Standard Time
CAST+09:30オーストラリア中部標準時間Central Australia Standard Time
WAST+08:00オーストラリア西部標準時間West Australian Standard Time
EADT+11:00オーストラリア東部夏時間East Australian Daylight Time
CADT+10:30オーストラリア中部夏時間Central Australia Daylight Time
WADT+09:00オーストラリア西部夏時間West Australian Daylight Time
LIGT+10:00オーストラリア/メルボルン時間Melbourne, Australia
NZT+12:00ニュージーランド時間New Zealand Time
NZST+12:00ニュージーランド標準時間New Zealand Standard Time
NZDT+13:00ニュージーランド夏時間New Zealand Daylight Time
CXT+07:00クリスマス島時間Christmas Island Time
MART-09:30マルケサス諸島時間Marquesas Time
MHT+09:00マーシャル群島、クワジュリン時間Kwajalein Time
ACT-05:00大西洋/ポルトアクリ標準時間Atlantic/Porto Acre Standard Time
AST-04:00(カナダ)大西洋標準時間Atlantic Standard Time (Canada)
ADT-03:00大西洋夏時間Atlantic Daylight Time
NT-11:00ノーム時間Nome Time
TFT+05:00ケルゲレン諸島時間Kerguelen Time
MAWT+06:00モーソン時間(南極大陸)Mawson (Antarctica) Time
AWT-03:00(不明)(Unknown)

(*) そもそも時間帯名は非常に重複が多く、しかも、どうやら統一された標準が存在しないようです。
たとえば、PostgreSQLではISTをイスラエル標準時間としているので、このクラスでもそれに準じていますが、 ウィキペディアでは、 ISTをインド標準時間として表記していますし、あるいは両方の名前として載せてるサイトもあったりします。
よって、このクラスで使用している時間帯名は、必ずしも他で通用するとは限らないことにご注意ください。


PostgreSQLとの相違点

(*1) わたしがざっと探した限り、EADTという時間帯名は一般的には使われていないようです。 少なくとも、それっぽいサイトをググって見つかる範囲で、 普通に使ってるらしいのはCiscoのIP電話くらいです。

(*2) アメリカでは、EST, CST, MST, PST をそれぞれ自国の時間帯名として使用しているようです。
一方、オーストラリアでは、EST, CST, WST をそれぞれ自国の時間帯名として使用しているようです。
EST, CST が重複するので、これらの記号はアメリカ側に合わせ、重複しないWSTも、整合性の点から削除しました。 オーストラリアは AEST, ACST, AWST を使用してください。

(*3) SAST, SADT(オーストラリア南部標準時間/夏時間)は、それぞれCAST, CADT(オーストラリア中部標準時間/夏時間) と同一です。 SAST, SADTを入力可能にすると、整合性の点から、ASST, ASSST(笑) も入力可能にするべき、なんてことになりそうなので削除しました。


仕様や設計方針などについてのあれこれ

このクラスを使用する際に留意しておくべき事柄など。


引数の検査

かなり適当です。このマニュアルに明記されている以外の引数を渡せば、エラーが発生したり、想定外の動作をすることになります。
たとえば set に時間名として "hasOwnProperty" という文字列を渡せば、エラーで実行停止するはずです。
また、get に"hasOwnProperty" を渡すと、意味不明な値を返します。

止まってはいけないプログラムで利用するのであれば、自分で try-catch するなり、引数と戻り値を完全にチェックするなりしてください。
最も適切な対応として、大切なプログラムでは、このライブラリを利用しないことをオススメします。


計算可能な時間の範囲

このクラスで扱える時間の範囲は、
JavaScript の実行環境に依存します。

現在の一般的なブラウザでは、JavaScript の数値を IEEE754 に準拠した変数で扱います。
それらのブラウザであれば、西暦(グレゴリオ暦)で±1億8千万年程度が、 全ての時間名について、精度を保証できる限界になります。

IEEE754 で整数の加減算の精度が保証できるのは ±9007199254740991(=0x1FFFFFFFFFFFFF) の範囲であるため、 これをUNIX時間に換算して、グレゴリオ暦世界時で B.C.285424813-02-21 01:23:29 ~ A.D.285428751-11-12 16:36:31 が、 UNIX時間の限界ということになります。

しかし、あまりに大きな数に対しては小数点以下の精度が悪くなることから、 小数を扱うユリウス日/修正ユリウス日は、この範囲ぎりぎりでは精度が維持できません。 ユリウス日/修正ユリウス日で ±1億8千万年を超える時刻を扱うと、 小数点以下のケタ数が少なすぎて精度を維持できず、時間が秒単位でズレるようになります。 よって、±1億8千万年程度が秒単位の精度を保証できる限界です。
逆に言うと、秒単位の精度が必要ない場合は、これ以上の時間に対して計算しても正しい値が得られます。 たとえば当日の世界時午前0時ジャストのユリウス日/修正ユリウス日を求めるだけなら、 小数点以下は 0 か 0.5 だけなので、±12兆年の範囲で精度が保証できます。
なお、地方時を扱う場合は分単位での精度が必要なので、範囲はこれよりも小さくなります。 単純計算で、±108億年(=1億8000万年×60)ほどです。

UNIX時間/ユリウス日/修正ユリウス日のいずれも扱わない場合、 時間を単一の数値として扱う必要がなくなるので、精度が保証できる限界は飛躍的に大きくなります。

前述の時間以外で、精度の保証が可能な範囲が最も小さいのは天晶暦ですが、 他の時間を天晶暦に変換する、または天晶暦を他の時間に変換する場合は、 西暦換算で ±350兆年 がおおよその目安となります。
UNIX時間/ユリウス日/修正ユリウス日/天晶暦のいずれでもなく、 単に西暦(グレゴリオ暦/ユリウス暦の世界時/地方時)同士の変換を行う場合は±9千兆年程度です。

まとめると、精度が保証できる限界は以下の通りです。

±1億8千万年
全ての時間で精度が保証できる
ユリウス日/修正ユリウス日(jd, mjd)の秒精度保証限界
±2億8千万年
UNIX時間(unix, time)の精度保証限界
±108億年
ユリウス日/修正ユリウス日(jd, mjd)の分精度保証限界
±12兆年
ユリウス日/修正ユリウス日(jd, mjd)の半日精度保証限界
±350兆年
天晶暦(ffxi)の精度保証限界
±9千兆年
西暦(ce, gc, jc)の精度保証限界

なお、内部計算に使用している "total" は ±360京年(=9千兆年の400倍) 程度の精度があります。 内部の処理は全て「入力された時間を "total" に変換」「"total"を指定された時間に変換して出力」という操作なので、 変換時の内部計算における精度落ちを考慮する必要はありません。


設計方針

この説明ページはやたら長いですが、慣れれば使い方は単純なはずです。
要するに、複数の時間名( "gc", "jc", "unix" ... )を set で設定して、 それを複数の時間名( "gc", "jc", "unix" ... )として get で取り出すことができると、それだけです。 曜日のみ、get では取り出すことができないので、wday か format を使う必要があります。

元々の設計方針は、時間変換の書式の汎用化です。
たとえば UNIX時間から西暦への変換、あるいはその逆を行う場合、以下のように記述します。


let arr = time.unix(0).gc("UTC"); // arr = [1970, 1, 1, 0, 0, 0]
let unix = time.gc([1970, 1, 1, 0, 0, 0], "UTC").unix(); // unix = 0

ここで、UNIX時間ではなく修正ユリウス日を扱いたい場合には、このようになります。


let arr = time.mjd(0).gc("UTC"); // arr = [1858, 11, 17, 0, 0, 0]
let mjd = time.gc([1858, 11, 17, 0, 0, 0], "UTC").mjd(); // mjd = 0

UNIX時間をグレゴリオ暦に(unix → gc)という変換は、unix(引数).gc() と記述でき、 グレゴリオ暦を修正ユリウス日に(gc → mjd)という変換は、gc(引数).mjd() と記述できるわけです。
このクラスで扱える全ての時間名で、このような記述が可能になるように設計しています。

コンストラクタの引数は set メソッドと同様なので、いちいちインスタンスを作りたくない場合には、 コンストラクタに引数を渡して直後にgetすることも可能です。


let arr = FOT.Time(0, "unix").gc("UTC"); // arr = [1970, 1, 1, 0, 0, 0]
let unix = FOT.Time([1970, 1, 1, 0, 0, 0], "gc", "UTC").unix(); // unix = 0

また、setter になるメソッドは、全てインスタンス自身を返すように設計しているので、 たとえばユーザーが入力した時刻(グレゴリオ暦)の当日午前0時(日本時間)のUNIX時間を求める場合は、 間に setToday を挟んで、以下のように記述できます。


let date = [year, month, day, hour, min, sec]; // ユーザーが入力した時刻
let unix = time.gc(date, "JST").setToday("gc", "JST").unix();

ここで、一連の操作で gc や JST が複数回出てくる場合があることが分かったと思います。
ceType や tz による省略値の設定は、これを軽減するためのもので、以下のように記述しても同じになります。


time.ceType("gc").tz("JST");
let unix = time.ce(date).setToday().unix();

時間の仕組み自体が複雑なので、時間を扱うための基本メソッドを網羅するように設計したこのクラスも複雑に見えるかと思います。 実際、ある程度時間の仕組みを把握していないと、とても扱いきれるものではないと思います。
ただ、その把握さえできてしまえば、適切な省略値を設定することで十分に単純な書式で利用できるように設計しているつもりです。


日付の演算

最初に『「日付の演算」機能はない』と書きましたが、もちろん「日付とはなにか」を正しく理解している方なら、 「日付の変換」さえできれば、演算なんて楽勝だということはお分かりのはずです。
秒差を求めるなら、


let time_diff = FOT.Time([年,月,日,時,分,秒]).unix() - FOT.Time([年,月,日,時,分,秒]).unix();

で、全く問題なく計算できます。
では、なぜ演算関係のメソッドを作らないのかというと、西暦の加減算というものは、秒単位で定義することができないからです。

たとえば「1月30日の1か月後は何月何日ですか?」という話です。
一般に、1月1日の1か月後は2月1日、1月10日の1か月後は2月10日、1月25日の1か月後は2月25日ですが、 1月30日の1か月後は「だいたい2月末」としか表現できません。 『1か月』や『1年』という期間は、日数にすると値が可変なのです。

このクラスで、2001年1月30日の1か月後を単純に+1で入力すると、3月2日になります。
計算過程は以下の通り。

  1. time.gc([2001, 1 + 1, 30, 0, 0, 0])
  2. => 2001-02-30
  3. => 2001-02-28 + 2
  4. => 2001-03-02

一般的には、1月30日の1か月後は3月2日にはなりません。3月2日の1か月前は2月2日です。
でも、[1月30日の1か月後]→[1月1日の29日後の1か月後]→[1月1日の1か月後の29日後]→[2月1日の29日後]→[3月2日]。 ある意味では、これも正しい計算です。 間違っているのは『1か月』の日数が不定であることを考慮せずに1か月後を求めようとしていることです。

日数差(日の加減算)であれば、1日=86400秒で不変なので計算可能です。 また、400年の加減算も、グレゴリオ暦400年=14万6097日=126億2278万800秒なので計算可能です(*)。
しかし、年差や月差は可変なので計算不可能です。

利用者がこれを踏まえた上で、引数に適当な値を入れるのは問題ありません。 日付の計算を理解せずに変な値を入れると、変な数字にしかなりません。

なお、たとえば(現在設定されている時刻を維持したまま)今月末の日付を求めたいのであれば、last_day = obj.clone().setNextMonth().setYesterday().day() (同時刻のインスタンスを作り、来月1日の前日に設定して、その日付を返す)といった応用ができます。
同様に、来年の2月末日の日付であれば feb_last_day = obj.clone().setNextYear().setNextMonth().setNextMonth().setYesterday().day() (同時刻のインスタンスを作り、来年1月1日の翌々月の前日に設定して、その日付を返す) という操作で可能です。

このように、『先月の○日』や『来年の○月』といった概念は、特定時刻設定メソッドとの組み合わせで求めることができる場合があります。
内部では set に対して引数を適切に設定しているだけなので、特定時刻メソッドを使って表現可能な操作は、 これらのメソッドを使わず自分で引数を設定することでも全て実行可能です。

(*) ユリウス暦の場合は4年単位(うるう年周期)で加減算が可能ですが、 ユリウス暦で4年単位の加減算を行うと曜日のズレが生じます。 曜日周期も考慮した加減算を行う場合は4*7=28年周期となります。


UNIX時間と環境依存の秒数

このクラスでは、UNIX時間(unix)と環境依存の秒数(time)を区別していますが、 わたしの知る限り、JavaScriptで 1970-01-01 00:00:00 以外の時刻を基準にしている環境は存在しないので、 現在は、この2つは実質的に同じモノの別名に過ぎません。
ECMAScript で明確に仕様化されたので、今後、基準時刻が違う環境が実装されることもおそらくないでしょう。

これは、このクラスが元々Perlからの移植であり、 Perlでは過去のMacOSで基準時刻が違うモノがあったため、それに対応した名残りです。
このクラスでも内部の実装はしてあるので、 unix はどんな環境であっても 1970-01-01 を基準にした秒数を返しますし、 time はその環境の time 値を正しく受け取ることができます。

今後、このクラスでミリ秒を扱えるような仕様変更を行うことになった場合、 time が秒単位からミリ秒単位に変更されて、JavaScript の Date.getTime を直接受け取るようになる可能性があります。


内部の変換操作

内部の処理としては、入力された時間は全て独自の内部形式 "total" に変換して保持しておき、 呼び出された時にはその都度 "total" からそれぞれの形式に変換しています。
"total" は、[400年を1とする単位, 日単位, 秒単位] の3要素を持つ配列で、精度保証限界は±360京年です。 total がミリ秒を保持するように設計していないために、このクラスではミリ秒を扱うことはできません(*)。

説明する意味があまりない(上に説明するのも面倒な)ので省略していますが、 実は set / get ともに、時間名として "total" を受け付けることができますし、 メソッドとして total も存在しています。
扱い方を理解していれば、time.total().join(",") で360京年の精度を維持したまま時間を文字列化しておいて、 time.total(str.split(",")) で戻すという操作などに使えます。

(*) なお、ミリ秒を扱えるように修正することは可能なのですが、その場合 format 用の指定子を %m にできないので、 イマイチ綺麗な作りにできず、修正する気が起きません :-)
ちなみに、仮にミリ秒を扱えるようにした場合、ce / gc / jc で入出力する配列の要素数が7になったり、 time が Date.getTime に合わせてミリ秒になったりと、大幅な仕様の変更も発生することになります。


クラス継承

一切考えていません。clone メソッドが存在し、new を隠している以上、内部の実装に依存しない限りは継承による拡張は不可能なはずです。

インスタンスにメソッドを直接突っ込めば、それで大抵は何とかなるでしょうし、 それでは無理だというのであれば、継承ではなく包含でクラス設計してください。


非推奨の機能

再三書いたように、time メソッドは非推奨です。
現状では後方互換のために存在していますが、いずれ仕様変更される可能性があります。

あえて外しましたが、format の %Y も、オプションとして esj を受け付けています。 また、%Y に限り、k オプションも存在しています。
これらを指定すると、先頭に認識文字がついて、1未満の年数は紀元前表記になります。 たとえば %eY なら "A.D.(年)" / "B.C.(年)" に置換され、 %jY なら "西暦 (年)" / "紀元前 (年)" に置換されます。
month や wday と違い、文字列化の法則が特殊なので扱いに注意が必要です。基本的には非推奨と考えてください。

現在の設定を文字列化する serialize() と、その文字列を元に時刻を設定する unserialize() というメソッドもあります。
仕様が全然固まっていませんし、そもそもスクリプト内で使い捨てる以外の利用は想定していません。


ソース

初見で分かる人はいないだろーってぐらいの我流の極みです。

これを読んでみようなんて思う酔狂な人がいるとは思いませんが、 万一、間違ってそんな気を起こした方がいるのなら、先にFOT.Colorを見てみることをオススメします。
あちらが後発で、このFOT.Timeの基本構造をそのまま流用して組み上げたものです。 あちらの方がやってることが少ないので構造が分かりやすいかと。 あちらの構造を把握してからであれば、こちらの把握も幾分容易になる、かもしれません。


何で作ったの?

元々は PerlCGI の掲示板プログラムをいじっていた時の副産物です。

  1. Perl に gmtime と localtime があるけど、localtime は環境依存。実行環境の時差を毎回チェックするぐらいなら、 標準の localtime は使わないで、gmtime に時差を加えた値を渡して時刻を返す localtime 関数を実装しても手間は変わらないし確実だなぁ
  2. 時間操作するのに timegm と timelocal もあると便利そうだから追加してみよう
  3. gmtime も標準関数使うのやめて自分で実装してしまえば、時間範囲の制約がなくなるな
  4. Perl の time は環境依存だから、timeunix と unixtime も追加しよう
  5. ログに保存する時は unix の方が確実だから、unix をベースに時間操作することにして、gmunix と unixgm と localunix と unixlocal も追加しよう
  6. 組み合わせ上、gmlocal と localgm がないけど、ここに追加するのは複雑になり過ぎるから、 全て total との相互変換で実装すれば、(gm, local, unix, time) → total → (gm, local, unix, time) で全ての変換ができる。 これをクラス化すれば、外部からは (gm, local, unix, time) → (gm, local, unix, time) の直接変換のように使う事ができるな
  7. format を実装してパターン文字列を直接作れるようにしよう
  8. jc を追加するには gm と local を統合して gc にすればいいな
  9. ついでに jd と mjd と ffxi も追加しておこう
  10. このライブラリの動作テスト用に作った PerlCGI のメンテが面倒だから Ajax にしよう
  11. インターフェースが JavaScript で演算が Perl なのは面倒だから、いっそ全て JavaScript に移植しよう
  12. JavaScript ならサーバ側の動作コスト考えなくていいから万年カレンダーとか作ろう
  13. カレンダーは毎月1日の曜日取得があるけど、format じゃ手間だから date と wday を実装しよう
  14. カレンダー用に ce があると便利だから追加しよう
  15. カレンダー作ってる時に必要になった「今年の1月1日」とかの機能も追加しよう
  16. 操作に便利な clone とか cmp も追加しよう
  17. メソッドが増えて自分でも使い方分からなくなってきたからマニュアルを作ろう
  18. マニュアルをちょっといじるか←いまここ

要するに、自分が欲しくなったモノを作っただけです。