代码之家  ›  专栏  ›  技术社区  ›  berkes

解析并创建iso8601日期和时间间隔,如PHP中的PT15M

  •  26
  • berkes  · 技术社区  · 14 年前

    我正在使用的一个库和web服务在时间间隔内进行通信 ISO 8601 format: PnYnMnDTnHnMnS . 我想把这些格式转换成秒。反之亦然。用秒来计算要容易得多。

    • PT1M或PT60S(1分钟)
    • PT1H、PT60M或PT3600S(1小时)

    iso8601_interval_to_seconds() 从几秒钟到几秒钟: iso8601_interval_from_seconds()

    后者相当简单,因为它可以作为“PT{$seconds}S”来完成,只需始终传递秒数。如果解析器切换到H(小时)或M(分钟),也许这可以做得更好?

    第一种方法比较难,但是在PHP中使用一个字符串到日期转换器可能有什么诀窍?我很想学习如何使用这样的函数来解析区间。或者学习另一种选择。

    5 回复  |  直到 6 年前
        1
  •  18
  •   Fanis Hatzidakis    14 年前

    它看起来像PHP5.3 DateInterval 支持这一点。

        2
  •  8
  •   user1441149 user1441149    12 年前

    strotime不能直接使用iso8601格式(例如P1Y1DT1S), 但它所理解的格式(1年1天1秒)并不太简单 远远的——这将是一个相当直接的转变。(一点点

    谢谢李,我不知道strotime接受这种格式。这是我拼图中缺失的部分。也许我的功能可以完成你的回答。

    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;
        }
    }
    

    该函数还支持负数格式。 -10年9月7日 如果不需要此行为,则传递false作为第二个参数。这样函数将始终返回正值。 在结果键['symbol']中,min/plus符号仍然可用。

    还有一点更新: 此函数使用第一个函数获取总秒数。

    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
    
        3
  •  7
  •   Lee    14 年前

    请注意,在不知道实际开始日期/时间的情况下,无法准确地将包含天、月和/或年的持续时间转换为秒等持续时间。

    例如

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

    所有这些--当然,您可以压缩包含 将小时、分钟和秒转换为只包含秒的值。我建议您构建一个简单的解析器来完成这项工作(或者考虑一个正则表达式)。

    如果必须使用低于v5.3.0的版本,可以尝试围绕这个小宝石构建一些东西:

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

    strtotime 不能直接使用ISO8601格式(例如。 P1Y1DT1S 明白吗( 1Year1Day1Second )不会太远--这将是一个相当直接的转换。(有点“黑”。。。但这是PHP为您准备的)。

    祝你好运!

        4
  •  1
  •   Mantas D    7 年前
    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
    
        5
  •  0
  •   Todd Moses    14 年前

    您要找的是DateTime::diff

    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