From 3019e5cfdd49426e96eb5a37c9217d4bc16584f6 Mon Sep 17 00:00:00 2001 From: Olav Morken <olav.morken@uninett.no> Date: Mon, 8 Sep 2008 13:30:20 +0000 Subject: [PATCH] Utilities: Add code to parse a duration. git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@860 44740490-163a-0410-bde0-09ae8108e29a --- lib/SimpleSAML/Utilities.php | 83 ++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/lib/SimpleSAML/Utilities.php b/lib/SimpleSAML/Utilities.php index daf57e59f..033f0f691 100644 --- a/lib/SimpleSAML/Utilities.php +++ b/lib/SimpleSAML/Utilities.php @@ -392,6 +392,89 @@ class SimpleSAML_Utilities { } + /** + * Interpret a ISO8601 duration value relative to a given timestamp. + * + * @param string $duration The duration, as a string. + * @param int $timestamp The unix timestamp we should apply the duration to. Optional, default + * to the current time. + * @return int The new timestamp, after the duration is applied. + */ + public static function parseDuration($duration, $timestamp = NULL) { + assert('is_string($duration)'); + assert('is_null($timestamp) || is_int($timestamp)'); + + /* Parse the duration. We use a very strict pattern. */ + $durationRegEx = '#^(-?)P(?:(?:(?:(\\d+)Y)?(?:(\\d+)M)?(?:(\\d+)D)?(?:T(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+)S)?)?)|(?:(\\d+)W))$#'; + if (!preg_match($durationRegEx, $duration, $matches)) { + throw new Exception('Invalid ISO 8601 duration: ' . $duration); + } + + $durYears = (empty($matches[2]) ? 0 : (int)$matches[2]); + $durMonths = (empty($matches[3]) ? 0 : (int)$matches[3]); + $durDays = (empty($matches[4]) ? 0 : (int)$matches[4]); + $durHours = (empty($matches[5]) ? 0 : (int)$matches[5]); + $durMinutes = (empty($matches[6]) ? 0 : (int)$matches[6]); + $durSeconds = (empty($matches[7]) ? 0 : (int)$matches[7]); + $durWeeks = (empty($matches[8]) ? 0 : (int)$matches[8]); + + if (!empty($matches[1])) { + /* Negative */ + $durYears = -$durYears; + $durMonths = -$durMonths; + $durDays = -$durDays; + $durHours = -$durHours; + $durMinutes = -$durMinutes; + $durSeconds = -$durSeconds; + $durWeeks = -$durWeeks; + } + + if ($timestamp === NULL) { + $timestamp = time(); + } + + if ($durYears !== 0 || $durMonths !== 0) { + /* Special handling of months and years, since they aren't a specific interval, but + * instead depend on the current time. + */ + + /* We need the year and month from the timestamp. Unfortunately, PHP doesn't have the + * gmtime function. Instead we use the gmdate function, and split the result. + */ + $yearmonth = explode(':', gmdate('Y:n', $timestamp)); + $year = (int)($yearmonth[0]); + $month = (int)($yearmonth[1]); + + /* Remove the year and month from the timestamp. */ + $timestamp -= gmmktime(0, 0, 0, $month, 1, $year); + + /* Add years and months, and normalize the numbers afterwards. */ + $year += $durYears; + $month += $durMonths; + while ($month > 12) { + $year += 1; + $month -= 12; + } + while ($month < 1) { + $year -= 1; + $month += 12; + } + + /* Add year and month back into timestamp. */ + $timestamp += gmmktime(0, 0, 0, $month, 1, $year); + } + + /* Add the other elements. */ + $timestamp += $durWeeks * 7 * 24 * 60 * 60; + $timestamp += $durDays * 24 * 60 * 60; + $timestamp += $durHours * 60 * 60; + $timestamp += $durMinutes * 60; + $timestamp += $durSecods; + + return $timestamp; + } + + /** * Show and log fatal error message. * -- GitLab