# Zend_Date API の概要

`Zend_Date` の API はシンプルで統一性がありますが、 非常に柔軟で強力な設計になっており、 さまざまな操作や演算ができます。

## Zend_Date のオプション

### 日付の書式の型の選択

いくつかのメソッドでは、PHP の `date()` 関数と似た形式の日付書式文字列を使用します。 PHP の日付書式指定子のほうが ISO 書式指定子よりなじみがあるという場合は、 `Zend_Date::setOptions(array('format_type' => 'php'))` とできます。こうすると、`$format` パラメータを持つすべての関数で PHP の日付書式指定子が使用できるようになります。 `Zend_Date::setOptions(array('format_type' => 'iso'))` とすると、デフォルトのモードに戻ります。このモードは、 ISO 日付書式トークンのみをサポートするものです。 サポートする書式コードの一覧は、 を参照ください。

### 夏時間と月

日付を処理する際には、夏時間の適用前後をまたがってしまうこともあります。 通常は、そのような場合は結果が一時間増えたり減ったりします。 たとえば、夏時間の適用前の日付に何ヶ月か追加してその結果が夏時間適用後になった場合、 結果の日付は一時間ずれます。月末や月初の深夜 0 時のような境界上で、 それをまたがった月の加算を行うと、結果から 1 時間引かれることで 前月末日の日付になってしまい "off by 1" エラーが発生します。 このような状況になることを避けるためには、夏時間の変更を無視するためのオプション `fix_dst` を使用します。夏時間/冬時間の境界をまたぐ際に、 通常は 1 時間分足したり引いたりします。 たとえば、春の夏時間適用日をまたがる日付計算の結果は、 時刻部分が 00:00:00 のままの場合は予期したものより 1 日少なくなります。というのも、 `Zend_Date` は日付部分ではなくタイムスタンプに基づいて計算を行うからです。 タイムスタンプが 1 時間少なくなるので、日付も予期したものより 1 日少なくなってしまいます。 これを避けるためにはオプション `fix_dst` を使用します。 このオプションのデフォルトは `TRUE` で、この場合は夏時間が "月" の計算 (`addMonth()`、 `subMonth()`) に影響を与えなくなります。 `Zend_Date::setOptions(array('fix_dst' => false))` とすると、 夏時間にあわせた時間の加減算を "月" の計算時にも適用します。

`Zend_Date` インスタンスの実際のタイムゾーンが UTC あるいは GMT の場合、 オプション `'fix_dst'` は用いられません。 これらのタイムゾーンには DST は適用されないからです。 このインスタンスのタイムゾーンを UTC あるいは GMT 以外のものに変更すると、 その前に設定されていた 'fix_dst' オプションの値を "月" の計算時に適用します。

### 月の計算

ある日付に対して月を足したり引いたりすると、 もとの日付が月の最後のほうだった場合に予期せぬ結果となることがあります。 たとえば「1月31日」に一ヶ月足すことを考えてみましょう。 SQL に慣れている人なら、この結果は「2月28日」になるものと思われるでしょう。 一方、Excel や OpenOffice を使っている人は、この結果が「3月3日」 になるものと考えるのではないでしょうか。 この問題は、計算結果の月の日数が元の日付の月の日数より少ない場合に起こりえます。 Zend Framework の開発者向けには、どちらの方式かを選択できるようにしました。 `extend_month` オプションを `FALSE` にすると SQL 風の挙動になり、`TRUE` にすると表計算ソフト風の挙動になります。 `extend_month` のデフォルトは `FALSE` なので、 `Zend_Date` は SQL 互換の計算をします。 デフォルトでは、`Zend_Date` は月の計算をする際に (必要に応じて) 日を切り詰めます。計算した結果に該当する日がその月に存在しなかった場合に、 翌月にまたがることはありません。 `Zend_Date::setOptions(array('extend_month' => true))` とすると、表計算ソフトと同様の方式で計算することになります。

