Date-Calc-5.3 > Date::Calc

名前

Date::Calc - グレゴリオ暦に基づいた日付計算

モットー

小さく、早く、単純なままに

前書き

このモジュールは、グレゴリオ暦(今日の西洋で一番良く使われています)に基づくあらゆる日付計算のため 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メールアドレスは、このドキュメントの最後のところにあります。

一覧

  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();

共通の問題を解決するためには、このドキュメントの下にあるレシピの項を見てください。

<2000年問題対応>

このモジュールにおける年の数の上限は、最も大きな正の整数の大きさによって決められています。 その数はあなたのシステム上におけるC言語におけるint型の変数によって表現されます。 そして、ANSI C standardによれば少なくとも32767です(例外は下を見てください)

単純な計算をするために、このモジュールは紀元1年までさかのぼります。この暦がカトリックのPope Gregory13世によって最初に決められた1582年より前です。

そのため、例えば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年の範囲の年だけを扱うことが出来ると記しておきます。

最初の目次

このモジュールにおいては、全ての範囲は1から始まります。0ではありません

例えば、ある月の日付、週の中の日、年の中の日付、年の中の月、年の中の週、 最初の意味のある年の数、そして言語は全て1から数え始めます。0ではありません。

唯一の例外は、"Week_Number()"関数(この関数は、与えられた日が実は前年の最後の週にある場合に0を返します)、 そしてもちろん、時間は(0..23)、分は(0..59)、秒は(0..59)です。

関数命名のきまり

以下の場合は完全に、関数の名前がどんな値を返すかを暗示しています。

真偽値

このモジュールにおける真偽値は、常に偽を表すのには数値の0、真を表すのには数値の1です。

例外処理

このモジュールの関数は、常に入力されたパラメーター・中間の値・出力の値が範囲外である場合は、 対応するエラーメッセージと共に終了します。

以下の関数は、異なる形でエラーを用います。

  -  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"の項を読んでください。

解説

use Date::Calc qw( Days_in_Year Days_in_Month ... );
use Date::Calc qw(:all);

関数を明確にインポートをしたければ、"qw()"の括弧の中に列挙することもできますし、 ":all"を使うことで、全ての関数をインポートすることも可能です。

$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"です。

$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"、他も同じです。

$weeks = Weeks_in_Year($year);

この関数は、"$year"で与えられた年の週の数を返します。つまり、"52"か"53"です。

if (leap_year($year))

この関数は、"$year"で与えられた年がうるう年なら"true"、すなわち"1"を返し、そうでなければ"false"、すなわち"0"を返します。

if (check_date($year,$month,$day))

この関数は、"$year"、"$month"、"$day"の3つの数値が、日付として意味を持てば"true" ("1")を返し、そうでなければ"false" ("0")を返します。

if (check_time($hour,$min,$sec))

この関数は、"$hour"、"$min"、"$sec"の3つの数値が意味のある時刻、すなわち(0 <= $hour < 24, 0 <= $min < 60 and 0 <= $sec < 60)を満たせば "true" ("1")を返し、そうでなければ"false" ("0") を返します。

if (check_business_date($year,$week,$dow))

この関数は、"$year"、"$week"、"$dow"、の3つの数値がビジネスフォーマット上で存在する日を構成していれば"true" ("1")、そうでなければ "false" ("0")を返します。 (訳者注:$dowはDayOfYearの略語です。また、ビジネスフォーマットの良い訳があれば教えてください)

注意して欲しいのは、この関数は与えられた日が仕事のある日(つまり月曜から金曜)かどうかは計算しません。 そんな時には代りに"(Day_of_Week($year,$month,$day) < 6)"としてください。

$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"です。

$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);
$dow = Day_of_Week($year,$month,$day);

この関数は、与えられた日の週の中での順番を返します。 月曜なら"1"、火曜なら"2"、そして日曜日の"7"までを返します。 キリスト教の暦の元となっているヘブライ暦において、週は日曜日から始まって安息日または土曜日で終わります。 (この日は、聖書に記述されている創世記において、主が世界をおつくりになって休まれた日です)

中世に、カトリックのPopesがキリスト教徒をヘブライ信仰から引き離すために日曜日を公用の休日として制定しました。

今日、日曜と土曜はいつも"週末(week-end)"と呼ばれて、休日として共通に考えられています。

経験と矛盾しないように、現在の標準(ISO/R 2015-1971やDIN 1355、それからISO 8601のような)は月曜日を週の初めとして定義しました。

$week = Week_Number($year,$month,$day);

この関数は、与えられた日が、第何週目にあるかを返します。 与えられた日が前年の最後の週にある場合は、"0"が返されます。 与えられた日が翌年の最初の週にある場合は、"Weeks_in_Year($year) + 1"の値が返されます。

($week,$year) = Week_of_Year($year,$month,$day);

この関数は、与えられた日がどの週に存在するかということと、その週が存在する年を返します。

例えば、与えられた日が前年の最後の週に存在していれば、"(Weeks_in_Year($year-1), $year-1)"の値が返されます。

もし、与えられた日が翌年の最初の週に存在していれば、"(1, $year+1)"が返されます。

そうでなければ、"(Week_Number($year,$month,$day), $year)"が返されます。

$week = Week_of_Year($year,$month,$day);

スカラーコンテキストにおいては、この関数は週の数を返すだけです。 この機能で、"($week) = Week_of_Year($year,$month,$day);" と書く代わりに"$week = Week_of_Year($year,$month,$day);"と書けます。 ("$week"の周りにある丸括弧を注目すること)

与えられた日が前年の最後の週に存在していれば、"Weeks_in_Year($year-1)"の値が返されます。 もし、与えられた日が翌年の最初の週に存在していれば、"1"が返されます。 そうでなければ、"Week_Number($year,$month,$day)"が返されます。

この関数を、スカラーコンテキストとして扱うのは、危険な特徴です。というのもその週がどの年にあるかを知らなければ、うかつな間違った思い込みをするかもしれません。

例えばもし離れた日付を扱い続けると、与えられた日がある週がいつも同じ年にあると思い込むことがありえます。同じ状況でも運が悪ければ間違っているのに、です。

多くの年においては、例えば12月31日は翌年の週番号に所属しています。 あなたの考えている日(この例では12月31日ですが)とその年が同じだと思い込むと、 あなたはその年の最初の週に送られてしまいます。運が悪ければその週の月曜日とか、その前の年に存在するところにまで!

こんなことは、たとえば実際に2002年に起こります。 ですから、対応する年をとにかく必要とするようにしておいて、記録するようにしてください。

あなたがこのことを理解したのであれば、覚えていなくてもかまいません。 でも、単純にこの関数をスカラーコンテキストでは使わないでください。

