-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Brian Retterer
committed
Feb 11, 2016
0 parents
commit 1fa460f
Showing
8 changed files
with
394 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/vendor |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# PHP ISO8601 Duration Converter | ||
Easily converts ISO 8601 Durations to Seconds and Seconds to ISO 8601 Durations | ||
|
||
## Installation | ||
```sh | ||
composer require bretterer/iso_duration_converter | ||
``` | ||
|
||
## Usage | ||
```php | ||
$converter = new \Bretterer\IsoDurationConverter\DurationParser(); | ||
$converter->parse('PT8S'); // Returns 8 | ||
$converter->parse('PT5M'); // Returns 300 | ||
$converter->parse('PT20H'); // Returns 72000 | ||
$converter->parse('PT6M4S'); // Returns 364 | ||
|
||
$converter->compose(8); // Returns PT8S | ||
$converter->composer(300); // Returns PT5M | ||
$converter->composer(7200); // Returns PT20H | ||
$converter->compose(364); //Returns PT6M4S | ||
|
||
$converter->parse('P5W'); // Returns 3024000 | ||
// To Returns Weeks, The second argument should be true | ||
$converter->compose(3024000, true); // Returns P5W | ||
$converter->compose(3024000); // Returns P35D | ||
|
||
$converter->parse('Hello World'); // Throws 'Invalid Argument Exception' with Message 'Invalid Duration' | ||
$converter->parse('P10Y10M10D'); // Throws 'Invalid Argument Exception' with Message 'Ambiguous Duration' | ||
``` | ||
|
||
## Years and Months | ||
If years are passed into the `parse` method, an `invalid argument exception` will be thrown. | ||
|
||
If you are wanting to convert seconds into months, pass true as the second argument in the `compose` method | ||
|
||
## License | ||
MIT |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"name": "bretterer/iso_duration_converter", | ||
"description": "Easily convert ISO_8601 Duration time format to seconds and convert seconds to ISO-8601 Duration", | ||
"license": "MIT", | ||
"authors": [ | ||
{ | ||
"name": "Brian Retterer", | ||
"email": "[email protected]" | ||
} | ||
], | ||
"autoload": { | ||
"psr-4": { | ||
"Bretterer\\IsoDurationConverter\\": "src/" | ||
} | ||
}, | ||
"autoload-dev": { | ||
"classmap": [ | ||
"tests/TestCase.php" | ||
] | ||
}, | ||
"require": {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<phpunit bootstrap="tests/Bootstrap.php" | ||
colors="true" | ||
backupGlobals="false"> | ||
|
||
<testsuites> | ||
<testsuite name="Unit Tests"> | ||
<directory suffix="Test.php">./tests</directory> | ||
</testsuite> | ||
</testsuites> | ||
|
||
<filter> | ||
<whitelist addUncoveredFilesFromWhitelist="true"> | ||
<directory suffix=".php">./src</directory> | ||
</whitelist> | ||
</filter> | ||
</phpunit> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
<?php | ||
|
||
namespace Bretterer\IsoDurationConverter; | ||
|
||
class DurationParser | ||
{ | ||
const WEEK = '/^P([0-9]+W)$/'; | ||
const DATE_TIME = '/^P(([0-9]+Y)?([0-9]+M)?([0-9]+D)?)?(T([0-9]+H)?([0-9]+M)?([0-9]+S)?)?$/'; | ||
|
||
private $totalTime; | ||
private $composedDuration; | ||
|
||
public function parse($duration) | ||
{ | ||
$m = []; | ||
preg_match(self::WEEK, $duration, $m); | ||
|
||
if ($m) { | ||
return $this->parsePart('week', $m[1]); | ||
} | ||
|
||
preg_match(self::DATE_TIME, $duration, $m); | ||
|
||
if ($m) { | ||
return ( | ||
$this->parsePart('date', isset($m[2]) ? $m[2] : null) + | ||
$this->parsePart('date', isset($m[3]) ? $m[3] : null) + | ||
$this->parsePart('date', isset($m[4]) ? $m[4] : null) + | ||
$this->parsePart('time', isset($m[6]) ? $m[6] : null) + | ||
$this->parsePart('time', isset($m[7]) ? $m[7] : null) + | ||
$this->parsePart('time', isset($m[8]) ? $m[8] : null) | ||
); | ||
} | ||
|
||
throw new \InvalidArgumentException('Invalid duration'); | ||
|
||
} | ||
|
||
public function compose($time, $weekMode = false) | ||
{ | ||
$this->totalTime = $time; | ||
$this->composedDuration = 'P'; | ||
|
||
if($weekMode) { | ||
$this->composePart('week W'); | ||
return $this->composedDuration; | ||
} | ||
|
||
$this->composePart('date D'); | ||
$this->composePart('time H'); | ||
$this->composePart('time M'); | ||
$this->composePart('time S'); | ||
|
||
return $this->composedDuration; | ||
} | ||
|
||
private function parsePart($mode, $string) | ||
{ | ||
if(!$string) return 0; | ||
|
||
$n = $this->extractInt($string); | ||
$id = $mode . ' ' . $string[strlen($string)-1]; | ||
|
||
if ($n === 0) return 0; | ||
|
||
switch($id) { | ||
case 'time S': | ||
return $n * 1; | ||
case 'time M': | ||
return $n * 60; | ||
case 'time H': | ||
return $n * 3600; | ||
case 'date D': | ||
return $n * 86400; | ||
case 'week W': | ||
return $n * 604800; | ||
} | ||
throw new \InvalidArgumentException('Ambiguous duration'); | ||
} | ||
|
||
private function extractInt($string) | ||
{ | ||
return (int) substr($string, 0, strlen($string)-1); | ||
} | ||
|
||
private function composePart($mode) | ||
{ | ||
$time = true; | ||
|
||
switch($mode) { | ||
case 'time S': | ||
$string = max((int)floor($this->totalTime / 1), 0); | ||
$this->totalTime -= $string*1; | ||
$string = $string > 0 ? $string.'S' : ''; | ||
break; | ||
case 'time M': | ||
$string = max((int)floor($this->totalTime / 60), 0); | ||
$this->totalTime -= $string*60; | ||
$string = $string > 0 ? $string.'M' : ''; | ||
break; | ||
case 'time H': | ||
$string = max((int)floor($this->totalTime / 3600), 0); | ||
$this->totalTime -= $string*3600; | ||
$string = $string > 0 ? $string.'H' : ''; | ||
break; | ||
case 'date D': | ||
$string = max((int)floor($this->totalTime / 86400), 0); | ||
$this->totalTime -= $string*86400; | ||
$string = $string > 0 ? $string.'D' : ''; | ||
$time = false; | ||
break; | ||
case 'week W': | ||
$string = max((int)floor($this->totalTime / 604800), 0) . 'W'; | ||
$this->totalTime -= $string*604800; | ||
$time = false; | ||
break; | ||
} | ||
|
||
if(($time && !strpos($this->composedDuration, 'T')) && $string != '') { | ||
$this->composedDuration .= 'T'; | ||
} | ||
|
||
|
||
|
||
$this->composedDuration .= $string; | ||
|
||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<?php | ||
|
||
// Include the composer autoloader | ||
require_once dirname(__DIR__) . '/vendor/autoload.php'; | ||
|
||
|
||
date_default_timezone_set('UTC'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
<?php | ||
|
||
class DurationParserTest extends TestCase | ||
{ | ||
private $parser; | ||
|
||
public function __construct() | ||
{ | ||
$this->parser = new \Bretterer\IsoDurationConverter\DurationParser(); | ||
} | ||
|
||
/** @test */ | ||
public function it_can_parse_week_durations() | ||
{ | ||
$this->assertEquals($this->parser->parse('P0W'), 0); | ||
$this->assertEquals($this->parser->parse('P1W'), 1 * 604800); | ||
$this->assertEquals($this->parser->parse('P5W'), 5 * 604800); | ||
$this->assertEquals($this->parser->parse('P10W'), 10 * 604800); | ||
} | ||
|
||
/** @test */ | ||
public function it_can_compose_week_durations() | ||
{ | ||
$this->assertEquals($this->parser->compose(0, true), 'P0W'); | ||
$this->assertEquals($this->parser->compose(1 * 604800, true), 'P1W'); | ||
$this->assertEquals($this->parser->compose(5 * 604800, true), 'P5W'); | ||
$this->assertEquals($this->parser->compose(10 * 604800, true), 'P10W'); | ||
} | ||
|
||
|
||
/** @test */ | ||
public function it_can_parse_second_durations() | ||
{ | ||
$this->assertEquals($this->parser->parse('PT0S'), 0); | ||
$this->assertEquals($this->parser->parse('PT1S'), 1 * 1); | ||
$this->assertEquals($this->parser->parse('PT5S'), 5 * 1); | ||
$this->assertEquals($this->parser->parse('PT10S'), 10 * 1); | ||
} | ||
|
||
/** @test */ | ||
public function it_can_compose_second_durations() | ||
{ | ||
$this->assertEquals($this->parser->compose(1 * 1), 'PT1S'); | ||
$this->assertEquals($this->parser->compose(5 * 1), 'PT5S'); | ||
$this->assertEquals($this->parser->compose(10 * 1), 'PT10S'); | ||
} | ||
|
||
/** @test */ | ||
public function it_can_parse_minute_durations() | ||
{ | ||
$this->assertEquals($this->parser->parse('PT0M'), 0); | ||
$this->assertEquals($this->parser->parse('PT1M'), 1 * 60); | ||
$this->assertEquals($this->parser->parse('PT5M'), 5 * 60); | ||
$this->assertEquals($this->parser->parse('PT10M'), 10 * 60); | ||
} | ||
|
||
/** @test */ | ||
public function it_can_compose_minute_durations() | ||
{ | ||
$this->assertEquals($this->parser->compose(1 * 60), 'PT1M'); | ||
$this->assertEquals($this->parser->compose(5 * 60), 'PT5M'); | ||
$this->assertEquals($this->parser->compose(10 * 60), 'PT10M'); | ||
} | ||
|
||
/** @test */ | ||
public function it_can_parse_hour_durations() | ||
{ | ||
$this->assertEquals($this->parser->parse('PT0H'), 0); | ||
$this->assertEquals($this->parser->parse('PT1H'), 1 * 3600); | ||
$this->assertEquals($this->parser->parse('PT5H'), 5 * 3600); | ||
$this->assertEquals($this->parser->parse('PT10H'), 10 * 3600); | ||
} | ||
|
||
/** @test */ | ||
public function it_can_compose_hour_durations() | ||
{ | ||
$this->assertEquals($this->parser->compose(1 * 3600), 'PT1H'); | ||
$this->assertEquals($this->parser->compose(5 * 3600), 'PT5H'); | ||
$this->assertEquals($this->parser->compose(10 * 3600), 'PT10H'); | ||
} | ||
|
||
/** @test */ | ||
public function it_can_parse_full_time_durations() | ||
{ | ||
$this->assertEquals($this->parser->parse('PT0H2M'), 2 * 60); | ||
$this->assertEquals($this->parser->parse('PT1H5M'), 1 * 3600 + 5 * 60); | ||
$this->assertEquals($this->parser->parse('PT5H10S'), 5 * 3600 + 10 * 1); | ||
$this->assertEquals($this->parser->parse('PT10H40M23S'), 10 * 3600 + 40 * 60 + 23 * 1); | ||
|
||
} | ||
|
||
/** @test */ | ||
public function it_can_compose_full_time_durations() | ||
{ | ||
$this->assertEquals($this->parser->compose(10 * 3600 + 2 * 60), 'PT10H2M'); | ||
$this->assertEquals($this->parser->compose(1 * 3600 + 5 * 60), 'PT1H5M'); | ||
$this->assertEquals($this->parser->compose(5 * 3600 + 10 * 1), 'PT5H10S'); | ||
$this->assertEquals($this->parser->compose(10 * 3600 + 40 * 60 + 23 * 1), 'PT10H40M23S'); | ||
|
||
} | ||
|
||
/** @test */ | ||
public function it_can_parse_day_durations() | ||
{ | ||
$this->assertEquals($this->parser->parse('P0D'), 0 * 86400); | ||
$this->assertEquals($this->parser->parse('P1D'), 1 * 86400); | ||
$this->assertEquals($this->parser->parse('P5D'), 5 * 86400); | ||
$this->assertEquals($this->parser->parse('P10D'), 10 * 86400); | ||
|
||
} | ||
|
||
/** @test */ | ||
public function it_can_compose_day_durations() | ||
{ | ||
$this->assertEquals($this->parser->compose(1 * 86400), 'P1D'); | ||
$this->assertEquals($this->parser->compose(5 * 86400), 'P5D'); | ||
$this->assertEquals($this->parser->compose(10 * 86400), 'P10D'); | ||
|
||
} | ||
|
||
/** @test */ | ||
public function it_can_parse_full_date_time_durations() | ||
{ | ||
$this->assertEquals($this->parser->parse('P0DT30M'), 0 * 86400 + 30 * 60); | ||
$this->assertEquals($this->parser->parse('P10DT30S'), 10 * 86400 + 30 * 1); | ||
$this->assertEquals($this->parser->parse('P12DT28M'), 12 * 86400 + 28 * 60); | ||
$this->assertEquals($this->parser->parse('P14DT26H'), 14 * 86400 + 26 * 3600); | ||
} | ||
|
||
/** @test */ | ||
public function it_can_compose_full_date_time_durations() | ||
{ | ||
$this->assertEquals($this->parser->compose(1 * 86400 + 30 * 60), 'P1DT30M'); | ||
$this->assertEquals($this->parser->compose(10 * 86400 + 30 * 1), 'P10DT30S'); | ||
$this->assertEquals($this->parser->compose(12 * 86400 + 28 * 60), 'P12DT28M'); | ||
$this->assertEquals($this->parser->compose(14 * 86400 + 26 * 3600), 'P15DT2H'); | ||
} | ||
|
||
/** @test */ | ||
public function it_should_throw_invalid_argument_exception_when_garbage_is_used() | ||
{ | ||
$this->setExpectedException('\InvalidArgumentException', 'Invalid duration'); | ||
$this->parser->parse('PT123123'); | ||
} | ||
|
||
/** @test */ | ||
public function it_should_throw_invalid_argument_exception_for_ambiguous_durations() | ||
{ | ||
$this->setExpectedException('\InvalidArgumentException', 'Ambiguous duration'); | ||
$this->parser->parse('P8Y20M10D'); | ||
} | ||
|
||
/** @test */ | ||
public function examples_work() | ||
{ | ||
$this->assertEquals(8, $this->parser->parse('PT8S')); | ||
$this->assertEquals(300, $this->parser->parse('PT5M')); | ||
$this->assertEquals(72000, $this->parser->parse('PT20H')); | ||
$this->assertEquals(364, $this->parser->parse('PT6M4S')); | ||
|
||
$this->assertEquals('PT8S', $this->parser->compose(8)); | ||
$this->assertEquals('PT5M', $this->parser->compose(300)); | ||
$this->assertEquals('PT20H', $this->parser->compose(72000)); | ||
$this->assertEquals('PT6M4S', $this->parser->compose(364)); | ||
|
||
$this->assertEquals(3024000, $this->parser->parse('P5W')); | ||
$this->assertEquals('P5W', $this->parser->compose(3024000, true)); | ||
$this->assertEquals('P35D', $this->parser->compose(3024000)); | ||
} | ||
|
||
|
||
|
||
|
||
|
||
} |
Oops, something went wrong.