### 日付の地域化や正規化の、Zend_Cache による高速化

`Zend_Date` を高速に動作させるには `Zend_Cache` アダプタを使用します。これを使用すると、地域化したデータを扱う際の `Zend_Date` のすべてのメソッドが高速化します。 たとえば、定数 `Zend_Date::DATE` や `Zend_Date::TIME` を扱うメソッドは、すべてこの影響を受けます。 `Zend_Cache` アダプタを `Zend_Date` に設定するには、 `Zend_Date::setOptions(array('cache' => $adapter))` とするだけです。

### Zend_TimeSync による同期したタイムスタンプの取得

通常は、サーバやコンピュータの時刻はそれぞれ異なります。 `Zend_Date` は、この問題を `Zend_TimeSync` で解決できます。 タイムサーバを `Zend_Date::setOptions(array('timesync' => $timeserver))` で設定すると、すべての `Zend_Date` インスタンスについて、 そのタイムスタンプと実際のタイムスタンプを間のオフセットを設定します。 このオプションを使用しても、既存のインスタンスのタイムスタンプは変わりません。 そこで、これを用いる場合は起動ファイルで設定することをおすすめします。

## 日付の値の操作

`Zend_Date` オブジェクトの作成によって入力が正規化されると、 このオブジェクトはタイムゾーンに関連付けられます。しかし、内部的な形式としては通常の UNIX タイムスタンプを使用します。 各地域固有の方式で日付を表示するには、まずタイムゾーンを知る必要があります。 デフォルトのタイムゾーンは常に GMT/UTC です。オブジェクトのタイムゾーンを調べるには `getTimeZone()` を使用します。オブジェクトのタイムゾーンを変更するには `setTimeZone()` を使用します。 これらのオブジェクトに対するすべての操作は、このタイムゾーンを想定して行われます。

異なるタイムゾーンの日付オブジェクトを混在させないよう注意しましょう。 タイムスタンプにのみかかわる操作しかしないのならよいのですが、 それ以外の場合には期待通りの結果が得られなくなるでしょう。 異なるタイムゾーンの `Zend_Date` に対する操作は、 たいていの場合はうまく動作します。というのも `Zend_Date` のインスタンスを作成する際に、値が UNIX タイムスタンプに正規化されるからです。

ほとんどのメソッドで、引数 `$part` に定数を指定できます。 これにより、日付のどの部分を選択するかを指定します。この定数は、 たとえば `Zend_Date::HOUR` のようになります。 これらの定数は、以下のすべての関数で使用できます。使用可能なすべての定数の一覧は にあります。 `$part` を省略した場合は、`Zend_Date::TIMESTAMP` が指定されたものとみなします。また、ユーザ定義の書式を `$part` で使用することもできます。ここには、 `Zend_Locale_Format::getDate()` と同様のコードを使用します。 日付オブジェクトが明らかに無効な値を用いて作成された場合 (たとえば月が 12 より大きいなど) は、 `Zend_Date` は例外をスローします。ただし、特定の日付フォーマットが指定されている場合、 つまり `$part` が `NULL` あるいは `Zend_Date::DATES` ("あいまいな" フォーマット) のいずれかである場合は別です。

### ユーザ定義の入力日付書式

    $date1 = new Zend_Date('Feb 31, 2007', null, 'en_US');
    echo $date1, "\n"; // 出力は "Mar 3, 2007 12:00:00 AM" となります

    $date2 = new Zend_Date('Feb 31, 2007', Zend_Date::DATES, 'en_US');
    echo $date2, "\n"; // 出力は "Mar 3, 2007 12:00:00 AM" となります

    // 指定したフォーマットで解釈するように強制します
    $date3 = new Zend_Date('Feb 31, 2007', 'MM.dd.yyyy');
    echo $date3, "\n"; // 出力は "Mar 3, 2007 12:00:00 AM" となります