($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ならば水曜日・・・・等です。

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番目の与えられた週番号の日がない場合には、空のリストを返します。

($year,$week,$dow) = Standard_to_Business($year,$month,$day);

この関数は、一般的な記述方法(年と月と日)からビジネス書式(年と週と週番号)に変換します。

($year,$month,$day) = Business_to_Standard($year,$week,$dow);

この関数は、ビジネス書式(年と週と週番号)から一般的な記述方法(年と月と日)に変換します。

$Dd = Delta_Days($year1,$month1,$day1, $year2,$month2,$day2);

この関数は、二つの与えられた日の間隔を返します。 2つの日付が時系列順であれば(つまり、#1の日付が#2の日付よりも前にあれば)正の値を返しますし、逆であれば負の値を返します。 同一である場合の結果はゼロです。

($Dd,$Dh,$Dm,$Ds) = Delta_DHMS($year1,$month1,$day1, $hour1,$min1,$sec1, $year2,$month2,$day2, $hour2,$min2,$sec2);

この関数は、二つの与えられた日と時刻から、その間隔を返します。

2つの日付が時系列順になっている、すなわち#1の日付が#2の日付がの前にあれば4つの値は全て正になります。 そして、二つの日付が逆になっていれば、(4つの値が全て)負の値となります。

これは、"Delta_DHMS()"と"Add_Delta_DHMS()"の2つの関数(ずっと下で解説してあります)が互いに反対であり、補い合っているからです。

  Add_Delta_DHMS(@date1,@time1, Delta_DHMS(@date1,@time1, @date2,@time2))

とすれば"(@date2,@time2)"を再び得ることになりますし、

  Add_Delta_DHMS(@date2,@time2,
      map(-$_, Delta_DHMS(@date1,@time1, @date2,@time2)))

ならば"(@date1,@time1)"ですし、

  Delta_DHMS(@date1,@time1, Add_Delta_DHMS(@date1,@time1, @delta))

ならば"@delta"です。

二つの日と時刻が完全に同じならば、ゼロを返します。

($Dy,$Dm,$Dd) = Delta_YMD($year1,$month1,$day1, $year2,$month2,$day2);

この関数は、次のベクトルを返します

    ( $year2 - $year1, $month2 - $month1, $day2 - $day1 )

二つの日付のどちらかが意味を持たなければ、エラーになります。

($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()"を基にしていますが、追加の時刻計算を別に行います。 時刻の繰越が発生すれば、"$D_d"の値がそれに応じて調整され、正しい日と時刻の間隔が得られます。

引数は、正の答えを出すには時系列順であることが望まれます。

どんな場合であっても、最初の日と時刻、すなわち($year1,$month1,$day1, $hour1,$min1,$sec1)に関数の答えを足すと、 2つ目の日と時刻($year2,$month2,$day2, $hour2,$min2,$sec2)を再び得ることができます。 そしてまた、関数の答えの全ての符号を逆にした負の値を2つ目の日と時刻に足すと、最初の日と時刻が得られます。

日と時刻の値の足し算や、日と時刻の間隔については、ずっと下のほうにある、"Add_Delta_YMDHMS()" 関数を見てください。

二つの日と時刻のどちらかでも無意味な値が入っていれば、エラーが発生します。

($Dd,$Dh,$Dm,$Ds) = Normalize_DHMS($Dd,$Dh,$Dm,$Ds);

この関数は、4つの任意の値、すなわち日と時間と分と秒を取り(符号が違ってもかまいません)、 時間・分・秒が[-23..23][-59..59][-59..59]の範囲にあるように正常化させます。 そしてまた、4つの値の符号が全て同じ(もしくはゼロ)になるようにします。

与えられた値に触れることはありません。すなわち、変化はさせません。

($year,$month,$day) = Add_Delta_Days($year,$month,$day, $Dd);

この関数には2つの原理的な使い方がある。

まず、この関数で最初の日と日数のオフセット(これは正かもしれないし負かもしれない) から新しい日付を計算することができます。 例えば、「今日から90日後の日付はなんだろう?」のような質問に答えられます。

(週のオフセットを加えたければ、単にその週のオフセットに"7"をかけて、日のオフセットに加えてください)

もう一つは、日付の正規の日付の表現を変更することができます。 すなわち、ある日における数(紀元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 1 A.D.), back into a date given as year, month and day.

というのは、"1"から数え始めたとすれば、あなたは元の日付に戻るために正規の日数を引き算する必要があります。 すなわち

  $canonical = Date_to_Days($year,$month,$day);

  ($year,$month,$day) = Add_Delta_Days(1,1,1, $canonical - 1);

さらに言えば、この関数は"Delta_Days()"の逆関数です。すなわち

  Add_Delta_Days(@date1, Delta_Days(@date1, @date2))

とすれば"@date2"を再び得ることができるし、

  Add_Delta_Days(@date2, -Delta_Days(@date1, @date2))

ならば"@date1"だし、

  Delta_Days(@date1, Add_Delta_Days(@date1, $delta))

ならば"$delta"です。

($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);
($year,$month,$day) = Add_Delta_YM($year,$month,$day, $Dy,$Dm);

この関数は、与えられた日に年と月の両方もしくは片方のオフセットを加えるために使います。

すぐ下に説明されている関数の("Add_Delta_YMD()")とは対照的に、 この関数は、(オフセットの値を足した後の)答えの年と月の中の、意味のある範囲内にその日があるかどうかをラッピングしません。 その代わりに、単に答えの月のなかの一番最後の日に切り捨てます。

例: (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ヶ月後等も認められるということです)

仮に、追加で日のオフセットを用いたくて"Add_Delta_Days()"を使用する前か後に"Add_Delta_YM()"を呼んだ場合、

  @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)です。

(これが"Add_Delta_YM()"関数がどうして日数のオフセットを持たないのかという理由でもあります。 なぜなら、日のオフセットを加える前に年や月を加えるのか、あるいは後に加えるのかという2つの関数がありうるからです)

最初の日が意味を持たない場合は、エラーが発生します。

"Add_Delta_YM( Add_Delta_YM(@date, $Dy,$Dm), -$Dy,-$Dm );"とすることで、いつももとの日付が得られるわけではありません。 (上の例を考えてみてください)

(訳者注:7月31日の1ヶ月後の1ヶ月前は7月31日ですが、1ヶ月前の1ヶ月後は7月30日ですね?)

($year,$month,$day) = Add_Delta_YMD($year,$month,$day, $Dy,$Dm,$Dd);

この関数は、与えられた日に、年と月と日のオフセットを加えます。

(週のオフセットを加えるためには、単に週のオフセットに7をかけて、日のオフセットに加えてください)

年・月・日の3つのオフセットはお互い独立に与えることができますし、異なる符号でもかまいません。

まず年と月のオフセットが先に与えられ、日のオフセットは最後に処理されます。

仮に、例えば4月31日とか2月30日のような月の終わりより後の結果になってしまった場合、 余った分の日数は単純に翌月(翌年のこともあります)に繰り越されます。 (例えば4月の32日は5月の2日になります)

注意: この挙動は、前のバージョンのモジュールとは異なります。 前のバージョンでは、その月の最後の日に切り捨てられます。 もし、過去のバージョンの挙動を望むのであれば、 すぐ上に解説してある"Add_Delta_YM()"と"Add_Delta_Days()"の関数を代わりに使ってください。

注意: また、固定された日に対して年や月のオフセットが同義で無い場合においても この関数で実行された変換が、いつも逆方向に使って同じ結果がでるわけではありません! これは、完全に逆の関数が使える"Add_Delta_Days()"と"Add_Delta_DHMS()"とは異なります。 (例えば"Delta_Days()"と"Delta_DHMS()"の関数のヘルプを見てください)

同様の理由により、

  @date = Add_Delta_YMD(
          Add_Delta_YMD(@date, $Dy,$Dm,$Dd), -$Dy,-$Dm,-$Dd);

とすると、元の"@date"が必ず返ってくるわけではありません。 これはプログラムのバグではありませんし、そうあるべきなのです。 なぜなら、年や月の長さが変わりやすいからです。

($year,$month,$day, $hour,$min,$sec) = Add_Delta_YMDHMS($year,$month,$day, $hour,$min,$sec, $D_y,$D_m,$D_d, $Dh,$Dm,$Ds);

年・月・日のオフセットに加えて、時刻のオフセットを与える点を除いて、上の関数と同じです。

($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) = System_Clock([$gmt]);

あなたのオペレーティングシステムが、("time()"と"localtime()"もしくは"gmtime()")に相当する システム呼び出しをサポートしていれば、この関数はあなたのシステムの時計から提供された情報を返します。 すなわち、現在の日と時刻、そして年の中における日の順番、週の番号、そして夏時間が有効かどうかのフラグの値です。

これらの値の意味と範囲は以下の通りです。

        $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

"$doy"は、年の中における日の順番であり、時にユリウス日とも呼ばれます。 1から始まり、その年の日数まで大きくなります。 (訳者注:1月1日なら1ですし、12月31ならば365もしくは366となります)

週番号("$dow")は、月曜ならば"1"ですし、"2"ならば火曜日で、"7"の土曜までです。

夏時間のフラグ("$dst")は、そんな情報があなたのシステム上に存在しなければ"-1"ですし、 夏時間ではなければ(つまり冬時間です)であれば"0"ですし、夏時間が有効なら"1"です。

あなたのOSが必要なシステムコールを提供していない場合には"not available on this system"という致命的エラーメッセージを出します。

もし、この例外をあなた自身が使用するには、"eval"を以下のように使います。 If you want to handle this exception yourself, use "eval" 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の表現を評価する方法です)。

オプションの(真偽値としての)"$gmt"が与えられた場合、 その値が真、すなわち("1")ならば"localtime()"の代わりに"gmtime()" が内部的に使われることになり、ローカルな時刻の変わりにグリニッジ時刻(GMTもしくはUTC)が返されます。

($year,$month,$day) = Today([$gmt]);

この関数は、上の"System_Clock()"関数によって返される値のサブセットを返します。 すなわち、現在の年・月・日を返します。

相当するシステム上の関数がオペレーティングシステム上に存在していなければ、"not available on this system" の致命的エラーメッセージが発生します。

もし、オプションの真偽値の"$gmt"が与えられれた場合の動作は、 真、すなわち("1")ならば"localtime()"の代わりに"gmtime()" が内部的に使われることになり、ローカルな時刻の変わりにグリニッジ時刻(GMTもしくはUTC)が返されます。

($hour,$min,$sec) = Now([$gmt]);

この関数は、上の"System_Clock()"関数によって返される値のサブセットを返します。 すなわち、現在の時刻(時間・分・秒)を返します。

相当するシステム上の関数がオペレーティングシステム上に存在していなければ、"not available on this system" の致命的エラーメッセージが発生します。

もし、オプションの真偽値の"$gmt"が与えられれた場合の動作は、 真、すなわち("1")ならば"localtime()"の代わりに"gmtime()" が内部的に使われることになり、ローカルな時刻の変わりにグリニッジ時刻(GMTもしくはUTC)が返されます。

($year,$month,$day, $hour,$min,$sec) = Today_and_Now([$gmt]);

この関数は、上の"System_Clock()"関数によって返される値のサブセットを返します。 すなわち、現在の日付(年・月・日)と時刻(時間・分・秒)を返します。

相当するシステム上の関数がオペレーティングシステム上に存在していなければ、"not available on this system" の致命的エラーメッセージが発生します。

もし、オプションの真偽値の"$gmt"が与えられれた場合の動作は、 真、すなわち("1")ならば"localtime()"の代わりに"gmtime()" が内部的に使われることになり、ローカルな時刻の変わりにグリニッジ時刻(GMTもしくはUTC)が返されます。

$year = This_Year([$gmt]);

この関数は、ローカルな時刻に応じて現在の時刻を返します。 This function returns the current year, according to local time.

相当するシステム上の関数がオペレーティングシステム上に存在していなければ、"not available on this system" の致命的エラーメッセージが発生します。

もし、オプションの真偽値の"$gmt"が与えられれた場合の動作は、 真、すなわち("1")ならば"localtime()"の代わりに"gmtime()" が内部的に使われることになり、ローカルな時刻の変わりにグリニッジ時刻(GMTもしくはUTC)が返されます。 しかしながら、これは年の変わる数時間の間だけ違いを生じさせるだけです。(24時間近くも異なる可能性がある太平洋の島国にいる場合以外)

($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) = Gmtime([time]);

これは、Perl組み込みの"gmtime()"関数と同等です。"gmtime" in perlfuncも見てください。

返される値とその意味は以下の通りです。

        $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

"$doy"は、年の中の日の順番で、ユリウス日と呼ばれることもあります。 "1"から始まって、その年の日数まで増えます。

週番号の("$dow")は、"1"ならば月曜、"2"ならば火曜で、"7"の土曜日まであります。

夏時間のフラグ("$dst")は、そんな情報があなたのシステム上に存在しなければ"-1"ですし、 夏時間ではなければ(つまり冬時間です)であれば"0"ですし、夏時間が有効なら"1"です。

時間の値が範囲外、すなわち[0..(~0>>1)]の場合には、"time out of range"の致命的エラーが発生します。

時間の値を省略すると、"time()"の値を内部的に代わりに呼び出します。

($year,$month,$day, $hour,$min,$sec, $doy,$dow,$dst) = Localtime([time]);

これはPerlの組み込みの"localtime()"関数と同等です。"localtime" in perlfuncも見てください。

範囲と意味は以下の通りです。

        $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

"$doy"は、年の中の日の順番で、ユリウス日と呼ばれることもあります。 "1"から始まって、その年の日数まで増えます。

週番号の("$dow")は、"1"ならば月曜、"2"ならば火曜で、"7"の土曜日まであります。

夏時間のフラグ("$dst")は、そんな情報があなたのシステム上に存在しなければ"-1"ですし、 夏時間ではなければ(つまり冬時間です)であれば"0"ですし、夏時間が有効なら"1"です。

時間の値が範囲外、すなわち[0..(~0>>1)]の場合には、"time out of range"の致命的エラーが発生します。

時間の値を省略すると、"time()"の値を内部的に代わりに呼び出します。

$time = Mktime($year,$month,$day, $hour,$min,$sec);

この関数は、日付を時間の値に変換します。つまり、あなたのシステムが想定している"新時代"からの秒数に変換します。 Unixや、ほとんどのシステム上では、1970年の1月1日の深夜(GMT)からの秒数です。 MacOS Classicにおいては、1904年1月1日の深夜(ローカル時間)からの秒数です。

この関数は、"POSIX::mktime()"関数と似ています。(詳細は"mktime" in POSIXを見てください) しかしながら"POSIX::mktime"と異なる点としては、この関数の想定している日付の範囲です。 つまり、2001年ならば2001と表記しますし、月の数は1から12です。

致命的エラーの"date out of range"は、与えられた時刻が新時代からの秒数では表現出来ない場合に発生します。 (例えば新時代の前であったり、32 ビットのUnixシステム上で19-Jan-2038 03:14:07 GMT以降であったりとか MacOS ClassicのMacintosh上における06-Feb-2040 06:28:15 (local time)以降等の場合です)

"POSIX::mktime()"と同様に、この関数は内部的に"mktime()"のシステムコールを行います。

このことは、与えられた日付と時刻をローカルタイムとして扱うということであって、 この関数から返される値はあなたのマシンが設定されているタイムゾーンとか サマータイムを使っているか(またはそのとき使っていたか)、そしてシステム上の時計それ自身に依存します。

注意として"mktime()"は、 いくつかのシステム上において、"localtime()"の出力を"mktime()"に入れた場合に いつも同じ時刻の値を返すわけではありません。

つまり、同じ"$time"の値を与えても"Mktime((Localtime($time))[0..5])"がいつも同じ値とは限りません。

($D_y,$D_m,$D_d, $Dh,$Dm,$Ds, $dst) = Timezone([time]);

この関数は、"localtime(time)"と"gmtime(time)"の違い、 すなわち現在の場所と与えられた"time"におけるタイムゾーンのオフセットを返します。

そのオフセットは、あなたがグリニッジより東にいれば正の値ですし、 (サマータイムを実施している場合の一部の場所を除いて)西にあれば負の値となります。

このオフセットは、関連するシステムのセッティングの全て、そしてあなたのマシンのパラメーターに影響を受けます。 例えば、地域・環境変数("TZ"とか)・システム上の時計それ自身です。 詳細は、あなたのシステムの関連する文書を読んでください。

仮に、"time"が省略されれば、"time()"関数が自動的に内部的に (Perlの組み込み関数の"localtime()"や"gmtime()"と同じように)呼び出されます。

時間の値が範囲外、すなわち[0..(~0>>1)]の場合には、"time out of range"の致命的エラーが発生します。

返される配列の最後の要素は、現在夏時間が有効かどうかのフラグです。 このフラグが負の値(-1)であればあなたのシステムにその情報がありません。 ゼロ(0)ならば夏時間は有効ではなく、正の値(+1)ならば夏時間が有効です。

夏時間が現在有効かどうかをすばやくチェックするには、この関数をスカラーコンテキストで評価してください。 (スカラーコンテキストでは、Perlはリストの最後の要素を返します)

  if (scalar Timezone > 0) { # 夏時間が有効ならば

しかしながら、もうあと少し有能ならば、こうするでしょう。

  if (scalar System_Clock > 0) { # 夏時間が有効ならば
$time = Date_to_Time($year,$month,$day, $hour,$min,$sec);

この関数は、BSD関数の"timegm()"(全てのUnixシステム上で使えるわけではありません)の代わりであり、 日付と時刻から、時刻の数字、すなわちあなたのシステムが紀元としている時間からの秒数に変換します。 Unixをはじめとする多くのシステムにおいては、1970年の1月1日の深夜(GMT)からの秒数です。 MacOS Classicにおいては、1904年1月1日の深夜(ローカル時間)からの秒数です。

Unixにおいては、日付や時刻はUTC("Universal Time Coordinated" 協定世界時)であると考えられていて、 その値を返します。

UTCは、(例えば地球の回転における小さな変化を計測するための)うるう秒を持っている点を除いて GMT("Greenwich Mean Time" グリニッジ標準時)とほとんど同じです。

しかしながらMacOS Classicにおいては、出入力ともにローカルな時間として扱われます。

年や月の範囲については、このモジュールの他のものと同じ決まりに従います。 (そして、そのUnixと同等のルールを変えることも出来ません) すなわち、年は2001年なら2001だし、月の範囲は1から12までです。

致命的エラーの"date out of range"は、与えられた時刻が新時代からの秒数では表現出来ない場合に発生します。 (例えば新時代の前であったり、32 ビットのUnixシステム上で19-Jan-2038 03:14:07 GMT以降であったりとか MacOS ClassicのMacintosh上における06-Feb-2040 06:28:15 (local time)以降等の場合です)

この関数は、すごく速くあるべきです。というのも、簡単な方法で成し遂げられていて、 一切のシステムコールを行わないからです。

さらに言えば、"Date_to_Time()"と"Time_to_Date()"の関数は、お互いに補い合うことが保障されています。 つまり、"Date_to_Time(Time_to_Date($time))"と"Time_to_Date(Date_to_Time($year,$month,$day, $hour,$min,$sec))" は、いつも最初の値を返します。

($year,$month,$day, $hour,$min,$sec) = Time_to_Date([time]);

この関数は、POSIXの"gmtime()"関数(そしてPerl組み込みと同等のものです)の代わりです。 時刻の値から、それに相当する日付と時刻に変換することが出来ます。 与えられる時刻の値は、あなたのシステムが紀元としている時刻からの秒数でなければなりません。 Unixをはじめとする多くのシステムにおいては、1970年の元旦の深夜(GMT)であり、MacOS Classicにおいては、 ローカル時間の1904年の元旦の深夜からです。

Unixにおいては、日付や時刻はUTC("Universal Time Coordinated" 協定世界時)であると考えられていて、 その値を返します。

UTCは、(例えば地球の回転における小さな変化を計測するための)うるう秒を持っている点を除いて GMT("Greenwich Mean Time" グリニッジ標準時)とほとんど同じです。

しかしながらMacOS Classicにおいては、出入力ともにローカルな時間として扱われます。

入力される"time"の値が省略されると、"time()"関数が自動的に内部的に呼び出されます。 (Perlの組み込み関数における"localtime()"と"gmtime()"と似ています)

"time out of range"のエラーは、与えられた時刻の値が負の場合に発生します。

この関数は、すごく速くあるべきです。というのも、簡単な方法で成し遂げられていて、 一切のシステムコールを行わないからです。

さらに言えば、"Date_to_Time()"と"Time_to_Date()"の関数は、お互いに補い合うことが保障されています。 つまり、"Date_to_Time(Time_to_Date($time))"と"Time_to_Date(Date_to_Time($year,$month,$day, $hour,$min,$sec))" は、いつも最初の値を返します。

($year,$month,$day) = Easter_Sunday($year);

この関数は、よく知られている"Gaussian Rule"を使って1583年から2299年まで全ての年 (それ以外の年を入れると、致命的な"year out of range"エラーメッセージが発生します) の復活祭の日付を計算します。

復活祭の日付によって計算できる、関連するキリスト教の祝祭日です。 (訳者注:これ以上の訳は僕には出来ません。祭日の名前を見て分かるような人なら、わざわざこの日本語ドキュメントを見ませんよね?)

  Carnival Monday / Rosenmontag / Veille du Mardi Gras   =  -48 days #謝肉祭
  Mardi Gras / Karnevalsdienstag / Mardi Gras            =  -47 days #肥ゆる火曜日
  Ash Wednesday / Aschermittwoch / Mercredi des Cendres  =  -46 days #灰の水曜日
  Palm Sunday / Palmsonntag / Dimanche des Rameaux       =   -7 days #枝の主日
  Easter Friday / Karfreitag / Vendredi Saint            =   -2 days #聖金曜日
  Easter Saturday / Ostersamstag / Samedi de Paques      =   -1 day  #イースターサタデー
  Easter Monday / Ostermontag / Lundi de Paques          =   +1 day  #イースターマンデー
  Ascension of Christ / Christi Himmelfahrt / Ascension  =  +39 days #キリスト昇天祭
  Whitsunday / Pfingstsonntag / Dimanche de Pentecote    =  +49 days #五旬節聖霊降臨の祝祭
  Whitmonday / Pfingstmontag / Lundi de Pentecote        =  +50 days #その翌日
  Feast of Corpus Christi / Fronleichnam / Fete-Dieu     =  +60 days #キリストの聖体祝日

上に紹介したオフセットの対応する祝祭日のものを使って、以下のようにしてください。

  ($year,$month,$day) = Add_Delta_Days(Easter_Sunday($year), $offset));
if ($month = Decode_Month($string))

この関数は、選択されている言語の(詳しくは、このパッケージの多言語対応の部分を見てください) 月の名前を含む引数の文字列もしくはユニークな識別できる月の名前の省略(つまり最初の何文字か)をとり、 マッチに成功すれば1から12までの対応する月の番号を返しますし、そうでなければ"0"を返します。 (だから、帰ってきた値はif構文の条件文で使うことが出来ます)

入力された文字列は、月の名前が属していない文字を含まないかもしれません。 特に、余白を導いたり引きずった場合は。

また、マッチングは鈍感に動作します。(あなたの現在のシステムの場所に依存するかもしれません)

"英語"が現在選択されている言語の場合(これがデフォルトですが)、以下の例の全てで"9"が返されます。

  $month = Decode_Month("s");
  $month = Decode_Month("Sep");
  $month = Decode_Month("septemb");
  $month = Decode_Month("September");
if ($dow = Decode_Day_of_Week($string))

この関数は引数として現在選択されている言語における曜日の名前 (詳しくは、このパッケージの多言語対応の部分を見てください)、 もしくはユニークな識別できる曜日の名前の省略(つまり最初の何文字か)をとり、 マッチに成功すれば1から7までの対応する曜日の番号を返しますし、そうでなければ"0"を返します。 (だから、帰ってきた値はif構文の条件文で使うことが出来ます)

入力された文字列は、曜日の名前が属していない文字を含まないかもしれません。 特に、余白を導いたり引きずった場合は。

また、マッチングは鈍感に動作します。(あなたの現在のシステムの場所に依存するかもしれません)

"英語"が現在選択されている言語の場合(これがデフォルトですが)、以下の例の全てで"3"が返されます。

  $dow = Decode_Day_of_Week("w");
  $dow = Decode_Day_of_Week("Wed");
  $dow = Decode_Day_of_Week("wednes");
  $dow = Decode_Day_of_Week("Wednesday");
if ($lang = Decode_Language($string))

この関数は、このパッケージでサポートされている言語(言語そのものです)の名前を含む文字列、 もしくはユニークな識別できる言語名の名前の省略(つまり最初の何文字か)をとり、 マッチに成功すれば1から13までの割り当てられた対応する内部で使用される番号を返しますし、そうでなければ"0"を返します。 (だから、帰ってきた値はif構文の条件文で使うことが出来ます)

入力された文字列は、言語の名前が属していない文字を含まないかもしれません。 特に、余白を導いたり引きずった場合は。

また、マッチングは鈍感に動作します。(あなたの現在のシステムの場所に依存するかもしれません)

以下の13個の言語に割り当てられたオリジナルな番号です。

            English                    ==>    1 (default)#デフォルトは英語です
            Fran軋is    (French)       ==>    2 #フランス語
            Deutsch     (German)       ==>    3 #ドイツ語
            Espal     (Spanish)      ==>    4 #スペイン語
            Portugu黌   (Portuguese)   ==>    5 #ポルトガル語
            Nederlands  (Dutch)        ==>    6 #オランダ語
            Italiano    (Italian)      ==>    7 #イタリア語
            Norsk       (Norwegian)    ==>    8 #ノルウェー語
            Svenska     (Swedish)      ==>    9 #スウェーデン語
            Dansk       (Danish)       ==>   10 #デンマーク語
            suomi       (Finnish)      ==>   11 #フィンランド語
            Magyar      (Hungarian)    ==>   12 #ハンガリー語
            Polski      (Polish)       ==>   13 #ポーランド語

別の言語をこのパッケージの中に追加する方法については "INSTALL.txt"のファイルの中の"How to install additional languages"の説明を見てください。

独自の割り当て(他の言語をインストールしていない場合)において、 以下の例は全て"3"を返します。

  $lang = Decode_Language("d");
  $lang = Decode_Language("de");
  $lang = Decode_Language("Deutsch");

いくつかのシステムにおいては、直接キーボードを使って特別な国際的な文字を入れることができないかもしれません。

しかしながら問題にならないと思いますが。というのも言語の名前を構成している最初の数文字からなる省略で、 特別な国際的な文字が出てくる前に識別することが出来るからです。

if (($year,$month,$day) = Decode_Date_EU($string))

この関数は、与えられた文字列を解析し、そこに埋め込まれた日付を取り出そうとします。

この関数は、入力された文字列から意味のある時刻を取り出せなかった時には空のリストを返しますし、 そうでなければ見つけた日付を返します。

この関数は、ヨーロッパの順番(だからこんな名前がついているんですけれど)で日付が与えられれば、 ほとんどどんな形式でも受け付けます。すなわち(日-月-年)の順番です。

それよって、ゼロや数値でない文字列が日の前や年の後に存在してもかまいません。

さらに言えば、3つの項目の間(つまり日と月、月と年の間です)にゼロや英数字でない文字列も許されます。

月は数値として与えられてもいいですし、選択されている言語の名前である英数字で与えられてもかまいませんし、 それらを識別できるユニークな省略形でも構いません。

(詳しくは、このパッケージの多言語対応の部分を見てください)

仮に年が2桁(100以下の数字)しか与えられなかった場合は、"Moving Window()"関数のところで解説してあるように 現在の年から前後50年の場所にマッピングします(ずっと下を見てください)。

仮に、日や月、年が数値で与えられていて、しかしながらそれらの間に区切りが存在していなければ、 以下のように区切りが設定されます。

             文字列の長さ:      区切り:
                  3              dmy
                  4              dmyy
                  5              dmmyy
                  6              ddmmyy
                  7              dmmyyyy
                  8              ddmmyyyy

("d"は日、"m"は月、"y"は年を意味します)

介在する区切りがない場合は、その他全ての数値だけからなる文字列は排除されます。 すなわち、認められません。

例:

  "3.1.64"
  "3 1 64"
  "03.01.64"
  "03/01/64"
  "3. Jan 1964"
  "Birthday: 3. Jan '64 in Backnang/Germany"
  "03-Jan-64"
  "3.Jan1964"
  "3Jan64"
  "030164"
  "3ja64"
  "3164"

すばらしい! (そうするためには、このディストリビューションの"example"サブディレクトリに 対応する例のアプリケーションがあります)

if (($year,$month,$day) = Decode_Date_US($string))

この関数は文字列を解析し、そこに含まれている日付を取り出そうとします。

この関数は、入力された文字列から意味のある時刻を取り出せなかった時には空のリストを返しますし、 そうでなければ見つけた日付を返します。

この関数は、アメリカの順番(だからこんな名前がついているんですけれど)で日付が与えられれば、 ほとんどどんな形式でも受け付けます。すなわち(月-日-年)の順番です。

それよって、ゼロや数値でない文字列が月の前や後に存在してもかまいません。 (すなわち月の前に存在し、直後の日付と分けられていれば構いません)

さらに言えば、年の後と同様に日と年の間にゼロや英数字でない文字列も許されます。

月は数値として与えられてもいいですし、選択されている言語の名前である英数字で与えられてもかまいませんし、 それらを識別できるユニークな省略形でも構いません。

(詳しくは、このパッケージの多言語対応の部分を見てください)

仮に年が2桁(100以下の数字)しか与えられなかった場合は、"Moving Window()"関数のところで解説してあるように 現在の年から前後50年の場所にマッピングします(ずっと下を見てください)。

仮に、日や月、年が数値で与えられていて、しかしながらそれらの間に区切りが存在していなければ、 以下のように区切りが設定されます。

              文字列長:         区切り:
                  3              mdy
                  4              mdyy
                  5              mddyy
                  6              mmddyy
                  7              mddyyyy
                  8              mmddyyyy

("d"は日、"m"は月、"y"は年を意味します)

介在する区切りがない場合は、その他全ての数値だけからなる文字列は排除されます。 すなわち、認められません。

仮に、日と年が数値だけからなる文字列で区切りがなければ、以下のように区切られます。

              文字列長:         区切り:
                  2              dy
                  3              dyy
                  4              ddyy
                  5              dyyyy
                  6              ddyyyy

("d"は日、"m"は月、"y"は年を意味します)

例:

  "1 3 64"
  "01/03/64"
  "Jan 3 '64"
  "Jan 3 1964"
  "===> January 3rd 1964 (birthday)"
  "Jan31964"
  "Jan364"
  "ja364"
  "1364"

すばらしい! (そうするためには、このディストリビューションの"example"サブディレクトリに 対応する例のアプリケーションがあります)

$year = Fixed_Window($yy);

この関数は、"fixed window"と呼ばれる手法で2桁の数字を4桁の数字に変換します。

負の年数を入れると0が返される以外は、2桁でないその他のどんな数でも変換されることなく通り抜けます。

70未満の2桁の数"yy"は"20yy"に、そして70以上(訳者注:70は含みます)の数であれば(ただし100未満) "19yy"に変換されます。

このパッケージのオリジナルバージョンでは、基本となっている世紀は "1900"、基本の年は"70"(これはUNIXの標準です)に設定されていますが、これらの定数(紀元とも呼ばれますが) はこのモジュールをコンパイルする際に、("DateCalc.c" and "DateCalc.h"のファイルで)任意に選ぶことができます。

$year = Moving_Window($yy);

この関数は、必要なシステムコール(system clock)が使用できる状況の下で "moving window"と呼ばれる手法で2桁の数字を4桁の数に変換します。 そうでなければ、すぐ上で解説してある"fixed window"の手法に戻ることになります。

負の年数を入れると0が返される以外は、2桁でないその他のどんな数でも変換されることなく通り抜けます。

2桁の年を表す数は、現在から見て両方向(過去、そして未来への)50年の幅の"window" にしたがって配置されます。

つまり、まず2桁の数字は現在と同じ世紀に配置されます。 もしも、その答えが現在の年から50年よりも前であれば、答えに100年足されます。 また、答えが現在の年から50年より多く後であれば、100が引かれます。

$date = Compress($year,$month,$day);

注意:この関数は、過去の遺物です。廃止される可能性もあるので、使用しないでください。

この関数は、日付を16ビットにエンコードし、その値を返します。

エンコードされるスキーマ(仕組み)は以下の通りです。

            ビット列:      FEDCBA9 8765 43210
                内容:      yyyyyyy mmmm ddddd

("yyyyyyy"は年の数を含み、 "mmmm"は月の数、そして"ddddd"は日の数です)

この関数は、与えられた日付が意味を持たない値であれば"0"を返すので、 与えられた日付が意味を持った値を構成するかどうかを、帰ってきた値をif構文の中の条件表現でチェックすることができます。

この特殊なエンコードスキーマで、今までのようなデコードをしなくても、 compressされた日付を(小さかったり大きかったりといったような)等価演算や順番付けをすることができます。

しかしながら、隣接した日付のcompressされた表現同士も隣接した値であるとは限りません

つまり、日付表現のcompressされた値を増やしたからといって、意味のある値が生じるとは限りません。

また、この関数は一つの世紀に対してしか用いることができません。

基本となる世紀と年("紀元"とも呼ばれます)を定義することで(このモジュールをコンパイルする際に)その一つの世紀を選ぶことができます。 オリジナルの配布物としては、紀元の世紀は1900(つまり20世紀)、そして基本となる年は70年となっています(UNIXの標準です)。

この条件では、この関数は1970年から2069年まで扱うことができます。

仮に、与えられた年が"95"であれば、このパッケージは自動的にあなたが1995を意図していると仮定します。 しかしながら、70よりも小さな値(例えば"64"のような)を入れた場合、 このパッケージはあなたが2064年を意図していると仮定します。

しかしながら、(制限された)2桁の数を使用しなくてはならないわけではありません。

サポートされている範囲(すなわちオリジナルだと"1970"から"2069"までです)の範囲にある4桁の年の数も受け付けます。

この関数は、裏側の互換性のために維持されているので、使用は推奨されていません。

if (($century,$year,$month,$day) = Uncompress($date))

注意:この関数は、過去の遺物です。廃止される可能性もあるので、使用しないでください。

この関数は、上で使用されている"Compress()"関数によってエンコードされたデータをデコードします。

この関数は"$date"が意味のある値を表せば、"$date"にエンコードされた世紀、年、月、日を返し、 そうでなければ空のリストを返します。

"$year"で返される年は、2桁の数字(つまり100で割ったあまり)で、"$century + $year"によってのみ 4桁の年が生み出されます。(例えば1900 + 95 = 1995)

この関数は、裏側の互換性のために維持されているので、使用は推奨されていません。

*

if (check_compressed($date))

注意:この関数は、過去の遺物です。廃止される可能性もあるので、使用しないでください。

この関数は、与えられた値が意味のあるcompressされた日付であれば真("1")を返し、そうでなければ偽("0")を返します。

この関数は、裏側の互換性のために維持されているので、使用は推奨されていません。

$string = Compressed_to_Text($date);

注意:この関数は、過去の遺物です。廃止される可能性もあるので、使用しないでください。

この関数は"$date"にcompressされた日付を含んでいる固定長(常に9文字です)の文字列を返します。

文字列は、"dd-Mmm-yy"の形をしています。 "dd"は日付の2桁の数、"Mmm"は選択されている言語における月の名前の最初の3文字 (詳しくはずっと下にある多言語サポートの部分を読んでください)、 そして"yy"は年の2桁の数(年の数を100で割ったあまりです)となっています。

もしも、"$date"から意味のある日付が得られなければ、代わりに"??-???-??"が返されます。

この関数は、裏側の互換性のために維持されているので、使用は推奨されていません。

$string = Date_to_Text($year,$month,$day);

この関数は与えられた日付の"www dd-Mmm-yyyy"という形式の文字列表現を含む文字列を返します。 "www"は選択されている言語の曜日の名前の最初の3文字もしくは、選択されている言語に 特別な省略形があれば、その省略形です(詳しくはずっと下のほうの、多言語サポートの部分を見てください)。 "dd"は1桁もしくは2桁の日付、Mmmはその時選択されている言語における月の名前の最初の3文字の省略形、 "yyyy"は年数です。

仮に、意味のある値が入力されなければ、"not a valid date"エラーが発生します。

(あなたの望む形式の日付を表示するための短いコードは、このドキュメントの終わりのほうにあるレシピの項を見てください)

$string = Date_to_Text_Long($year,$month,$day);

この関数は、"Wwwwww, dd Mmmmmm yyyy"という形式の文字列表現を含む文字列を返します。 "Wwwwww"はその時選択されている言語における曜日の名前(詳しくはずっと下のほうの、多言語サポートの部分を見てください)、 "dd"は1桁もしくは2桁の日付、"Mmmmmm"はその時選択されている言語における月の名前、 "yyyy"は年数です。 This function returns a string containing a textual representation of the given date roughly of the form "Wwwwww, dd Mmmmmm yyyy", where "Wwwwww" is the name of the day of week in the currently selected language (see further below for details about the multi-language support of this package), "dd" is the day (one or two digits), "Mmmmmm" is the name of the month in the currently selected language, and "yyyy" is the number of the year in full length.

出力される文字列の形式は、選択されている言語によって変わります。 元の配布物では、以下のように定義されています。

  1  English    :  "Wwwwww, Mmmmmm ddth yyyy"        #英語
  2  French     :  "Wwwwww dd mmmmmm yyyy"           #フランス語
  3  German     :  "Wwwwww, den dd. Mmmmmm yyyy"     #ドイツ語
  4  Spanish    :  "Wwwwww, dd de mmmmmm de yyyy"    #スペイン語
  5  Portuguese :  "Wwwwww, dia dd de mmmmmm de yyyy"#ポルトガル語
  6  Dutch      :  "Wwwwww, dd mmmmmm yyyy"          #オランダ語
  7  Italian    :  "Wwwwww, dd Mmmmmm yyyy"          #イタリア語
  8  Norwegian  :  "wwwwww, dd. mmmmmm yyyy"         #ノルウェー語
  9  Swedish    :  "wwwwww, dd mmmmmm yyyy"          #スウェーデン語
 10  Danish     :  "wwwwww, dd. mmmmmm yyyy"         #デンマーク語
 11  Finnish    :  "wwwwww, dd. mmmmmmta yyyy"       #フィンランド語
 12  Hungarian  :  "dd. Mmmmmm yyyy., wwwwww"        #ハンガリー語
 13  Polish     :  "Wwwwww, dd Mmmmmm yyyy"          #ポーランド語

(あなたの個人的な好みに合うように、このモジュールをビルドする前に、"DateCalc.c"でこの形式を変えることができます。)

与えられた値が意味のある値でなければ、致命的な"not a valid date"エラーが発生します。

ノルウェー語における最初に存在している曜日の名前を利用するためには、 "lcfirst(Date_to_Text_Long($year,$month,$day));"を使ってください。

(あなたの望む形式の日付を表示するための例は、このドキュメントの終わりのほうにあるレシピの項を見てください)

$string = English_Ordinal($number);

この関数は、"$number"で与えられた基数詞の、(英語における)序数詞の省略を含む文字列を返します。 つまり

    0  =>  '0th'    10  =>  '10th'    20  =>  '20th'
    1  =>  '1st'    11  =>  '11th'    21  =>  '21st'
    2  =>  '2nd'    12  =>  '12th'    22  =>  '22nd'
    3  =>  '3rd'    13  =>  '13th'    23  =>  '23rd'
    4  =>  '4th'    14  =>  '14th'    24  =>  '24th'
    5  =>  '5th'    15  =>  '15th'    25  =>  '25th'
    6  =>  '6th'    16  =>  '16th'    26  =>  '26th'
    7  =>  '7th'    17  =>  '17th'    27  =>  '27th'
    8  =>  '8th'    18  =>  '18th'    28  =>  '28th'
    9  =>  '9th'    19  =>  '19th'    29  =>  '29th'

以下同様です。

$string = Calendar($year,$month[,$orthodox]);

この関数は、選択されている言語の与えられた年の中の与えられた月におけるカレンダーを返します。 (UNIXの"cal"コマンドと似ています) (詳しくはずっと下のほうにある多言語サポートの部分を見てください)

例:

  print Calendar(1998,5);

とすると

           May 1998
  Mon Tue Wed Thu Fri Sat Sun
                    1   2   3
    4   5   6   7   8   9  10
   11  12  13  14  15  16  17
   18  19  20  21  22  23  24
   25  26  27  28  29  30  31

オプションの真偽値である"$orthodox"が与えられ、真の値であれば カレンダーは月曜ではなくて日曜から始まります。

$string = Month_to_Text($month);

この関数は、その時選択されている言語の与えられた月の名前を返します。 (詳しくはずっと下のほうにある多言語サポートの部分を見てください)

与えられた月が、意味のある範囲である"1"から"12"の中になければ、 致命的エラーの"month out of range"が発生します。

$string = Day_of_Week_to_Text($dow);

この関数は、その時選択されている言語の与えられた曜日の名前を返します。 (詳しくはずっと下のほうにある多言語サポートの部分を見てください)

与えられた曜日が、意味のある範囲である"1"から"7"の中になければ、 致命的エラーの"day of week out of range"が発生します。

$string = Day_of_Week_Abbreviation($dow);

この関数は、その時選択されている言語に曜日の特別な省略形があればそれを返します。 (詳しくはずっと下のほうにある多言語サポートの部分を見てください)

(オリジナルの配布物では、ポルトガル語にのみ真実ではありますが)

そうでなければ、選択されている言語の曜日の名前の最初の3文字が代わりに返されます。

与えられた曜日が、意味のある範囲である"1"から"7"の中になければ、 致命的エラーの"day of week out of range"が発生します。

現在、特殊な曜日の省略形は"Date_to_Text()"と"Calendar()"においてのみ、 内部的に使われています。

$string = Language_to_Text($lang);

この関数は、言語に割り振られている内部的な番号の表す、 このパッケージによってサポートされている言語の名前を返します。 This function returns the name of any language supported by this package when the internal number representing that language is given as input.

元の配布物がサポートしている13個の言語は以下の通りです。

            English                    ==>    1 (default)#デフォルトは英語です
            Fran軋is    (French)       ==>    2 #フランス語
            Deutsch     (German)       ==>    3 #ドイツ語
            Espal     (Spanish)      ==>    4 #スペイン語
            Portugu黌   (Portuguese)   ==>    5 #ポルトガル語
            Nederlands  (Dutch)        ==>    6 #オランダ語
            Italiano    (Italian)      ==>    7 #イタリア語
            Norsk       (Norwegian)    ==>    8 #ノルウェー語
            Svenska     (Swedish)      ==>    9 #スウェーデン語
            Dansk       (Danish)       ==>   10 #デンマーク語
            suomi       (Finnish)      ==>   11 #フィンランド語
            Magyar      (Hungarian)    ==>   12 #ハンガリー語
            Polski      (Polish)       ==>   13 #ポーランド語

別の言語をこのパッケージの中に追加する方法については "INSTALL.txt"のファイルの中の"How to install additional languages"の説明を見てください。

どれくらいの言語がインストールされているこのパッケージで使用できるかを判断するには、 ずっと下にある"Languages()"関数の説明を見てください。

$lang = Language();
Language($lang);
$oldlang = Language($newlang);

この関数は、現在選択されている言語は何かを判断し、その選択を変えることができます。 This function can be used to determine which language is currently selected, and to change the selected language.

それぞれの言語は、ユニークな内部的な番号を持っています。 Thereby, each language has a unique internal number.

元の配布物がサポートしている13個の言語は以下の通りです。

            English                    ==>    1 (default)#デフォルトは英語です
            Fran軋is    (French)       ==>    2 #フランス語
            Deutsch     (German)       ==>    3 #ドイツ語
            Espal     (Spanish)      ==>    4 #スペイン語
            Portugu黌   (Portuguese)   ==>    5 #ポルトガル語
            Nederlands  (Dutch)        ==>    6 #オランダ語
            Italiano    (Italian)      ==>    7 #イタリア語
            Norsk       (Norwegian)    ==>    8 #ノルウェー語
            Svenska     (Swedish)      ==>    9 #スウェーデン語
            Dansk       (Danish)       ==>   10 #デンマーク語
            suomi       (Finnish)      ==>   11 #フィンランド語
            Magyar      (Hungarian)    ==>   12 #ハンガリー語
            Polski      (Polish)       ==>   13 #ポーランド語

別の言語をこのパッケージの中に追加する方法については "INSTALL.txt"のファイルの中の"How to install additional languages"の説明を見てください。

どれくらいの言語がインストールされているこのパッケージで使用できるかを判断するには、 ずっと下にある"Languages()"関数の説明を見てください。

注意: あなたのプログラムが持ち運びできるように、決して内部的な番号を明示的に書いてはいけません。 というのも、インストールされているこのパッケージにどの言語が追加されたかによって 同じ番号であっても違うシステムでは違う言語を意味するかもしれないからです。

ですから、希望する言語を選ぶにはこのように書いてください。

  Language(Decode_Language("言語の名前"));

そしてまた(以前に)選択された言語を判断するには

  $language = Language_to_Text(Language());

とか

  $old_language = Language_to_Text(Language("Name_of_new_Language"));

と書いてください。

選ばれた言語が、その時インストールされているパッケージで使用できない場合は 静かに間違った(ランダムな)言語を使うようなことをせず、 特有のエラーメッセージが発生します。 (間違った言語を使うとのは、違うインストールされたパッケージにおける同じ内部的な番号の場合だけです)

このパッケージの現在の実装においては選択された言語は 月の名前、曜日の名前、内部の言語を用いる全ての関数 及び、同じDate::Calcをメモリーに置いている全てのプロセス においてグローバルにセッティングされます。

そのため、マルチユーザーな環境の下では驚くような影響が出るかもしれません。 そしてまた、Perlで将来的にマルチスレッドが使えるようになればよりその影響がでるでしょう。

$max_lang = Languages();

この関数は、インストールされているこのパッケージにおいて使用することのできる言語の(最大)数を返します。

(この値は、インストールされているものによって変わります)

別の言語をこのパッケージの中に追加する方法については

このパッケージの元の配布物においては13の組み込み言語があり、 あなた独自のインストールにおいて他の言語を一切追加していなければ"13"が返されるでしょう

if (($year,$month,$day) = Decode_Date_EU2($string))

この関数は"Decode_Date_EU()"(Cによって実装されています)と同義のPerlの関数です。 単に、特殊な要求に応えるため、必要性が出て来た時のため、そしてあなた自身の発展の基礎のために、 Perlにおいて(普通の手段を用いて)独自のルーチンを組むのが如何に楽かを例示しているという点だけです。

このPerlのバージョンにおける詳しい違いは、 許されている挟まれている(制限している)文字列を考える限りにおいてはCの同義のものよりもより寛大だという点です。

(あなたはcodeを見たり、経験的に、ちょっとした、ほとんど取るに足らない違いを指摘できますか? ヒント:"a3b1c64d"という文字列を両方の関数に入れてみてください)

if (($year,$month,$day) = Decode_Date_US2($string))

この関数は"Decode_Date_US()"(Cによって実装されています)と同義のPerlの関数です。 単に、特殊な要求に応えるため、必要性が出て来た時のため、そしてあなた自身の発展の基礎のために、 Perlにおいて(普通の手段を用いて)独自のルーチンを組むのが如何に楽かを例示しているという点だけです。

このPerlのバージョンにおける詳しい違いは、 許されている挟まれている(制限している)文字列を考える限りにおいてはCの同義のものよりもより寛大だという点です。

(ヒント:この違いは、"Decode_Date_EU()"と"Decode_Date_EU2()"の二つの関数の違いと同じです)

別の場合だと、Cのバージョンのほうが、Perlのバージョンよりもより寛大です。

(あなたはcodeを見たり、経験的に、ちょっとした、ほとんど取るに足らない違いを指摘できますか? ヒント:"(1/364)"という文字列を両方の関数に入れてみてください)

if (($year,$month,$day) = Parse_Date($string))

この関数は、UNIXの"date"コマンドやe-mailのヘッダに見られる日付形式を容易に解析できます。 (例えば、E-mailがいつ送られたのかを知るためなどに使えます)

例 #1:

  ($year,$month,$day) = Parse_Date(`/bin/date`);

例 #2:

  while (<MAIL>)
  {
      if (/^From \S/)
      {
          ($year,$month,$day) = Parse_Date($_);
          ...
      }
      ...
  }

この関数は、入力された文字列から意味のある日付を取り出せなければ空のリストを返します。

$lower = ISO_LC($string);

与えられた文字列のISO-Latin-1の文字セットを同等の小文字に置き換えたコピーを返します。

Perl組み込み関数の"lc()"に似ていますが、単なるASCIIコードではなくてISO-Latin-1のための関数です。

$upper = ISO_UC($string);

与えられた文字列のISO-Latin-1の文字セットを同等の大文字に置き換えたコピーを返します。

Perl組み込み関数の"uc()"に似ていますが、単なるASCIIコードではなくてISO-Latin-1のための関数です。

$string = Date::Calc::Version();

この関数は、このパッケージのコアとなっている C のライブラリー("DateCalc.c")の(数字の)バージョンナンバーを返します。 (これはまた自動的に"Calc.xs"ファイルのバージョンナンバーとなります)

普通の環境においては、このバージョンナンバーはPerl変数"$Date::Calc::VERSION"として見つかるもの唯一つだけです。 ("Calc.pm"ファイルのバージョンナンバーです)

この関数は、エクスポートすることができません。いつでも明示的に使用できます。 すなわち"Date::Calc::Version()"という形です。

他のモジュールにおいてバージョン関数と衝突する可能性のある名前は避けるべきです。

レシピ

1) 2つの日付を比較するにはどうしたらいいでしょう?

解答 #1:

  use Date::Calc qw( Date_to_Days );

  if (Date_to_Days($year1,$month1,$day1)  <
      Date_to_Days($year2,$month2,$day2))

  if (Date_to_Days($year1,$month1,$day1)  <=
      Date_to_Days($year2,$month2,$day2))

  if (Date_to_Days($year1,$month1,$day1)  >
      Date_to_Days($year2,$month2,$day2))

  if (Date_to_Days($year1,$month1,$day1)  >=
      Date_to_Days($year2,$month2,$day2))

  if (Date_to_Days($year1,$month1,$day1)  ==
      Date_to_Days($year2,$month2,$day2))

  if (Date_to_Days($year1,$month1,$day1)  !=
      Date_to_Days($year2,$month2,$day2))

  $cmp = (Date_to_Days($year1,$month1,$day1)  <=>
          Date_to_Days($year2,$month2,$day2));

解答 #2:

  use Date::Calc qw( Delta_Days );

  if (Delta_Days($year1,$month1,$day1,
                 $year2,$month2,$day2) > 0)

  if (Delta_Days($year1,$month1,$day1,
                 $year2,$month2,$day2) >= 0)

  if (Delta_Days($year1,$month1,$day1,
                 $year2,$month2,$day2) < 0)

  if (Delta_Days($year1,$month1,$day1,
                 $year2,$month2,$day2) <= 0)

  if (Delta_Days($year1,$month1,$day1,
                 $year2,$month2,$day2) == 0)

  if (Delta_Days($year1,$month1,$day1,
                 $year2,$month2,$day2) != 0)
2) 与えられた日付が、ある範囲の中にあるかどうかチェックするにはどうしたらいいでしょうか?
  use Date::Calc qw( Date_to_Days );

  $lower = Date_to_Days($year1,$month1,$day1);
  $upper = Date_to_Days($year2,$month2,$day2);

  $date = Date_to_Days($year,$month,$day);

  if (($date >= $lower) && ($date <= $upper))
  {
      # ok
  }
  else
  {
      # not ok
  }
