Intereting Posts
Поиск многомерного массива с использованием регулярных выражений в PHP и возвращаемых ключах Как изменить папку Pear / PECL по умолчанию из / var / tmp? Мне нужна моя страница PHP, чтобы показать мой образ BLOB из базы данных mysql Как обращаться с выходом пользователя в браузере с несколькими вкладками? PHP bindParam, похоже, не работает с параметром PARAM_INT out Пробелы, разрывы строк, вкладки; они влияют на производительность сервера? PHP: лучший способ разделить строку на алфавитные и числовые компоненты PHP – получить все ключи из массива, которые начинаются с определенной строки Как контролировать активность пользователя на моем веб-сайте? Настроить .htaccess для работы с PHP Framework (Silex) Условный запрос в elasticsearch Рекурсивно цикл через многомерный для создания плоского массива Безопасное FTP-соединение с использованием PHP Простое изменение цвета Обрезаемая фатальная ошибка: объект класса __PHP_Incomplete_Class

Разбор и создание ISO 8601. Временные интервалы даты и времени, такие как PT15M в PHP

Библиотеку и веб-сервис, которые я использую, обмениваются временными интервалами в ISO 8601: PnYnMnDTnHnMnS. Я хочу преобразовать такие форматы в несколько секунд. И наоборот. Секунды намного легче рассчитать.

Пример значений интервала:

  • PT1M или PT60S (1 минута)
  • PT1H, PT60M или PT3600S (1 час)

Мне нужны две функции: проанализировать от таких значений до секунд: iso8601_interval_to_seconds() и от секунд до таких интервалов: iso8601_interval_from_seconds() .

Последнее довольно просто, потому что это можно сделать как «PT {$ seconds} S», просто пропустите секунды вдоль, всегда. Может быть, это можно сделать лучше с парсером, который переключается на H (час) или M (минута)?

Первый сложнее, но, может быть, есть трюк с одним из многих современных преобразователей в PHP? Мне бы хотелось узнать, как использовать такую ​​функцию для парсинга. Или изучите альтернативу.

Похоже, что DateInterval PHP 5.3 поддерживает это.

Если вы не можете использовать 5.3, я полагаю, что любая такая функция преобразования будет знать, сколько секунд занимает год, месяц, день, час и минута. Затем, при переходе от секунд, он будет делиться в этом порядке, каждый раз принимая по модулю предыдущей операции, пока осталось только <60 секунд. При преобразовании из представления интервала ISO 8601 должно быть тривиально анализировать строку и умножать каждый найденный элемент соответственно.

Имейте в виду, что длительность преобразования, которая содержит Дни, Месяцы и / или годы, в длительность, как секунды, не может быть выполнена точно, не зная фактической начальной даты / времени.

Например

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

Это потому, что сентябрь имеет 30 дней, а октябрь – 31 день. Такая же проблема возникает при преобразовании интервалов Year из-за високосных лет и прыжков секунд. Високосные годы еще больше усложняют конверсию Месяца – с февраля на один день дольше в високосный год, чем в противном случае. Дни являются проблематичными в тех областях, где практикуется летнее время – однодневный период, происходящий во время перехода на летнее время, на самом деле на 1 час больше, чем в противном случае.

Все сказанное – вы можете, конечно, сжать значения, содержащие только часы, минуты и секунды, в значения, содержащие только секунды. Я предлагаю вам создать простой парсер для выполнения задания (или, возможно, рассмотреть регулярное выражение).

Просто знай о подводных камнях, изложенных выше – там будут драконы. Если вы намерены иметь дело с днями, месяцами и / или годами, вам нужно использовать один из встроенных механизмов для выполнения математики для вас в контексте известной даты / времени. Как отмечали другие: класс DateInterval, в сочетании с функциями, предоставляемыми в классе DateTime, вероятно, является наиболее интуитивным способом справиться с этим. Но это доступно только в PHP версии 5.3.0 или выше.

Если вам нужно работать с меньшим, чем v5.3.0, вы можете попытаться создать что-то вокруг этой маленькой жемчужины:

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

strtotime не будет работать с форматом ISO 8601 напрямую (например, P1Y1DT1S ), но формат, который он понимает ( 1Year1Day1Second ), не слишком далеко – это будет довольно прямое преобразование. (немного «взломанный» … но это PHP для вас).

удачи!

strtotime не будет работать с форматом ISO 8601 напрямую (например, 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 Если это поведение нежелательно, передать false как второй параметр. Таким образом, функция всегда будет возвращать положительные значения. Символ min / plus по-прежнему будет доступен в ключе результата ['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 

То, что вы ищете, – 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

 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