オプションのパラメータ `$locale` を指定すると、 その `$locale` をもとに `$date` オペランドを解決します。 つまり、日付文字列に含まれる月名や曜日名などを、そのロケールにあわせて適切に解釈します (`Zend_Locale_Format::getDate()` を参照ください)。 各地域固有の形式の文字列で `$date` オペランドが指定された際に 自動で正規化が行われるのは、`$part` が 定数 `Zend_Date::DATE*` あるいは `Zend_Date::TIME*` のいずれかであるときです。 `$date` が日付を含む文字列の場合は、 月名や曜日名をパースする際に使用する言語はロケールをもとに決定します。 入力パラメータ `$date` が指定されなかった場合は、 `$locale` パラメータの内容をもとにして地域化した結果 (日付書式を文字列で表したもの) を出力します。 入力パラメータ `$date` に具体的な型が指定されている場合もあります (たとえば `addHour()` では `$hour` です)。 このような場合でも、引数として `Zend_Date` オブジェクトを使用できることに注意しましょう。 `$locale` を指定しなかった場合は、 現在のオブジェクトのロケールを使用して `$date` を解釈します。あるいは出力用書式を選択します。

Zend Framework 1.7.0 以降では、`Zend_Date` はアプリケーション単位でのロケールの使用にも対応します。 そのためには、`Zend_Locale` のインスタンスを以下のようにレジストリに登録します。 このようにすれば、同じロケールを何度も使用したいときに 各インスタンスで毎回ロケールを設定する手間を省けます。

    // 起動ファイルで
    $locale = new Zend_Locale('de_AT');
    Zend_Registry::set('Zend_Locale', $locale);

    // アプリケーションのどこかで
    $date = new Zend_Date('31.Feb.2007');

## 多くの日付要素で共通に使用できる、Zend_Date の基本操作

メソッド `add()`, `sub()`, `compare()`, `get()` および `set()` は、日付全般に対して使用できます。それぞれのメソッドは、 そのインスタンスが保持する日付の値を操作します。 これらのメソッドのうち、`get()` 以外ではすべて `$date` オペランドが必要となります。 ここには `Zend_Date` のインスタンスか 数値文字列、あるいは整数値を指定します。 これらのメソッドで `$date` にオブジェクト以外を指定した場合、 それはタイムスタンプであるとみなされます。 しかし、`$part` オペランドを使用すると、 ふたつの日付データが日付のどの部分を表すものなのかを指定できます。 たとえば "年"、"分" などが指定できます。それだけではなく、 "December 31, 2007 23:59:59" のような長い形式の文字列も `$date` に指定できます。 `compare()` および `get()` 以外のメソッドは、処理の結果としてオブジェクト内の日付が変更されます。

### 日付要素の操作

    $date = new Zend_Date(); // $date のタイムスタンプは time() の返す値と等しくなります

    // $date に 12 時間足します
    $date->add('12', Zend_Date::HOUR);
    print $date;

基本的な操作について、一般的な日付要素と組み合わせて使用する際に 便利なメソッドが用意されています。 これらのメソッドを使用すると、上で説明したメソッドのように 日付要素の定数 をいちいちタイプする必要がなくなります。 好都合なことに、これらのメソッドの名前は プレフィックス (基本操作の名前) とサフィックス (日付要素の名前) を組み合わせた形式、たとえば `addYear()` のようになっています。以下の一覧における、すべての "日付要素" と "基本操作" の組み合わせが存在します。 たとえば "add" は、各要素について `addDay()` や `addYear()` などといったメソッドが存在します。

これらの便利なメソッドの機能は、基本操作メソッドと同等です。 しかし、`$date` オペランドに文字列や整数値を使用する場合は、 メソッド名のサフィックスが指す日付要素以外を指定することはできません。 つまり、`$date` が文字列あるいは整数値の場合は、 `$date` オペランドの単位が メソッド名によって ("Year" や "Minute" などに) 決まるということです。