3) 2つの時刻を伴った日付を比較するにはどうしたらいいでしょうか? ある与えられた間隔よりも離れてるとか近いとかをチェックするにはどうしたらいいでしょうか?

解答 #1:

  use Date::Calc qw( Add_Delta_DHMS Date_to_Days );

  @date1 = (2002,8,31,23,59,1);
  @date2 = (2002,9,1,11,30,59); # ==> 12時間より短い

  #@date1 = (2002,8,31,22,59,1);
  #@date2 = (2002,9,1,11,30,59); # ==> 12時間より長い

  #二つの日付を比較するだけならば、次の行は省略してください
  #(そしてまた、@date3と@d3を@date1と@d1にそれぞれ書き換えてください)

  @date3 = Add_Delta_DHMS(@date1, 0,12,0,0); # ==> これは12時間の間隔

  @d2 = ( Date_to_Days(@date2[0..2]), ($date2[3]*60+$date2[4])*60+$date2[5] );
  @d3 = ( Date_to_Days(@date3[0..2]), ($date3[3]*60+$date3[4])*60+$date3[5] );

  @diff = ( $d2[0]-$d3[0], $d2[1]-$d3[1] );

  if ($diff[0] > 0 and $diff[1] < 0) { $diff[0]--; $diff[1] += 86400; }
  if ($diff[0] < 0 and $diff[1] > 0) { $diff[0]++; $diff[1] -= 86400; }

  if (($diff[0] || $diff[1]) >= 0) { print "12時間より長いです\n"; }
  else                             { print "12時間より短いです\n"; }

