=encoding euc-jp =head1 名前 Date::Calc - グレゴリオ暦に基づいた日付計算 =head1 モットー 小さく、早く、単純なままに =head1 前書き このモジュールは、グレゴリオ暦(今日の西洋で一番良く使われています)に基づくあらゆる日付計算のため CのライブラリーとPerlのモジュール(これもCのライブラリーを内部的に使っていますが) によって構成されています。それにより、妥当な標準に従います。 すなわち、ISO/R 2015-1971及びDIN 1355に準拠し、適用できる部分ではISO 8601の拡張もあります。 (DIN 1355について調べるなら、 http://www.engelschall.com/u/sb/download/Date-Calc/DIN1355/ のドキュメントを読んでください(ドイツ語です)). このモジュールは、当然のことながら2000年以降も正しく動作します(2000年問題対応) なんと1年から、あなたのシステムで扱える最も大きな正の数(それは少なくとも32767年です)までの全ての数を扱うことが出来るのです。 しかしながら、内部のPOSIXの日付・時刻処理の関数の一部であるこのパッケージの出入力を行なう関数にとってそれは正しくありません。単に、以下の日付のみに対応します。 01-Jan-1970 00:00:00 GMT .. 19-Jan-2038 03:14:07 GMT [Unix etc.] 01-Jan-1904 00:00:00 LT .. 06-Feb-2040 06:28:15 LT [MacOS Classic] (LT = local time) このパッケージの事業であるグレゴリオ暦は紀元1年にさかのぼることを記しておきます。 -- もっともグレゴリオ暦は、 1582年にPope Gregory13世による法令に一致するように服従するほとんどのヨーロッパにあるカトリックの国々によって、 この年にに採用されたのですが。 主にプロテスタントであるいくつかの国々は、それまで使っていたユリウス暦を使い続け、20世紀の初頭にいたるまで変更しませんでした。 最終的には、あなたが自然と想像するであろう全ての機能をつけること予定していません。 むしろUNIXの精神と伝統に基づき、道具箱であるよう、それでいながらいつでもあなたが行きたいところに連れて行くべきものとして 提供する予定なのです。 共通の問題を解決するためには、このドキュメントの下にあるレシピの項を見てください。 もし、どうしても特定の問題を解く方法を発見できなければ、教えてください。 Eメールアドレスは、このドキュメントの最後のところにあります。 =head1 一覧 use Date::Calc qw( Days_in_Year Days_in_Month Weeks_in_Year leap_year check_date check_time check_business_date Day_of_Year Date_to_Days Day_of_Week Week_Number Week_of_Year Monday_of_Week Nth_Weekday_of_Month_Year Standard_to_Business Business_to_Standard Delta_Days Delta_DHMS Delta_YMD Delta_YMDHMS Normalize_DHMS Add_Delta_Days Add_Delta_DHMS Add_Delta_YM Add_Delta_YMD Add_Delta_YMDHMS System_Clock Today Now Today_and_Now This_Year Gmtime Localtime Mktime Timezone Date_to_Time Time_to_Date Easter_Sunday Decode_Month Decode_Day_of_Week Decode_Language Decode_Date_EU Decode_Date_US Fixed_Window Moving_Window Compress Uncompress check_compressed Compressed_to_Text Date_to_Text Date_to_Text_Long English_Ordinal Calendar Month_to_Text Day_of_Week_to_Text Day_of_Week_Abbreviation Language_to_Text Language Languages Decode_Date_EU2 Decode_Date_US2 Parse_Date ISO_LC ISO_UC ); use Date::Calc qw(:all); Days_in_Year $days = Days_in_Year($year,$month); Days_in_Month $days = Days_in_Month($year,$month); Weeks_in_Year $weeks = Weeks_in_Year($year); leap_year if (leap_year($year)) check_date if (check_date($year,$month,$day)) check_time if (check_time($hour,$min,$sec)) check_business_date if (check_business_date($year,$week,$dow)) Day_of_Year $doy = Day_of_Year($year,$month,$day); Date_to_Days $days = Date_to_Days($year,$month,$day); Day_of_Week $dow = Day_of_Week($year,$month,$day); Week_Number $week = Week_Number($year,$month,$day); # こうしないでください Week_of_Year ($week,$year) = Week_of_Year($year,$month,$day); # 推奨されています $week = Week_of_Year($year,$month,$day); # 危険です Monday_of_Week ($year,$month,$day) = Monday_of_Week($week,$year); Nth_Weekday_of_Month_Year if (($year,$month,$day) = Nth_Weekday_of_Month_Year($year,$month,$dow,$n)) Standard_to_Business ($year,$week,$dow) = Standard_to_Business($year,$month,$day); Business_to_Standard ($year,$month,$day) = Business_to_Standard($year,$week,$dow); Delta_Days $Dd = Delta_Days($year1,$month1,$day1, $year2,$month2,$day2); Delta_DHMS ($Dd,$Dh,$Dm,$Ds) = Delta_DHMS($year1,$month1,$day1, $hour1,$min1,$sec1, $year2,$month2,$day2, $hour2,$min2,$sec2); Delta_YMD ($Dy,$Dm,$Dd) = Delta_YMD($year1,$month1,$day1, $year2,$month2,$day2); Delta_YMDHMS ($D_y,$D_m,$D_d, $Dh,$Dm,$Ds) = Delta_YMDHMS($year1,$month1,$day1, $hour1,$min1,$sec1, $year2,$month2,$day2, $hour2,$min2,$sec2); Normalize_DHMS ($Dd,$Dh,$Dm,$Ds) = Normalize_DHMS($Dd,$Dh,$Dm,$Ds); Add_Delta_Days ($year,$month,$day) = Add_Delta_Days($year,$month,$day, $Dd); Add_Delta_DHMS ($year,$month,$day, $hour,$min,$sec) = Add_Delta_DHMS($year,$month,$day, $hour,$min,$sec, $Dd,$Dh,$Dm,$Ds); Add_Delta_YM ($year,$month,$day) = Add_Delta_YM($year,$month,$day, $Dy,$Dm); Add_Delta_YMD ($year,$month,$day) = Add_Delta_YMD($year,$month,$day, $Dy,$Dm,$Dd); Add_Delta_YMDHMS ($year,$month,$day, $hour,$min,$sec) = Add_Delta_YMDHMS($year,$month,$day, $hour,$min,$sec, $D_y,$D_m,$D_d, $Dh,$Dm,$Ds); System_Clock ($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) = System_Clock([$gmt]); Today ($year,$month,$day) = Today([$gmt]); Now ($hour,$min,$sec) = Now([$gmt]); Today_and_Now ($year,$month,$day, $hour,$min,$sec) = Today_and_Now([$gmt]); This_Year $year = This_Year([$gmt]); Gmtime ($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) = Gmtime([time]); Localtime ($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) = Localtime([time]); Mktime $time = Mktime($year,$month,$day, $hour,$min,$sec); Timezone ($D_y,$D_m,$D_d, $Dh,$Dm,$Ds, $dst) = Timezone([time]); Date_to_Time $time = Date_to_Time($year,$month,$day, $hour,$min,$sec); Time_to_Date ($year,$month,$day, $hour,$min,$sec) = Time_to_Date([time]); Easter_Sunday ($year,$month,$day) = Easter_Sunday($year); Decode_Month if ($month = Decode_Month($string)) Decode_Day_of_Week if ($dow = Decode_Day_of_Week($string)) Decode_Language if ($lang = Decode_Language($string)) Decode_Date_EU if (($year,$month,$day) = Decode_Date_EU($string)) Decode_Date_US if (($year,$month,$day) = Decode_Date_US($string)) Fixed_Window $year = Fixed_Window($yy); Moving_Window $year = Moving_Window($yy); Compress $date = Compress($year,$month,$day); Uncompress if (($century,$year,$month,$day) = Uncompress($date)) check_compressed if (check_compressed($date)) Compressed_to_Text $string = Compressed_to_Text($date); Date_to_Text $string = Date_to_Text($year,$month,$day); Date_to_Text_Long $string = Date_to_Text_Long($year,$month,$day); English_Ordinal $string = English_Ordinal($number); Calendar $string = Calendar($year,$month[,$orthodox]); Month_to_Text $string = Month_to_Text($month); Day_of_Week_to_Text $string = Day_of_Week_to_Text($dow); Day_of_Week_Abbreviation $string = Day_of_Week_Abbreviation($dow); Language_to_Text $string = Language_to_Text($lang); Language $lang = Language(); Language($lang); $oldlang = Language($newlang); Languages $max_lang = Languages(); Decode_Date_EU2 if (($year,$month,$day) = Decode_Date_EU2($string)) Decode_Date_US2 if (($year,$month,$day) = Decode_Date_US2($string)) Parse_Date if (($year,$month,$day) = Parse_Date($string)) ISO_LC $lower = ISO_LC($string); ISO_UC $upper = ISO_UC($string); Version $string = Date::Calc::Version(); =head1 重要な注釈 (共通の問題を解決するためには、このドキュメントの下にあるレシピの項を見てください。) =over 2 =item <2000年問題対応> このモジュールにおける年の数の上限は、最も大きな正の整数の大きさによって決められています。 その数はあなたのシステム上におけるC言語におけるint型の変数によって表現されます。 そして、ANSI C standardによれば少なくとも32767です(例外は下を見てください) 単純な計算をするために、このモジュールは紀元1年までさかのぼります。この暦がカトリックのPope Gregory13世によって最初に決められた1582年より前です。 そのため、B<例えば1998年と言いたい時には、いつでも1998年と表記してください。決して代りに98年と書いてはいけません。> 何でかと言えば、そうすると実際は1998年ではなくて紀元98年を元に計算してしまいます。 自身の名前に"compress"という単語を含んでいる関数(これらの関数は、1970年から2069年まででのみ動作し、"00"から"99"までの省略を受け付けます) そして、"Decode_Date_"で始まる名前の関数(これらは"moving window"として知られている方法を使って、100より小さな数を変換します) はこの規則の例外です。 (訳者注:moving windowについては、下のほうで解説してあります。Moving_Windowという関数がありますので、そこを見てください) (訳者注:Compressという単語を含む関数は、使用が薦められていません。詳しくはこの関数のところを見てください) 2桁の数字を、少なくとも最近の年くらいはきちんとした4桁の年の数に変換したいならば、 "Fixed_Window()" と "Moving_Window()"の二つの関数を使ってください。(使い方はずっと下のほうにあります) 以下のimportしたりexportする関数は、とても限られた範囲に代表される日時しか扱えないと記しておきます。 それらはPOSIX関数である"time()"、"gmtime()"、"localtime()"、"mktime()"のインターフェイスもしくは、 "localtime()"と"mktime()"の代りであるBSD関数の"timegm()"そしてPOSIX関数の"gmtime()"のインターフェースです。 それとは対照的に、このパッケージ内の他の全ての関数では、仮想的に紀元1年1月1日から全ての日を網羅しています。 System_Clock() Today() Now() Today_and_Now() This_Year() Gmtime() Localtime() Mktime() Timezone() Date_to_Time() Time_to_Date() これらの関数は、01-Jan-1970 00:00:00 GMTから19-Jan-2038 03:14:07 GMTまでの範囲しか扱えません。 (しかしながら19-Jan-2038 03:14:07 GMTというのは、権威のある32ビットシステムでだけで、 原理的にはちょっとだけコードを修正すれば64ビットシステムでも使えるはずです) MacOS Classicでは、扱える日の範囲は、両端を含んでlocaltimeで01-Jan-1904 00:00:00 から 06-Feb-2040 06:28:15となっています。 さらに、"Easter_Sunday()"関数は、1583年から2299年の範囲の年だけを扱うことが出来ると記しておきます。 =item 最初の目次 このモジュールにおいては、B<全ての>範囲は1から始まります。B<0ではありません> 例えば、ある月の日付、週の中の日、年の中の日付、年の中の月、年の中の週、 最初の意味のある年の数、そして言語はB<全て>1から数え始めます。B<0ではありません。> 唯一の例外は、"Week_Number()"関数(この関数は、与えられた日が実は前年の最後の週にある場合に0を返します)、 そしてもちろん、時間は(0..23)、分は(0..59)、秒は(0..59)です。 =item 関数命名のきまり 以下の場合は完全に、関数の名前がどんな値を返すかを暗示しています。 =item 真偽値 このモジュールにおける真偽値は、常に偽を表すのには数値の0、真を表すのには数値の1です。 =item 例外処理 このモジュールの関数は、常に入力されたパラメーター・中間の値・出力の値が範囲外である場合は、 対応するエラーメッセージと共に終了します。 以下の関数は、異なる形でエラーを用います。 - check_date() - check_time() - check_business_date() - check_compressed() (これらは、入力されたものが意味のある日や時刻でなければ偽の値を返します) - Nth_Weekday_of_Month_Year() (この関数は、求められた第5週の日が存在しなければ、空のリストを返します) - Decode_Month() - Decode_Day_of_Week() - Decode_Language() - Fixed_Window() - Moving_Window() - Compress() (これらは、失敗したり無意味な入力に対しては偽を返します) - Decode_Date_EU() - Decode_Date_US() - Decode_Date_EU2() - Decode_Date_US2() - Parse_Date() - Uncompress() (これらは、失敗したり無意味な入力に対しては、空のリストを返します) あなたはいつでもこのモジュール内のどの関数の例外も取得できますし、 evalで囲われた関数呼び出しを、渦巻状の括弧と特殊変数"$@"の値をチェックしながら使うことで、 その例外をあなた自身が扱うことができます。 詳しくは、perlfunc(1)の"eval"の項を読んでください。 =back =head1 解説 =over 2 =item use Date::Calc qw( Days_in_Year Days_in_Month ... ); =item use Date::Calc qw(:all); 関数を明確にインポートをしたければ、"qw()"の括弧の中に列挙することもできますし、 ":all"を使うことで、全ての関数をインポートすることも可能です。 =item $days = Days_in_Year($year,$month); この関数は、"$year"で与えられた年の、1月から始まり"$month"を含む月までにある日数の和を返します。 例:"Days_in_Year(1998,1)"と書けば"31"が返り、"Days_in_Year(1998,2)"ならば"59"、 "Days_in_Year(1998,3)"なら"90"といった具合です。 ちなみに"Days_in_Year($year,12)"は、"$year"で与えられた年の日数を返します。すなわち、"365"もしくは"366"です。 =item $days = Days_in_Month($year,$month); この関数は、"$year"で与えられた年の、"$month"で与えられた月の日数を返します。 うるう年かどうかを判定することが2月にしか影響がないとはいえ、"$year"は必ずなくてはいけません。 例:"Days_in_Month(1998,1)"だと"31"が返り、"Days_in_Month(1998,2)"だと"28"、"Days_in_Month(2000,2)"ならば"29"、"Days_in_Month(1998,3)"ならば"31"、他も同じです。 =item $weeks = Weeks_in_Year($year); この関数は、"$year"で与えられた年の週の数を返します。つまり、"52"か"53"です。 =item if (leap_year($year)) この関数は、"$year"で与えられた年がうるう年なら"true"、すなわち"1"を返し、そうでなければ"false"、すなわち"0"を返します。 =item if (check_date($year,$month,$day)) この関数は、"$year"、"$month"、"$day"の3つの数値が、日付として意味を持てば"true" ("1")を返し、そうでなければ"false" ("0")を返します。 =item if (check_time($hour,$min,$sec)) この関数は、"$hour"、"$min"、"$sec"の3つの数値が意味のある時刻、すなわち(0 <= $hour < 24, 0 <= $min < 60 and 0 <= $sec < 60)を満たせば "true" ("1")を返し、そうでなければ"false" ("0") を返します。 =item if (check_business_date($year,$week,$dow)) この関数は、"$year"、"$week"、"$dow"、の3つの数値がビジネスフォーマット上で存在する日を構成していれば"true" ("1")、そうでなければ "false" ("0")を返します。 (訳者注:$dowはDayOfYearの略語です。また、ビジネスフォーマットの良い訳があれば教えてください) 注意して欲しいのは、この関数は与えられた日が仕事のある日(つまり月曜から金曜)かどうかはB<計算しません>。 そんな時には代りに"(Day_of_Week($year,$month,$day) < 6)"としてください。 =item $doy = Day_of_Year($year,$month,$day); この関数は、与えられた年の中における、与えられた日の(相対的な)順番を返します。 例えば、 "Day_of_Year($year,1,1)"なら"1"だし、"Day_of_Year($year,2,1)"なら"32"、 "Day_of_Year($year,12,31)" ならば"365"か"366"です。 =item $days = Date_to_Days($year,$month,$day); この関数は、紀元1年1月1日から数え始めた時の、与えられた日の(絶対的な)順番を返します すなわち、"Date_to_Days(1,1,1)"ならば"1"、"Date_to_Days(1,12,31)"ならば"365"、"Date_to_Days(2,1,1)"ならば"366"、"Date_to_Days(1998,5,1)"ならば"729510"といった具合です。 この値は、時に(正しいとはいえないのですが)ユリウス日と呼ばれることもあります。 その年の月の数(1から365もしくは366)がしばしばユリウス日のことを指すので、混乱を引き起こすかもしれません。 実際問題として、グレゴリオ暦の前に使われていたのはユリウス暦(この名称はローマ時代に研究したかの有名なユリウス・シーザーの名前から取られた)です。 ユリウス暦は、年の正確な長さに合わせるためにあまりに多くのうるう年があり、 例えば自身の統治の延長等のため、勝手気ままにルールが変わるのであまり正確ではないのです。 この関数によって返された値から、日付を取るには、 このように"Add_Delta_days"関数を使います。(ずっと下で解説してあります) $days = Date_to_Days($year,$month,$day); ($year,$month,$day) = Add_Delta_Days(1,1,1, $days - 1); =item $dow = Day_of_Week($year,$month,$day); この関数は、与えられた日の週の中での順番を返します。 月曜なら"1"、火曜なら"2"、そして日曜日の"7"までを返します。 キリスト教の暦の元となっているヘブライ暦において、週は日曜日から始まって安息日または土曜日で終わります。 (この日は、聖書に記述されている創世記において、主が世界をおつくりになって休まれた日です) 中世に、カトリックのPopesがキリスト教徒をヘブライ信仰から引き離すために日曜日を公用の休日として制定しました。 今日、日曜と土曜はいつも"週末(week-end)"と呼ばれて、休日として共通に考えられています。 経験と矛盾しないように、現在の標準(ISO/R 2015-1971やDIN 1355、それからISO 8601のような)は月曜日を週の初めとして定義しました。 =item $week = Week_Number($year,$month,$day); この関数は、与えられた日が、第何週目にあるかを返します。 与えられた日が前年の最後の週にある場合は、"0"が返されます。 与えられた日が翌年の最初の週にある場合は、"Weeks_in_Year($year) + 1"の値が返されます。 =item ($week,$year) = Week_of_Year($year,$month,$day); この関数は、与えられた日がどの週に存在するかということと、その週が存在する年を返します。 例えば、与えられた日がB<前年の最後の週>に存在していれば、"(Weeks_in_Year($year-1), $year-1)"の値が返されます。 もし、与えられた日がB<翌年の最初の週>に存在していれば、"(1, $year+1)"が返されます。 そうでなければ、"(Week_Number($year,$month,$day), $year)"が返されます。 =item $week = Week_of_Year($year,$month,$day); スカラーコンテキストにおいては、この関数は週の数を返すだけです。 この機能で、"($week) = Week_of_Year($year,$month,$day);" と書く代わりに"$week = Week_of_Year($year,$month,$day);"と書けます。 ("$week"の周りにある丸括弧を注目すること) 与えられた日がB<前年の最後の週>に存在していれば、"Weeks_in_Year($year-1)"の値が返されます。 もし、与えられた日がB<翌年の最初の週>に存在していれば、"1"が返されます。 そうでなければ、"Week_Number($year,$month,$day)"が返されます。 この関数を、スカラーコンテキストとして扱うのは、B<危険な>特徴です。というのもその週がどの年にあるかを知らなければ、うかつな間違った思い込みをするかもしれません。 例えばもし離れた日付を扱い続けると、与えられた日がある週がいつも同じ年にあると思い込むことがありえます。同じ状況でも運が悪ければB<間違って>いるのに、です。 多くの年においては、例えば12月31日はB<翌年の>週番号に所属しています。 あなたの考えている日(この例では12月31日ですが)とその年が同じだと思い込むと、 あなたはB<その年>の最初の週に送られてしまいます。運が悪ければその週の月曜日とか、そのB<前の>年に存在するところにまで! こんなことは、たとえば実際に2002年に起こります。 ですから、対応する年をとにかく必要とするようにしておいて、記録するようにしてください。 あなたがこのことを理解したのであれば、覚えていなくてもかまいません。 でも、単純にこの関数をスカラーコンテキストではB<使わないで>ください。 =item ($year,$month,$day) = Monday_of_Week($week,$year); この関数は、与えられた週の最初の日、要は月曜日の日付を返します。 "$year"は"1"よりも大きくなくてはいけないし、"$week"は"1"から"Weeks_in_Year($year)"まででなければいけません。 与えられた日のある週の月曜日の日付を計算するために、"($year,$month,$day) = Monday_of_Week(Week_of_Year($year,$month,$day));"と書くこともできます。 もし、あなたが与えた日と同じ週の、別の曜日の日付を知りたければ、以下のように書いてください。 @date = Add_Delta_Days(Monday_of_Week(Week_of_Year(@date)),$offset); $offset = 1ならば火曜日ですし、2ならば水曜日・・・・等です。 =item if (($year,$month,$day) = Nth_Weekday_of_Month_Year($year,$month,$dow,$n)) この関数は、"$year"で与えられた年の"$month"で与えられた月の中で、"$n"番目の週番号が"$dow"である日付を計算します。 例えば、ある年・ある月の3番目の火曜日といったような日付です。 これは例えば、毎月第三火曜日に普通会うようなグループのメンバーの通知メールを送る時などに使えます。 (本当にそうする場合のコードの断片は、この文書の終わり近くにあるレシピの項をみてください) "$year"は"1"以上、"$month"は"1"から"12"、"$dow"は"1"から"7"、そして"$n"は"1"から"5"にしてください。 でなければ、適切なエラーメッセージとともに致命的なエラーが発生します。 該当する年と月の中に5番目の与えられた週番号の日がない場合には、空のリストを返します。 =item ($year,$week,$dow) = Standard_to_Business($year,$month,$day); この関数は、一般的な記述方法(年と月と日)からビジネス書式(年と週と週番号)に変換します。 =item ($year,$month,$day) = Business_to_Standard($year,$week,$dow); この関数は、ビジネス書式(年と週と週番号)から一般的な記述方法(年と月と日)に変換します。 =item $Dd = Delta_Days($year1,$month1,$day1, $year2,$month2,$day2); この関数は、二つの与えられた日の間隔を返します。 2つの日付が時系列順であれば(つまり、#1の日付が#2の日付よりも前にあれば)正の値を返しますし、逆であれば負の値を返します。 同一である場合の結果はゼロです。 =item ($Dd,$Dh,$Dm,$Ds) = Delta_DHMS($year1,$month1,$day1, $hour1,$min1,$sec1, $year2,$month2,$day2, $hour2,$min2,$sec2); この関数は、二つの与えられた日と時刻から、その間隔を返します。 2つの日付が時系列順になっている、すなわち#1の日付が#2の日付がのB<前に>あれば4つの値は全て正になります。 そして、二つの日付が逆になっていれば、(4つの値が全て)負の値となります。 これは、"C"と"C"の2つの関数(ずっと下で解説してあります)が互いに反対であり、補い合っているからです。 Add_Delta_DHMS(@date1,@time1, Delta_DHMS(@date1,@time1, @date2,@time2)) とすれば"C<(@date2,@time2)>"を再び得ることになりますし、 Add_Delta_DHMS(@date2,@time2, map(-$_, Delta_DHMS(@date1,@time1, @date2,@time2))) ならば"C<(@date1,@time1)>"ですし、 Delta_DHMS(@date1,@time1, Add_Delta_DHMS(@date1,@time1, @delta)) ならば"C<@delta>"です。 二つの日と時刻が完全に同じならば、ゼロを返します。 =item ($Dy,$Dm,$Dd) = Delta_YMD($year1,$month1,$day1, $year2,$month2,$day2); この関数は、次のベクトルを返します ( $year2 - $year1, $month2 - $month1, $day2 - $day1 ) 二つの日付のどちらかが意味を持たなければ、エラーになります。 =item ($D_y,$D_m,$D_d, $Dh,$Dm,$Ds) = Delta_YMDHMS($year1,$month1,$day1, $hour1,$min1,$sec1, $year2,$month2,$day2, $hour2,$min2,$sec2); この関数は、上の"Delta_YMD()"を基にしていますが、追加の時刻計算を別に行います。 時刻の繰越が発生すれば、"C<$D_d>"の値がそれに応じて調整され、正しい日と時刻の間隔が得られます。 引数は、正の答えを出すには時系列順であることが望まれます。 どんな場合であっても、最初の日と時刻、すなわち(C<$year1,$month1,$day1,> C<$hour1,$min1,$sec1>)に関数の答えを足すと、 2つ目の日と時刻(C<$year2,$month2,$day2,> C<$hour2,$min2,$sec2>)を再び得ることができます。 そしてまた、関数の答えの全ての符号を逆にした負の値を2つ目の日と時刻に足すと、最初の日と時刻が得られます。 日と時刻の値の足し算や、日と時刻の間隔については、ずっと下のほうにある、"Add_Delta_YMDHMS()" 関数を見てください。 二つの日と時刻のどちらかでも無意味な値が入っていれば、エラーが発生します。 =item ($Dd,$Dh,$Dm,$Ds) = Normalize_DHMS($Dd,$Dh,$Dm,$Ds); この関数は、4つの任意の値、すなわち日と時間と分と秒を取り(符号が違ってもかまいません)、 時間・分・秒がC<[-23..23]>・C<[-59..59]>・C<[-59..59]>の範囲にあるように正常化させます。 そしてまた、4つの値の符号が全て同じ(もしくはゼロ)になるようにします。 与えられた値に触れることはありません。すなわち、変化はさせません。 =item ($year,$month,$day) = Add_Delta_Days($year,$month,$day, $Dd); この関数には2つの原理的な使い方がある。 まず、この関数で最初の日と日数のオフセット(これは正かもしれないし負かもしれない) から新しい日付を計算することができます。 例えば、「今日から90日後の日付はなんだろう?」のような質問に答えられます。 (週のオフセットを加えたければ、単にその週のオフセットに"C<7>"をかけて、日のオフセットに加えてください) もう一つは、日付の正規の日付の表現を変更することができます。 すなわち、ある日における数(S<紀元1年>の1月1日から数え始めた)から、与えられた年・月・日まで戻る表現です。 Second, it can be used to convert the canonical representation of a date, i.e., the number of that day (where counting starts at the 1st of January in S<1 A.D.>), back into a date given as year, month and day. というのは、"C<1>"から数え始めたとすれば、あなたは元の日付に戻るために正規の日数を引き算する必要があります。 すなわち $canonical = Date_to_Days($year,$month,$day); ($year,$month,$day) = Add_Delta_Days(1,1,1, $canonical - 1); さらに言えば、この関数は"C"の逆関数です。すなわち Add_Delta_Days(@date1, Delta_Days(@date1, @date2)) とすれば"C<@date2>"を再び得ることができるし、 Add_Delta_Days(@date2, -Delta_Days(@date1, @date2)) ならば"C<@date1>"だし、 Delta_Days(@date1, Add_Delta_Days(@date1, $delta)) ならば"C<$delta>"です。 =item ($year,$month,$day, $hour,$min,$sec) = Add_Delta_DHMS($year,$month,$day, $hour,$min,$sec, $Dd,$Dh,$Dm,$Ds); この関数は、オフセットの日・時間・分・秒を与えられた日と時刻に加えます。 "今日のこの時刻から7日後の5時間前の30分後の日と時刻を教えてほしい"というような日と時刻です。 ($y,$m,$d,$H,$M,$S) = Add_Delta_DHMS(Today_and_Now(), +7,-5,+30,0); =item ($year,$month,$day) = Add_Delta_YM($year,$month,$day, $Dy,$Dm); この関数は、与えられた日に年と月の両方もしくは片方のオフセットを加えるために使います。 すぐ下に説明されている関数の("C")とは対照的に、 この関数は、(オフセットの値を足した後の)答えの年と月の中の、意味のある範囲内にその日があるかどうかをラッピングしません。 その代わりに、単に答えの月のなかの一番最後の日に切り捨てます。 例: (1999,1,31)の0年と1月後は、(無意味な値である)(1999,2,31)です。この関数は、この値を(意味のある)(1999,2,28)に置き換えます。 同じく(1999,1,31)に1年と1ヶ月をオフセットとして加えると、(やっぱり無意味な)(2000,2,31)という結果になります。 この関数は、意味のある値である(2000,2,29)に置き換えます。(2000年はうるう年ですから) オフセットの年と月は、負の値でもかまいませんし、年と月に異なる符号を用いることもできます。(訳者注:1年後の1ヶ月後等も認められるということです) 仮に、追加で日のオフセットを用いたくて"C"を使用する前か後に"C"を呼んだ場合、 @date2 = Add_Delta_Days( Add_Delta_YM(@date1, $Dy,$Dm), $Dd ); @date2 = Add_Delta_YM( Add_Delta_Days(@date1, $Dd), $Dy,$Dm ); この2つの関数を使う順番によって答えが変わるかもしれません! (1999,2,28)の0年と1ヶ月、そして1日後を考えて見ましょう。 (1999,2,28)の1ヵ月後は(1999,3,28)で、これの翌日は(1999,3,29)です。(1999,2,28)の翌日は(1999,3,1)で、これの一ヵ月後は(1999,4,1)です。 (これが"C"関数がどうして日数のオフセットを持たないのかという理由でもあります。 なぜなら、日のオフセットを加える前に年や月を加えるのか、あるいは後に加えるのかという2つの関数がありうるからです) 最初の日が意味を持たない場合は、エラーが発生します。 "C"とすることで、いつももとの日付が得られるわけではありません。 (上の例を考えてみてください) (訳者注:7月31日の1ヶ月後の1ヶ月前は7月31日ですが、1ヶ月前の1ヶ月後は7月30日ですね?) =item ($year,$month,$day) = Add_Delta_YMD($year,$month,$day, $Dy,$Dm,$Dd); この関数は、与えられた日に、年と月と日のオフセットを加えます。 (週のオフセットを加えるためには、単に週のオフセットに7をかけて、日のオフセットに加えてください) 年・月・日の3つのオフセットはお互い独立に与えることができますし、異なる符号でもかまいません。 まず年と月のオフセットが先に与えられ、日のオフセットは最後に処理されます。 仮に、例えば4月31日とか2月30日のような月の終わりより後の結果になってしまった場合、 余った分の日数は単純に翌月(翌年のこともあります)に繰り越されます。 (例えば4月の32日は5月の2日になります) B<注意>: この挙動は、前のバージョンのモジュールとは異なります。 前のバージョンでは、その月の最後の日に切り捨てられます。 もし、過去のバージョンの挙動を望むのであれば、 すぐ上に解説してある"C"と"C"の関数を代わりに使ってください。 B<注意>: また、固定された日に対して年や月のオフセットが同義で無い場合においても この関数で実行された変換が、B<いつも逆方向に使って同じ結果がでるわけではありません!> これは、完全に逆の関数が使える"C"と"C"とは異なります。 (例えば"C"と"C"の関数のヘルプを見てください) 同様の理由により、 @date = Add_Delta_YMD( Add_Delta_YMD(@date, $Dy,$Dm,$Dd), -$Dy,-$Dm,-$Dd); とすると、元の"C<@date>"が必ず返ってくるわけではありません。 これはプログラムのバグではB<ありません>し、そうあるべきなのです。 なぜなら、年や月の長さが変わりやすいからです。 =item ($year,$month,$day, $hour,$min,$sec) = Add_Delta_YMDHMS($year,$month,$day, $hour,$min,$sec, $D_y,$D_m,$D_d, $Dh,$Dm,$Ds); 年・月・日のオフセットに加えて、時刻のオフセットを与える点を除いて、上の関数と同じです。 =item ($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) = System_Clock([$gmt]); あなたのオペレーティングシステムが、("C"と"C"もしくは"C")に相当する システム呼び出しをサポートしていれば、この関数はあなたのシステムの時計から提供された情報を返します。 すなわち、現在の日と時刻、そして年の中における日の順番、週の番号、そして夏時間が有効かどうかのフラグの値です。 これらの値の意味と範囲は以下の通りです。 $year : 1970..2038 (もしくはそれ以上) [Unix etc.] $year : 1904..2040 [MacOS Classic] $month : 1..12 $day : 1..31 $hour : 0..23 $min : 0..59 $sec : 0..59 (0..61であるシステムもあります) $doy : 1..366 $dow : 1..7 $dst : -1..1 "C<$doy>"は、年の中における日の順番であり、時にユリウス日とも呼ばれます。 1から始まり、その年の日数まで大きくなります。 (訳者注:1月1日なら1ですし、12月31ならば365もしくは366となります) 週番号("C<$dow>")は、月曜ならば"C<1>"ですし、"C<2>"ならば火曜日で、"C<7>"の土曜までです。 夏時間のフラグ("C<$dst>")は、そんな情報があなたのシステム上に存在しなければ"C<-1>"ですし、 夏時間ではなければ(つまり冬時間です)であれば"C<0>"ですし、夏時間が有効なら"C<1>"です。 あなたのOSが必要なシステムコールを提供していない場合には"not available on this system"という致命的エラーメッセージを出します。 もし、この例外をあなた自身が使用するには、"C"を以下のように使います。 If you want to handle this exception yourself, use "C" as follows: eval { ($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) = System_Clock(); }; if ($@) { # Handle missing system clock # (For instance, ask user to enter this information manually) } ここでは渦巻き括弧("{"と"}")が"eval"(Perlで例外を取得する方法です)で扱われる範囲を定めていて、 引用されていません(これは、実行中においてPerlの表現を評価する方法です)。 オプションの(真偽値としての)"C<$gmt>"が与えられた場合、 その値が真、すなわち("C<1>")ならば"C"の代わりに"C" が内部的に使われることになり、ローカルな時刻の変わりにグリニッジ時刻(GMTもしくはUTC)が返されます。 =item ($year,$month,$day) = Today([$gmt]); この関数は、上の"C"関数によって返される値のサブセットを返します。 すなわち、現在の年・月・日を返します。 相当するシステム上の関数がオペレーティングシステム上に存在していなければ、"not available on this system" の致命的エラーメッセージが発生します。 もし、オプションの真偽値の"C<$gmt>"が与えられれた場合の動作は、 真、すなわち("C<1>")ならば"C"の代わりに"C" が内部的に使われることになり、ローカルな時刻の変わりにグリニッジ時刻(GMTもしくはUTC)が返されます。 =item ($hour,$min,$sec) = Now([$gmt]); この関数は、上の"C"関数によって返される値のサブセットを返します。 すなわち、現在の時刻(時間・分・秒)を返します。 相当するシステム上の関数がオペレーティングシステム上に存在していなければ、"not available on this system" の致命的エラーメッセージが発生します。 もし、オプションの真偽値の"C<$gmt>"が与えられれた場合の動作は、 真、すなわち("C<1>")ならば"C"の代わりに"C" が内部的に使われることになり、ローカルな時刻の変わりにグリニッジ時刻(GMTもしくはUTC)が返されます。 =item ($year,$month,$day, $hour,$min,$sec) = Today_and_Now([$gmt]); この関数は、上の"C"関数によって返される値のサブセットを返します。 すなわち、現在の日付(年・月・日)と時刻(時間・分・秒)を返します。 相当するシステム上の関数がオペレーティングシステム上に存在していなければ、"not available on this system" の致命的エラーメッセージが発生します。 もし、オプションの真偽値の"C<$gmt>"が与えられれた場合の動作は、 真、すなわち("C<1>")ならば"C"の代わりに"C" が内部的に使われることになり、ローカルな時刻の変わりにグリニッジ時刻(GMTもしくはUTC)が返されます。 =item $year = This_Year([$gmt]); この関数は、ローカルな時刻に応じて現在の時刻を返します。 This function returns the current year, according to local time. 相当するシステム上の関数がオペレーティングシステム上に存在していなければ、"not available on this system" の致命的エラーメッセージが発生します。 もし、オプションの真偽値の"C<$gmt>"が与えられれた場合の動作は、 真、すなわち("C<1>")ならば"C"の代わりに"C" が内部的に使われることになり、ローカルな時刻の変わりにグリニッジ時刻(GMTもしくはUTC)が返されます。 しかしながら、これは年の変わる数時間の間だけ違いを生じさせるだけです。(24時間近くも異なる可能性がある太平洋の島国にいる場合以外) =item ($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) = Gmtime([time]); これは、Perl組み込みの"gmtime()"関数と同等です。Lも見てください。 返される値とその意味は以下の通りです。 $year : 1970..2038 (それ以上の場合もあります) [Unix etc.] $year : 1904..2040 [MacOS Classic] $month : 1..12 $day : 1..31 $hour : 0..23 $min : 0..59 $sec : 0..59 $doy : 1..366 $dow : 1..7 $dst : -1..1 "C<$doy>"は、年の中の日の順番で、ユリウス日と呼ばれることもあります。 "C<1>"から始まって、その年の日数まで増えます。 週番号の("C<$dow>")は、"C<1>"ならば月曜、"C<2>"ならば火曜で、"C<7>"の土曜日まであります。 夏時間のフラグ("C<$dst>")は、そんな情報があなたのシステム上に存在しなければ"C<-1>"ですし、 夏時間ではなければ(つまり冬時間です)であれば"C<0>"ですし、夏時間が有効なら"C<1>"です。 時間の値が範囲外、すなわちC<[0..(~0EE1)]>の場合には、"time out of range"の致命的エラーが発生します。 時間の値を省略すると、"time()"の値を内部的に代わりに呼び出します。 =item ($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) = Localtime([time]); これはPerlの組み込みの"localtime()"関数と同等です。Lも見てください。 範囲と意味は以下の通りです。 $year : 1970..2038 (それ以上の場合もあります) [Unix etc.] $year : 1904..2040 [MacOS Classic] $month : 1..12 $day : 1..31 $hour : 0..23 $min : 0..59 $sec : 0..59 $doy : 1..366 $dow : 1..7 $dst : -1..1 "C<$doy>"は、年の中の日の順番で、ユリウス日と呼ばれることもあります。 "C<1>"から始まって、その年の日数まで増えます。 週番号の("C<$dow>")は、"C<1>"ならば月曜、"C<2>"ならば火曜で、"C<7>"の土曜日まであります。 夏時間のフラグ("C<$dst>")は、そんな情報があなたのシステム上に存在しなければ"C<-1>"ですし、 夏時間ではなければ(つまり冬時間です)であれば"C<0>"ですし、夏時間が有効なら"C<1>"です。 時間の値が範囲外、すなわちC<[0..(~0EE1)]>の場合には、"time out of range"の致命的エラーが発生します。 時間の値を省略すると、"time()"の値を内部的に代わりに呼び出します。 =item $time = Mktime($year,$month,$day, $hour,$min,$sec); この関数は、日付を時間の値に変換します。つまり、あなたのシステムが想定している"新時代"からの秒数に変換します。 Unixや、ほとんどのシステム上では、1970年の1月1日の深夜(GMT)からの秒数です。 MacOS Classicにおいては、1904年1月1日の深夜(ローカル時間)からの秒数です。 この関数は、"POSIX::mktime()"関数と似ています。(詳細はLを見てください) しかしながら"POSIX::mktime"と異なる点としては、この関数の想定している日付の範囲です。 つまり、2001年ならば2001と表記しますし、月の数は1から12です。 致命的エラーの"date out of range"は、与えられた時刻が新時代からの秒数では表現出来ない場合に発生します。 (例えば新時代の前であったり、S<32 ビット>のUnixシステム上でS<19-Jan-2038 03:14:07 GMT>以降であったりとか MacOS ClassicのMacintosh上におけるS<06-Feb-2040 06:28:15> (local time)以降等の場合です) "POSIX::mktime()"と同様に、この関数は内部的に"mktime()"のシステムコールを行います。 このことは、与えられた日付と時刻をローカルタイムとして扱うということであって、 この関数から返される値はあなたのマシンが設定されているタイムゾーンとか サマータイムを使っているか(またはそのとき使っていたか)、そしてシステム上の時計それ自身に依存します。 B<注意>として"mktime()"は、 いくつかのシステム上において、"localtime()"の出力を"mktime()"に入れた場合に いつも同じ時刻の値を返すわけではありません。 つまり、同じ"C<$time>"の値を与えても"C"がいつも同じ値とは限りません。 =item ($D_y,$D_m,$D_d, $Dh,$Dm,$Ds, $dst) = Timezone([time]); この関数は、"C"と"C"の違い、 すなわち現在の場所と与えられた"C