### 日付要素の一覧

#### 日付要素

日付要素 | 説明
--- | ---
Timestamp (タイムスタンプ) | UNIX タイムスタンプ。January 1st, 1970 00:00:00 GMT/UTC からの経過秒数です。
Year (年) | グレゴリオ暦の年 (例: 2006)。
Month (月) | グレゴリオ暦の月 (1-12、各地域固有の名前もサポートしています)。
24 hour clock (24 時間の時間) | その日の時間 (0-23)。これは、その日がはじまってからの経過時間数を表します。
minute (分) | 時間内の分 (0-59)。これは、その時間がはじまってからの経過分数を表します。
Second (秒) | 分内の秒 (0-59)。これは、その分が始まってからの経過秒数を表します。
millisecond (ミリ秒) | ミリ秒 (0-999)。これは、千分の一秒を表します。 `Zend_Date` では、秒未満の単位を扱うために 二つのメソッドを用意しています。デフォルトでは、 `Zend_Date` のインスタンスはミリ秒単位の精度を使用します。 これは `getFractionalPrecision()` を使用して取得します。 精度を変更するには `setFractionalPrecision($precision)` を使用します。しかし、精度は事実上ミリ秒までに制限されます。 というのも、`Zend_Date` は `microtime()` を使用しているからです。
Day (日) | `Zend_Date::DAY_SHORT` は `$date` から抽出します。これは、`$date` オペランドが `Zend_Date` のインスタンスであるか、 あるいは数値文字列である場合に行われます。 それ以外の場合は、以下の定数によって指定した規約に基づいて抽出します。 `Zend_Date::WEEKDAY_NARROW`、`Zend_Date::WEEKDAY_NAME`、 `Zend_Date::WEEKDAY_SHORT`、 `Zend_Date::WEEKDAY` (グレゴリオ暦とみなして処理します)。
Week (週) | `Zend_Date::WEEK` は `$date` から抽出します。これは、`$date` オペランドが `Zend_Date` のインスタンスであるか、 あるいは数値文字列である場合に行われます。 それ以外の場合は例外が発生します (グレゴリオ暦とみなして処理します)。
Date (日) | `Zend_Date::DAY_MEDIUM` は `$date` から抽出します。これは、`$date` オペランドが `Zend_Date` のインスタンスである場合に行われます。 それ以外の場合は、文字列 `$date` を正規化して Zend_Date::DATE_MEDIUM 形式の日付にしようとします。 `Zend_Date::DAY_MEDIUM` の書式は、 そのオブジェクトのロケールに依存します。
Weekday (曜日) | 曜日は、0 (日曜日) から 6 (土曜日) までの数字で表されます。 `Zend_Date::WEEKDAY_DIGIT` は `$date` から抽出します。これは、`$date` オペランドが `Zend_Date` のインスタンスであるか、 あるいは数値文字列である場合に行われます。 それ以外の場合は、以下の定数によって指定した規約に基づいて抽出します。 `Zend_Date::WEEKDAY_NARROW`、`Zend_Date::WEEKDAY_NAME`、 `Zend_Date::WEEKDAY_SHORT`、 `Zend_Date::WEEKDAY` (グレゴリオ暦とみなして処理します)。
DayOfYear (年内の日数) | `Zend_Date` では、これは年初からの経過日数 (0-365) を表します。これまでの他の単位と同様、 端数は切り捨てられます (グレゴリオ暦とみなして処理します)。
Arpa | Arpa 日付 (つまり RFC 822 形式の日付) をサポートしています。 出力形式は、"GMT" あるいは "地方時 + 時差" 形式になります (RFC 822 の section 5 を参照ください)。 PHP 5.2.2 より前のバージョンでは、定数 DATE_RFC822 を PHP の日付関数で使用したときに おかしな結果 となる場合がありました。`Zend_Date` は、正しい結果を返します。 例: `Mon, 31 Dec 06 23:59:59 GMT`
Iso | 出力形式として、完全な ISO 8601 日付のみをサポートしています。 例: `2009-02-14T00:31:30+01:00`