解答 #2:

この解答は、あなたの与える日付があなたのシステム上の日付の上限と加減の範囲にあることが 保証されている場合にのみ使えます!

     Unix:    1-Jan-1970 00:00:00  to  19-Jan-2038 03:14:07
     MacOS:   1-Jan-1904 00:00:00  to   6-Feb-2040 06:28:15

  use Date::Calc qw( Date_to_Time );

  @date1 = (2002,8,31,23,59,1);
  @date2 = (2002,9,1,11,30,59); # ==> 12時間より短い間隔

  #@date1 = (2002,8,31,22,59,1);
  #@date2 = (2002,9,1,11,30,59); # ==> 12時間よりも長い間隔

  $d1 = Date_to_Time(@date1);
  $d2 = Date_to_Time(@date2);

  if ($d1 <= $d2) { print "2つの日付が時系列順ならば\n"; }
  else            { print "2つの日付が逆順ならば\n"; }

  if ($d1 + 12*60*60 <= $d2) { print "12時間以上\n"; }
  else                       { print "12時間未満\n"; }
4) ある人間が、ある年齢になっているかを証明するにはどうしたらいいでしょうか?
  use Date::Calc qw( Decode_Date_EU Today leap_year Delta_Days );

  $date = <STDIN>; # 誕生日を入力

  ($year1,$month1,$day1) = Decode_Date_EU($date);

  ($year2,$month2,$day2) = Today();

  if (($day1 == 29) && ($month1 == 2) && !leap_year($year2))
      { $day1--; }

  if ( (($year2 - $year1) >  18) ||
     ( (($year2 - $year1) == 18) &&
     (Delta_Days($year2,$month1,$day1, $year2,$month2,$day2) >= 0) ) )
  {
      print "あなたは18歳以上です\n";
  }
  else
  {
      print "あなたはまだ18歳未満です!\n";
  }

  あるいは代わりに(上の最後のif構文の代わりとして)

  if (($year1+18 <=> $year2 || $month1 <=> $month2 || $day1 <=> $day2) <= 0)
      { print "Ok - you are over 18.\n"; }
  else
      { print "Sorry - you aren't 18 yet!\n"; }
