Platform: All
Viersion: 7.0.1 and above
1. エクストラを使う
日付から曜日を直接調べるコマンドは、Lingoには用意されていません。Macromedia Director TechNote「日付の取得と計算」には、DateTimeXtraを使用する方法が紹介されています。
2. date()オブジェクトを利用する
date()オブジェクトを使うと、ふたつの日付の間の日数を計算することができます。すると、その一方の日付の曜日がわかれば、他方も簡単に特定できます。つまり、差の日数が7で割切れれば同じ曜日、そうでなければ余りの分だけ曜日をずらせばよいのです。その計算は、比較的簡単なスクリプトです。
今回はDateTimeXtraやFlash ActionScriptのDate.getDay()メソッドと同じく、日曜日から土曜日までを0から6までの整数で返す関数をご紹介します。日曜日を0にするには、過去の日曜日の日付をひとつ決めて[*1]、指定された日付との日数の差を7で割り、その余り(剰余)を返せばよいことになります(スクリプト001)。
スクリプト001■date()オブジェクトの利用により曜日を返す関数
on xGetWeekDay(nYear, nMonth, nDay)
return (date(nYear, nMonth, nDay) - date(1, 1, 7)) mod 7
end
|
[*1] スクリプト001で過去の日付として設定した西暦1年1月7日は、年数の連続が保たれる西暦1年以降で、グレグリオ歴に従った論理計算上の日曜日となるべき日です。しかし後述「5. どこまで過去に遡れるか」で解説するとおり、この時代にはまだユリウス暦が採用されているため、実際の1年1月7日の曜日は異なります。
なお、date()オブジェクトには、0年12月31日を設定することができません(MXおよびMX 2004で確認)。論理的に整合性のある結果とは考えにくいものの、実際西暦0年は存在しません(後述「5. どこまで過去に遡れるか」参照)。date()オブジェクトには、年数に1以上を指定すべきでしょう。
put date(0, 12, 31)
-- date( 1, 1, 1 )
put date(1, 1, 1) - date(0, 12, 31)
-- 0
|
3. FlashのDateクラスを使う
Director MX 2004からは、Flash ActionScriptのクラスインスタンスを生成して、そのメソッドを利用することができます。したがって、DirectorからもFlashのDate.getDay()メソッドが使えるのです。Dateクラスには他にも数多くのメソッドが実装されていますので、利用方法を知っておくと便利でしょう。
スクリプト002■FlashのDate.getDay()メソッドにより曜日を返す関数
on xGetWeekDay2(nYear, nMonth, nDay)
oDate = newObject("Date") -- [1]インスタンスの生成
oDate.setFullYear(nYear, nMonth-1, nDay) -- [2]日付の設定
return integer(oDate.getDay()) -- [3]Date.getDay()メソッドの値を返す
end
|
[1]Flashのクラスを利用するには、原則としてそのインスタンスを生成する必要があります。Dateクラスはインスタンスを作成するときに、オプションの引数を加えて日付を設定することができます。Dateクラスに指定する月数は、1月から12月を0から11の整数で示すことに注意が必要です。
oDate = newObject("Date", 2005, 0, 1) -- 2005年1月1日を設定
put oDate.toString() -- インスタンスの文字列表現を表示
-- "Sat Jan 1 00:00:00 GMT+0900 2005"
さらに、年数を2桁以下で指定すると、4桁の頭の1900が省略されたものとみなされます。
oDate = newObject("Date", 1, 0, 1) -- 1901年1月1日と認識
put oDate.toString()
-- "Tue Jan 1 00:00:00 GMT+0900 1901"
Dateクラスのインスタンスを生成するときに、日付の引数を指定しなければ、現在日付がデフォルトで設定されます。
[2]Dateインスタンスの生成後に、改めて日付を設定するのが、Date.setFullYear()メソッドです。年数は指定したとおりに認識されるので、2桁以下の年数も設定することができます。その他の引数の指定は、Dateインスタンスの作成時と同様です。
[3]Date.getDay()メソッドは、Dateインスタンスに指定された日付の曜日を、0(日曜日)から6(土曜日)までの整数で返します。ただし、FlashのActionScriptは、Directorに対して数値を浮動小数で返します。そのため、Lingoで整数として扱いたいときは、integer()関数で変換する必要があります。
4. 曜日を求める公式を利用する
西暦の年月日から曜日を求める公式があります。1887年に、ゼラー(Zeller)という人が考えたものだとされます。その公式によれば、100c+y年m月d日の曜日は、つぎのような計算で求められます。
[21c/4] + [5y/4] + [26(m + 1)/10] + d‐1 (mod 7)
ただし、[]はガウス記号と呼ばれるもので、数値の整数部分を表します(たとえば、[3.14] = 3です)[*2]。4桁の西暦年数のうち、上2桁をc、下2桁をyとします。また、月数mが1月または2月の場合には、西暦の年数を1減算し、それぞれ13月あるいは14月とする必要があります。(mod 7)は、Lingoのmod演算子と同じく、7で割った余り(剰余)を意味します。結果の整数値0から6が、日曜日から土曜日に相当します。
スクリプト003■公式の利用により曜日を返す関数
on xGetWeekDay3(nYear, nMonth, nDay) {
if (nMonth<3) then
nYear = nYear - 1
nMonth = nMonth + 12
end if
c = nYear/100
y = nYear mod 100
w = (21*c/4)+(5*y/4)+(26*(nMonth+1)/10)+nDay-1
return w mod 7
end
|
[*2] 値に正数を指定するかぎりでは、切捨てと同じ結果になります。スクリプト003で計算の対象となる変数値(x、y、m、d)およびそれらを割る分母の数値はすべて正の整数ですので、Lingoでは単純に割り算を行えばよいでしよう。
負の小数値を扱う場合には、integer()関数とは結果が異なることに注意しましょう。ガウス記号の演算を関数として定義するなら、たとえばつぎのようなスクリプトになります。
スクリプト004■ガウス記号の演算を行う関数
on xGauss(n)
if (n > 0) then
return integer(n-0.5)
else
return integer(n-0.5)+(integer(n) = n)
end if
end
|
なお、Flash ActionScriptのMath.floor()メソッドは、ガウス記号と同じ演算処理を行います。
put integer(-3.14)
-- -3
put xGauss(-3.14)
-- -4
put newObject("Math").floor(-3.14)
-- -4.0000
|
5. どこまで過去に遡れるか
上記の曜日を求める関数は、具体的に過去の何年何月何日まで、曜日を調べることができるでしょうか。まず、年数から考えます。西暦0年は存在しませんので、紀元前と数値としての連続性が失われます(西暦1年 - 1年 = 紀元前1年になってしまうので)。したがって、少なくとも西暦1年以降しか、サポートされそうにないことが推測されます。上記3つの関数を西暦1年1月1日から同3000年12月31日まで調べたかぎりでは、すべて同じ値を返しました。
そこで、ActionScriptが準拠する仕様であるECMA-262第3版でDateクラスを確認すると、15.9.1.3年数(Year Number)に「ECMAScriptは、日数の年数へのマップと一年内の月日の決定にグレゴリオ暦を用いる」とされています。グレゴリオ暦は、1582年10月15日から実施されたといいます。実際上記3関数は、1582年10月15日に対して正しく5(金曜日)を返します。しかし、それ以前については、ユリウス暦からグレゴリオ暦への切換え時に日付が非連続になったり、うるう年の例外的な扱いがあったりした[*3]ために、実際の曜日を論理的に計算することができないようです。
したがって、今回作成した関数を含め、一般的にコンピュータの日付計算は、1582年10月15日以降に対応しているものと考えられそうです。
_____
作成者: 野中文雄
作成日: 2005年1月8日