### 日付操作の一覧

便利なメソッド群ではなく以下の基本操作を使用する場合には、 適切な定数 を `$part` パラメータで指定します。

#### 基本操作

基本操作 | 説明
--- | ---
`get()` | get($part = null, $locale = null) `get($part)` を使用して、このオブジェクトの日付の `$part` の部分を取得します。 結果は、`$locale` にもとづいて地域化された書式の文字列か整数値となります。 BCMath 拡張モジュールを使用している場合は、 大きな値の場合に整数ではなく数値文字列が返されるかもしれません。 注意: `get()` とは異なり、その他の get*() 系のメソッドは `Zend_Date` のインスタンスのみを返します。 その中身は、選択された時刻/日付となります。
`set()` | set($date, $part = null, $locale = null) ロケール `$locale` の入力データ `$date` から、 `$part` に対応する部分の値を 現在のオブジェクトに設定します。
`add()` | add($date, $part = null, $locale = null) ロケール `$locale` の入力データ `$date` から、 `$part` に対応する部分の値を 現在のオブジェクトに加えます。
`sub()` | sub($date, $part = null, $locale = null) ロケール `$locale` の入力データ `$date` から、 `$part` に対応する部分の値を 現在のオブジェクトから引きます。
`copyPart()` | copyPart($part, $locale = null) オブジェクトの複製を返します。もとのオブジェクトの日付のうち `$part` の部分のみがコピーされます。 複製のロケールは、`$locale` で任意のものに指定できます。
`compare()` | compare($date, $part = null, $locale = null) `$date` の `$part` 部分を このオブジェクトのタイムスタンプと比較します。等しい場合は 0、 このオブジェクトの値のほうが $date の内容より新しい場合に 1、 それ以外の場合に -1 を返します。

## 日付の比較

以下の基本操作については、 の一覧にある各日付要素に特化した便利なメソッドは存在しません。

### 日付の比較用メソッド

メソッド | 説明
--- | ---
`equals()` | equals($date, $part = null, $locale = null) ロケール `$locale` で格納されている日付 `$date` の要素 `$part` がこのオブジェクトの日付要素と等しい場合に `TRUE`、 それ以外の場合に `FALSE` を返します。
`isEarlier()` | isEarlier($date, $part = null, $locale = null) このオブジェクトの日付要素 `$part` が、 ロケール `$locale` で格納されている日付 `$date` の要素 `$part` より前である場合に `TRUE` を返します。
`isLater()` | isLater($date, $part = null, $locale = null) このオブジェクトの日付要素 `$part` が、 ロケール `$locale` で格納されている日付 `$date` の要素 `$part` より後である場合に `TRUE` を返します。
`isToday()` | isToday() 今日の年月日が、このオブジェクトの日付と一致するかどうかを調べます (このオブジェクトのタイムゾーンを用いて判断します)。
`isTomorrow()` | isTomorrow() 明日の年月日が、このオブジェクトの日付と一致するかどうかを調べます (このオブジェクトのタイムゾーンを用いて判断します)。
`isYesterday()` | isYesterday() 昨日の年月日が、このオブジェクトの日付と一致するかどうかを調べます (このオブジェクトのタイムゾーンを用いて判断します)。
`isLeapYear()` | isLeapYear() `isLeapYear()` を使用して、 そのオブジェクトが閏年であるかどうかを調べます。あるいは `Zend_Date::checkLeapYear($year)` を使用すると、 `$year` (文字列、整数値 あるいは `Zend_Date` のインスタンス) が閏年かどうかを知ることができます。
`isDate()` | isDate($date, $format = null, $locale = null) このメソッドは、指定した日付が本当に日付であるかどうかを調べ、 すべてのチェックを通過したときに `TRUE` を返します。 PHP の checkdate() 関数と似たような働きですが、各地域固有の月名にも対応しており、 また checkdate() の対象範囲外の日付でも正しく判定できます。