5) 現在が、第何週目にあるかを計算するにはどうしたらいいですか?

例:

            1998年4月
    Mon Tue Wed Thu Fri Sat Sun
              1   2   3   4   5  =  第1週
      6   7   8   9  10  11  12  =  第2週
     13  14  15  16  17  18  19  =  第3週
     20  21  22  23  24  25  26  =  第4週
     27  28  29  30              =  第5週

解答:

  use Date::Calc qw( Today Day_of_Week );

  ($year,$month,$day) = Today();

  $week = int(($day + Day_of_Week($year,$month,1) - 2) / 7) + 1;
6) 与えられた日が、該当月の何番目のその曜日なのか計算する方法はどうしたらいいでしょうか?

例:

           2000年10月
    Mon Tue Wed Thu Fri Sat Sun
                              1
      2   3   4   5   6   7   8
      9  10  11  12  13  14  15
     16  17  18  19  20  21  22
     23  24  25  26  27  28  29
     30  31

2000年10月15日の日曜日は、その月の何番目の日曜日でしょうか?

解答:

  use Date::Calc qw( Day_of_Week Delta_Days
                     Nth_Weekday_of_Month_Year
                     Date_to_Text_Long English_Ordinal
                     Day_of_Week_to_Text Month_to_Text );

  ($year,$month,$day) = (2000,10,15);

  $dow = Day_of_Week($year,$month,$day);

  $n = int( Delta_Days(
            Nth_Weekday_of_Month_Year($year,$month,$dow,1),
            $year,$month,$day)
            / 7) + 1;

  printf("%s is the %s %s in %s %d.\n",
      Date_to_Text_Long($year,$month,$day),
      English_Ordinal($n),
      Day_of_Week_to_Text($dow),
      Month_to_Text($month),
      $year);

