28

私が使用しているライブラリとWebサービスは、ISO8601形式PnYnMnDTnHnMnSで時間間隔を通信します。そのようなフォーマットを秒に変換したいと思います。およびその逆。秒は計算がはるかに簡単です。

間隔値の例は次のとおりです。

  • PT1MまたはPT60S(1分)
  • PT1H、PT60MまたはPT3600S(1時間)

私は2つの関数が必要です:そのような値から秒への解析:iso8601_interval_to_seconds()そして秒からそのような間隔へ:iso8601_interval_from_seconds()

後者は、 `" PT {$ seconds} S "として実行できるため、かなり単純です。常に秒を渡すだけです。たぶん、これはH(時間)またはM(分)に切り替わるパーサーでよりうまく行うことができますか?

最初の方法は難しいですが、PHPにある多くの文字列から日付へのコンバーターの1つにトリックがあるのではないでしょうか。このような関数を使用して間隔を解析する方法を学びたいと思います。または別の方法を学びます。

4

5 に答える 5

18

PHP5.3のDateIntervalがこれをサポートしているようです。

5.3を使用できない場合、そのような変換関数は、1年、1か月、1日、1時間、1分の秒数を知っていると思います。次に、秒から変換する場合、残りが60秒未満になるまで、前の操作のモジュロを取るたびに、この順序で除算されます。ISO 8601間隔表現から変換する場合、文字列を解析し、それに応じて見つかった各要素を乗算するのは簡単です。

于 2010-09-15T19:42:44.580 に答える
8

strtotimeはISO8601形式(P1Y1DT1Sなど)では直接機能しませんが、理解できる形式(1Year1Day1Second)はそれほど遠くありません-かなり簡単な変換になります。(少し「ハッキー」です...しかし、それはあなたのためのPHPです)。

リーに感謝します、私はstrtotimeがこのフォーマットを受け入れたことに気づいていませんでした。これは私のパズルの欠けている部分でした。おそらく私の関数はあなたの答えを完成させることができます。

function parse_duration($iso_duration, $allow_negative = true){
    // Parse duration parts
    $matches = array();
    preg_match('/^(-|)?P([0-9]+Y|)?([0-9]+M|)?([0-9]+D|)?T?([0-9]+H|)?([0-9]+M|)?([0-9]+S|)?$/', $iso_duration, $matches);
    if(!empty($matches)){       
        // Strip all but digits and -
        foreach($matches as &$match){
            $match = preg_replace('/((?!([0-9]|-)).)*/', '', $match);
        }   
        // Fetch min/plus symbol
        $result['symbol'] = ($matches[1] == '-') ? $matches[1] : '+'; // May be needed for actions outside this function.
        // Fetch duration parts
        $m = ($allow_negative) ? $matches[1] : '';
        $result['year']   = intval($m.$matches[2]);
        $result['month']  = intval($m.$matches[3]);
        $result['day']    = intval($m.$matches[4]);
        $result['hour']   = intval($m.$matches[5]);
        $result['minute'] = intval($m.$matches[6]);
        $result['second'] = intval($m.$matches[7]);     
        return $result; 
    }
    else{
        return false;
    }
}

この関数はネガティブフォーマットもサポートしています。 -P10Y9MT7M5Sは、次のような配列を返します。 [年] =>-10[月]=>-9[日]=>0[時間]=>0[分]=>-7[秒]=>-5この場合動作は望ましくありません。2番目のパラメーターとしてfalseを渡します。このようにして、関数は常に正の値を返します。最小/プラス記号は、結果キー['symbol']で引き続き使用できます。

そして少し更新:この関数は最初の関数を使用して合計秒数を取得します。

function get_duration_seconds($iso_duration){
    // Get duration parts
    $duration = parse_duration($iso_duration, false);
    if($duration){
        extract($duration);
        $dparam  = $symbol; // plus/min symbol
        $dparam .= (!empty($year)) ? $year . 'Year' : '';
        $dparam .= (!empty($month)) ? $month . 'Month' : '';
        $dparam .= (!empty($day)) ? $day . 'Day' : '';
        $dparam .= (!empty($hour)) ? $hour . 'Hour' : '';
        $dparam .= (!empty($minute)) ? $minute . 'Minute' : '';
        $dparam .= (!empty($second)) ? $second . 'Second' : '';
        $date = '19700101UTC';
        return strtotime($date.$dparam) - strtotime($date);
    }
    else{
        // Not a valid iso duration
        return false;
    }
}

$foo = '-P1DT1S';
echo get_duration_seconds($foo); // Output -86399
$bar = 'P1DT1S';
echo get_duration_seconds($bar); // Output 86401
于 2012-12-14T20:25:41.930 に答える
7

日、月、および/または年を含む期間を秒などの期間に変換することは、実際の開始日時を知らずに正確に行うことはできないことに注意してください。

例えば

1 SEP 2010:  +P1M2D means +2764800 seconds
1 OCT 2010:  +P1M2D means +2851200 seconds

これは、9月が30日、10月が31日であるためです。うるう年とうるう秒が原因で、年間隔の変換でも同じ問題が発生します。うるう年は、月の変換にもさらに複雑さをもたらします。2月はうるう年がそうでない場合よりも1日長いためです。夏時間が実施されている地域では、日数に問題があります。DST移行中に発生する1日の期間は、実際にはそうでない場合よりも1時間長くなります。

言われていることすべて-もちろん、時、分、秒のみを含む値を秒のみを含む値に圧縮することができます。仕事をするための単純なパーサーを作成することをお勧めします(または正規表現を検討することもできます)。

上で概説した落とし穴に注意してください-ドラゴンがいます。日、月、および/または年を処理する場合は、組み込みのメカニズムの1つを使用して、既知の日付/時刻のコンテキストで計算を行う必要があります。他の人が述べているように、DateIntervalクラスは、DateTimeクラスで提供される関数と組み合わせて、おそらくこれを処理するための最も直感的な方法です。ただし、これはPHPバージョン5.3.0以降でのみ使用できます。

v5.3.0未満で作業する必要がある場合は、この小さな宝石の周りに何かを構築してみることができます。

$startDateTime = '19700101UTC';
$duration = strtotime( $startDateTime.'+1Year1Day1Second' ) - strtotime($startDateTime);
print("Duration in Seconds:  $duration");

strtotimeISO 8601形式で直接動作することはありませんが(たとえばP1Y1DT1S)、それ理解する形式(1Year1Day1Second)はそれほど遠くありません-かなり簡単な変換になります。(少し「ハッキー」です...しかし、それはあなたのためのPHPです)。

幸運を!

于 2010-09-15T21:12:21.803 に答える
1
function parsePTTime($pt_time)
{
    $string = str_replace('PT', '', $pt_time);
    $string = str_replace('H', 'Hour', $string);
    $string = str_replace('M', 'Minute', $string);
    $string = str_replace('S', 'Second', $string);

    $startDateTime = '19700101UTC';
    $seconds = strtotime($startDateTime . '+' . $string) - strtotime($startDateTime);

    return $seconds;
}

テスト:

PT1H         - OK
PT23M        - OK
PT45S        - OK
PT1H23M      - OK
PT1H45S      - OK
PT23M45S     - OK
PT1H23M45S   - OK
于 2017-05-12T07:47:41.833 に答える
0

あなたが探しているのはDateTime::diffです

以下に示すように、2つの日付の違いを表すDateIntervalオブジェクト、または失敗した場合はFALSE。

$datetime1 = new DateTime('2009-10-11');
$datetime2 = new DateTime('2009-10-13');
$interval = $datetime1->diff($datetime2);
echo $interval->format('%R%d days');

日付の代わりに秒を使用してください。

これはhttp://www.php.net/manual/en/datetime.diff.phpからです

DateIntervalのリファレンスについては、http: //www.php.net/manual/en/class.dateinterval.phpを参照してください。

于 2010-09-15T19:53:17.067 に答える