## 日付および日付要素の取得

`Zend_Date` インスタンスに関する情報の取得をサポートするメソッド群について説明します。

### 日付出力用のメソッド

メソッド | 説明
--- | ---
`toString()` | toString($format = null, $locale = null) 直接実行することもできますし、マジックメソッド `__toString()` から間接的にコールされることもあります。 `toString()` メソッドは、自動的にオブジェクトの値の書式を設定します。 この書式は、オブジェクトのロケールか、あるいはオプションで指定した `$locale` にもとづいて決まります。 サポートする書式コードの一覧は、 を参照ください。

`toArray()`

toArray()

選択した日付を、そのオブジェクトのロケールにもとづいて配列形式で返します。 返される配列は PHP の getdate() 関数が返すものと同じ形式で、次のような要素を含みます。

- 日を表す 'day' (`Zend_Date::DAY_SHORT`)

- 月を表す 'month' (`Zend_Date::MONTH_SHORT`)

- 年を表す 'year' (`Zend_Date::YEAR`)

- 時間を表す 'hour' (`Zend_Date::HOUR_SHORT`)

- 分を表す 'minute' (`Zend_Date::MINUTE_SHORT`)

- 秒を表す 'second' (`Zend_Date::SECOND_SHORT`)

- タイムゾーンの略称を表す 'timezone' (`Zend_Date::TIMEZONE`)

- Unix タイムスタンプを表す 'timestamp' (`Zend_Date::TIMESTAMP`)

- 曜日番号を表す 'weekday' (`Zend_Date::WEEKDAY_DIGIT`)

- 年初からの日数を表す 'dayofyear' (`Zend_Date::DAY_OF_YEAR`)

- 週を表す 'week' (`Zend_Date::WEEK`)

- GMT からの時差を表す 'gmtsecs' (`Zend_Date::GMT_SECS`)

`toValue()` | toValue($part = null) 指定した日付要素 `$part` の、 そのオブジェクトのロケールにもとづいた整数表現を返します。 `$part` で `Zend_Date::MONTH_NAME_SHORT` のような非数値要素を選択した場合は、 `FALSE` を返します。 注意: このメソッドは `get()` をコールし、結果を PHP の integer 型にキャストします。つまり、 `get()` の返す結果が非常に大きな数値を表す数値表現となり、 それが PHP の integer 型の制限をこえた場合には予期せぬ結果となります。 そのような場合は、かわりに `get()` を使用します。
get() | get($part = null, $locale = null) このメソッドは、オブジェクトの日付要素 `$part` をロケール `$locale` に変換したものを、 文字列あるいは整数値で返します。 詳細な情報は を参照ください。
`now()` | now($locale = null) この関数は、`new Zend_Date()` と同等です。 これは、現在の日付を表す `Zend_Date` オブジェクトに、ロケール `$locale` を指定して返します。

## 一秒未満の単位の扱い

`Zend_Date` インスタンスに関する情報の取得をサポートするメソッド群について説明します。

### 日付の出力用メソッド

メソッド | 説明
--- | ---
`getFractionalPrecision()` | 一秒未満の値の精度を返します。
`setFractionalPrecision()` | 一秒未満の値の精度を設定します。

## 日の出 / 日の入り

これらの三つのメソッドにより、各地域に特化した太陽の情報を取得できます。 たとえば日の出や日の入りの時刻などが得られます。

### 雑多なメソッド

メソッド | 説明
--- | ---
`getSunrise($location)` | 日の出時刻を返します。
`getSunset($location)` | 日の入り時刻を返します。
`getSunInfo($location)` | 日の出/日の入り情報を含む配列を返します。