こうすると、以下のように表示されます。 (訳者注:これは訳さなくても大丈夫ですよね?)

  Sunday, October 15th 2000 is the 3rd Sunday in October 2000.
7) 現在の日付と同じ週にある水曜日の日付を計算するにはどうしたらいいでしょうか?

解答 #1:

  use Date::Calc qw( Today Day_of_Week Add_Delta_Days );

  $searching_dow = 3; # 3 = Wednesday

  @today = Today();

  $current_dow = Day_of_Week(@today);

  @date = Add_Delta_Days(@today, $searching_dow - $current_dow);

解答 #2:

  use Date::Calc qw( Today Add_Delta_Days
                     Monday_of_Week Week_of_Year );

  $searching_dow = 3; # 3 = Wednesday

  @today = Today();

  @date = Add_Delta_Days( Monday_of_Week( Week_of_Year(@today) ),
                          $searching_dow - 1 );

解答 #3:

  use Date::Calc qw( Standard_to_Business Today
                     Business_to_Standard );

  @business = Standard_to_Business(Today());

  $business[2] = 3; # 3 = Wednesday

  @date = Business_to_Standard(@business);
8) ビジネス日付に、週のオフセットを足すにはどうしたらいいですか?(年の境界を越えたりもします)
  use Date::Calc qw( Business_to_Standard Add_Delta_Days
                     Standard_to_Business );

  @temp = Business_to_Standard($year,$week,$dow);

  @temp = Add_Delta_Days(@temp, $week_offset * 7);

  ($year,$week,$dow) = Standard_to_Business(@temp);
9) 与えられた日の前回の土曜日、そして次の土曜日を計算するにはどうしたらいいですか?
  use Date::Calc qw( Today Day_of_Week Add_Delta_Days
                     Day_of_Week_to_Text Date_to_Text );

  $searching_dow = 6; # 6 = Saturday

  @today = Today();

  $current_dow = Day_of_Week(@today);

  if ($searching_dow == $current_dow)
  {
      @prev = Add_Delta_Days(@today,-7);
      @next = Add_Delta_Days(@today,+7);
  }
  else
  {
      if ($searching_dow > $current_dow)
      {
          @next = Add_Delta_Days(@today,
                    $searching_dow - $current_dow);
          @prev = Add_Delta_Days(@next,-7);
      }
      else
      {
          @prev = Add_Delta_Days(@today,
                    $searching_dow - $current_dow);
          @next = Add_Delta_Days(@prev,+7);
      }
  }

  $dow = Day_of_Week_to_Text($searching_dow);

  print "今日は:      ", ' ' x length($dow),
                               Date_to_Text(@today), "\n";
  print "前回の $dow は:     ", Date_to_Text(@prev),  "\n";
  print "次の $dow は: ", Date_to_Text(@next),  "\n";

こうすると、こんな感じで出力されます

  今日は:              Sun 12-Apr-1998
  前回の Saturday は:     Sat 11-Apr-1998
  次の Saturday は: Sat 18-Apr-1998
10) どうやって、月の最後の仕事の日(給料日なんです)を計算したらいいですか?

解答 #1 (祝日は考えていません):

  use Date::Calc qw( Days_in_Month Day_of_Week Add_Delta_Days );

  $day = Days_in_Month($year,$month);
  $dow = Day_of_Week($year,$month,$day);
  if ($dow > 5)
  {
      ($year,$month,$day) =
          Add_Delta_Days($year,$month,$day, 5-$dow);
  }

解答 #2 (祝日を考えています):

この解答は、次のような値を含む多次元配列の"@holiday"を使います。すなわち "$holiday[$year][$month][$day] = 1;"です。

(変化するキリスト教徒の祝日を計算する方法については、ずっと上のほうにある"Easter_Sunday()"関数の説明を見てください)

この配列の祝日でない日の要素は、定義していないか、0のままでなくてはいけません。

  use Date::Calc qw( Days_in_Month Add_Delta_Days Day_of_Week );

  $day = Days_in_Month($year,$month);
  while (1)
  {
      while ($holiday[$year][$month][$day])
      {
          ($year,$month,$day) =
              Add_Delta_Days($year,$month,$day, -1);
      }
      $dow = Day_of_Week($year,$month,$day);
      if ($dow > 5)
      {
          ($year,$month,$day) =
              Add_Delta_Days($year,$month,$day, 5-$dow);
      }
      else { last; }
  }

解答 #3 (祝日を考えた上で、より快適ではありますが、Date::Calendar(3)とDate::Calc::Object(3)を使います)

  use Date::Calc::Object qw( Today Add_Delta_YM Date_to_Text_Long );
  use Date::Calendar::Profiles qw($Profiles);
  use Date::Calendar;

  $calendar = Date::Calendar->new( $Profiles->{'DE-BW'} );

  @today = Today();
  @nextmonth = Add_Delta_YM(@today[0,1],1, 0,1);

  $workaround = $calendar->add_delta_workdays(@nextmonth,+1);
  $payday     = $calendar->add_delta_workdays($workaround,-2);

  print "給料日は = ", Date_to_Text_Long($payday->date()), "\n";

負の数を足した際の"add_delta_workdays()"メソッドのバグのため、 "workaround"は必要です。

11) MicrosoftのVisual Basicの"DATETIME"の値を日付と時間の構成要素に変換するにはどうしたらいいですか?
  use Date::Calc qw( Add_Delta_DHMS Date_to_Text );

  $datetime = "35883.121653";

  ($Dd,$Dh,$Dm,$Ds) = ($datetime =~ /^(\d+)\.(\d\d)(\d\d)(\d\d)$/);

  ($year,$month,$day, $hour,$min,$sec) =
      Add_Delta_DHMS(1900,1,1, 0,0,0, $Dd,$Dh,$Dm,$Ds);

  printf("与えられた日付は %s %02d:%02d:%02d\n",
      Date_to_Text($year,$month,$day), $hour, $min, $sec);

こうすると、以下のように表示します

  与えられた日付は Tue 31-Mar-1998 12:16:53

私は、Visual Basicを持っていないし使いもしないので、ここで仮定した数字列の規格が本当にそうであるか保証できません。 しかしながら、考え方の概要は分かると思います:-)

さらに、以下のことを考慮してください。

Morten Sickel <Morten.Sickel@nrpa.no> さんは以下のように書いています:

私はExcel(2000)にバグを発見しました。Excelは1900年をうるう年と考えています。 正しい日付を得るためには1899年の12月31日をExcelの日付に足す必要があります。

このバグが1900年の2月29日という"工業的標準"で作られたLotus123に由来することをウェブ上で発見しました。 MicrosoftはLotus 123との互換性のためにこのバグを残しました。 しかしながら、そのことはヘルプファイルにはまったく記述されていません。

12) 毎月第1金曜日に開かれる会合の前に、グループのメンバーに日付を忘れないようにメールを送る方法を教えてください。
  use Date::Calc qw( Today Date_to_Days Add_Delta_YMD
                     Nth_Weekday_of_Month_Year );

  ($year,$month,$day) = Today();

  $tomorrow = Date_to_Days($year,$month,$day) + 1;

  $dow = 5; # 5 = Friday
  $n   = 1; # 1 = First of that day of week

  $meeting_this_month = Date_to_Days(
      Nth_Weekday_of_Month_Year($year,$month,$dow,$n) );

  ($year,$month,$day) = Add_Delta_YMD($year,$month,$day, 0,1,0);

  $meeting_next_month = Date_to_Days(
      Nth_Weekday_of_Month_Year($year,$month,$dow,$n) );

  if (($tomorrow == $meeting_this_month) ||
      ($tomorrow == $meeting_next_month))
  {
      #メールを送るのを忘れずに
  }
13) "Date_to_Text()"、"Date_to_Text_Long()"、"Compressed_to_Text()"といった関数で提供されているのと 違う書式で日付を表現するにはどうしたらいいでしょうか?
  use Date::Calc qw( Today Day_of_Week_to_Text
                     Day_of_Week Month_to_Text
                     English_Ordinal );

  ($year,$month,$day) = Today();

例えば、"Fri 03-Jan-1964"のように1桁の日付の前に0をつけるには

  printf("%.3s %02d-%.3s-%d\n",
      Day_of_Week_to_Text(Day_of_Week($year,$month,$day)),
      $day,
      Month_to_Text($month),
      $year);

例えば、"April 12th, 1998"のようなアメリカ風の書式なら

  $string = sprintf("%s %s, %d",
                Month_to_Text($month),
                English_Ordinal($day),
                $year);

例えばISO 8601で使用可能と定められている書式の一つであれば

  @date = ($year,$month,$day,$hour,$min,$sec);
  $date = sprintf("%d-%02d-%02d %02d:%02d:%02d", @date);

( "printf" in perlfunc(1)"sprintf" in perlfunc(1)もまた見てください)

14) ある日付の範囲において、ループを行うにはどうしたらいいですか?
  use Date::Calc qw( Delta_Days Add_Delta_Days );

  @start = (1999,5,27);
  @stop  = (1999,6,1);

  $j = Delta_Days(@start,@stop);

  for ( $i = 0; $i <= $j; $i++ )
  {
      @date = Add_Delta_Days(@start,$i);
      printf("%4d/%02d/%02d\n", @date);
  }

このループには改善点があります。下のレシピを見てください。

15) ある範囲内における、(Perlの)配列を作るにはどうしたらいいでしょうか?
  use Date::Calc qw( Delta_Days Add_Delta_Days Date_to_Text );

  sub date_range
  {
      my(@date) = (@_)[0,1,2];
      my(@list);
      my($i);

      $i = Delta_Days(@_);
      while ($i-- >= 0)
      {
          push( @list, [ @date ] );
          @date = Add_Delta_Days(@date, 1) if ($i >= 0);
      }
      return(@list);
  }

  @range = &date_range(1999,11,3, 1999,12,24); # 時系列順

  foreach $date (@range)
  {
      print Date_to_Text(@{$date}), "\n";
  }

この方法を使わないほうがいいかもしれません。 というのも、日付のすべてにおいて繰り返す処理(すぐ上のレシピで行われています)のほうが、 このような配列を作ってループ処理をするよりも効果的だからです。 配列を作らない方が省スペースです。

16) 土曜や日曜を除いた上で、2つの日付の感覚を計算するにはどうしたらいいでしょうか?
  sub Delta_Business_Days
  {
      my(@date1) = (@_)[0,1,2];
      my(@date2) = (@_)[3,4,5];
      my($minus,$result,$dow1,$dow2,$diff,$temp);

      $minus  = 0;
      $result = Delta_Days(@date1,@date2);
      if ($result != 0)
      {
          if ($result < 0)
          {
              $minus = 1;
              $result = -$result;
              $dow1 = Day_of_Week(@date2);
              $dow2 = Day_of_Week(@date1);
          }
          else
          {
              $dow1 = Day_of_Week(@date1);
              $dow2 = Day_of_Week(@date2);
          }
          $diff = $dow2 - $dow1;
          $temp = $result;
          if ($diff != 0)
          {
              if ($diff < 0)
              {
                  $diff += 7;
              }
              $temp -= $diff;
              $dow1 += $diff;
              if ($dow1 > 6)
              {
                  $result--;
                  if ($dow1 > 7)
                  {
                      $result--;
                  }
              }
          }
          if ($temp != 0)
          {
              $temp /= 7;
              $result -= ($temp << 1);
          }
      }
      if ($minus) { return -$result; }
      else        { return  $result; }
  }

しかしながらこの解答は、おそらく現実にはあまり役に立たないでしょう。 というのも、休日が考えられていないからです。

休日を考慮するにはDate::Calendar(3) を見てください。

参考

Date::Calc::Object(3), Date::Calendar(3), Date::Calendar::Year(3), Date::Calendar::Profiles(3).

  "The Calendar FAQ":
  http://www.tondering.dk/claus/calendar.html
  by Claus Tondering <claus@tondering.dk>

制限事項

現在のこのパッケージの実現方法では、選択された言語がグローバル変数です。

ですから、スレッド式のPerlを使っているのであれば、好ましくないような影響が出るかもしれません。 (あるスレッドにおいて選ばれた言語が、他の全てのスレッドで選択されます)

バージョン

このドキュメントは"Date::Calc"のバージョン5.3のものです

作者

  Steffen Beyer
  mailto:sb@engelschall.com
  http://www.engelschall.com/u/sb/download/

著作権

Copyright (c) 1995 - 2002 by Steffen Beyer. All rights reserved.

ライセンス

このパッケージはフリーソフトであり、Perlそのものと同じように、改変した場合でも再配布可能です。 すなわち、"Artistic License(芸術家的ライセンス)"や"GNU General Public License(GNU一般公的使用許諾)"と同等の扱いです。

このPerlモジュールのコアにあるCのライブラリーはさらに、"GNU Library General Public License"の元で、 改変して再配布可能です。

これに関する詳細については"Artistic.txt"、"GNU_GPL.txt"、"GNU_LGPL.txt"を参照してください。

免責

このパッケージは使いやすいことを望んで配布されていますが、一切の保障をしません。 販売可能性であるとか、一定の目的に適合させるというような保障でさえも暗示しません。

詳細は、"GNU General Public License"を見てください。

翻訳者

澤勇太(Y.Sawa) (succeed@jojo.club.ne.jp)

Japanized Perl Resources Project