mirror of
https://github.com/rlanvin/php-rrule.git
synced 2025-02-20 09:54:16 +01:00
parent
e57f6eb0bc
commit
97d860e55e
@ -571,6 +571,9 @@ class RRule implements RRuleInterface
|
||||
|
||||
$string = trim($string);
|
||||
|
||||
$dtstart_type = 'date';
|
||||
$rfc_date_regexp = '/\d{6}(T\d{6})?Z?/'; // a bit loose
|
||||
|
||||
foreach ( explode("\n", $string) as $line ) {
|
||||
$line = trim($line);
|
||||
if ( strpos($line,':') === false ) {
|
||||
@ -586,7 +589,7 @@ class RRule implements RRuleInterface
|
||||
array_splice($tmp,0,1);
|
||||
foreach ( $tmp as $pair ) {
|
||||
if ( strpos($pair,'=') === false ) {
|
||||
throw new \InvalidArgumentException('Failed to parse RFC string, invlaid property parameters: '.$pair);
|
||||
throw new \InvalidArgumentException('Failed to parse RFC string, invalid property parameters: '.$pair);
|
||||
}
|
||||
list($key,$value) = explode('=',$pair);
|
||||
$property_params[$key] = $value;
|
||||
@ -595,15 +598,72 @@ class RRule implements RRuleInterface
|
||||
switch ( $property_name ) {
|
||||
case 'DTSTART':
|
||||
$tmp = null;
|
||||
if ( ! preg_match($rfc_date_regexp, $property_value) ) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Invalid DTSTART property: date or date time format incorrect'
|
||||
);
|
||||
}
|
||||
if ( isset($property_params['TZID']) ) {
|
||||
// TZID must only be specified if this is a date-time (see section 3.3.4 & 3.3.5 of RFC 5545)
|
||||
if ( strpos($property_value, 'T') === false ) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Invalid DTSTART property: TZID should not be specified if there is no time component'
|
||||
);
|
||||
}
|
||||
// The "TZID" property parameter MUST NOT be applied to DATE-TIME
|
||||
// properties whose time values are specified in UTC.
|
||||
if ( strpos($property_value, 'Z') !== false ) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Invalid DTSTART property: TZID must not be applied when time is specified in UTC'
|
||||
);
|
||||
}
|
||||
$dtstart_type = 'tzid';
|
||||
$tmp = new \DateTimeZone($property_params['TZID']);
|
||||
}
|
||||
elseif ( strpos($property_value, 'T') !== false ) {
|
||||
if ( strpos($property_value, 'Z') === false ) {
|
||||
$dtstart_type = 'localtime'; // no timezone
|
||||
}
|
||||
else {
|
||||
$dtstart_type = 'utc';
|
||||
}
|
||||
}
|
||||
$parts['DTSTART'] = new \DateTime($property_value, $tmp);
|
||||
break;
|
||||
case 'RRULE':
|
||||
foreach ( explode(';',$property_value) as $pair ) {
|
||||
list($key, $value) = explode('=', $pair);
|
||||
if ( $key === 'UNTIL' ) {
|
||||
if ( ! preg_match($rfc_date_regexp, $value) ) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Invalid DTSTART property: date or date time format incorrect'
|
||||
);
|
||||
}
|
||||
switch ( $dtstart_type ) {
|
||||
case 'date':
|
||||
if ( strpos($value, 'T') !== false) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Invalid UNTIL property: The value of the UNTIL rule part MUST be a date if DTSTART is a date.'
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'localtime':
|
||||
if ( strpos($value, 'T') === false || strpos($value, 'Z') !== false ) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Invalid UNTIL property: if the "DTSTART" property is specified as a date with local time, then the UNTIL rule part MUST also be specified as a date with local time'
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'tzid':
|
||||
case 'utc':
|
||||
if ( strpos($value, 'T') === false || strpos($value, 'Z') === false ) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Invalid UNTIL property: if the "DTSTART" property is specified as a date with UTC time or a date with local time and time zone reference, then the UNTIL rule part MUST be specified as a date with UTC time.'
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$value = new \DateTime($value);
|
||||
}
|
||||
$parts[$key] = $value;
|
||||
|
@ -15,6 +15,8 @@ class RRuleTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
return array(
|
||||
array(array()),
|
||||
array(array('FOOBAR' => 'DAILY')),
|
||||
|
||||
array(array('FREQ' => 'foobar')),
|
||||
array(array('FREQ' => 'DAILY', 'INTERVAL' => -1)),
|
||||
array(array('FREQ' => 'DAILY', 'UNTIL' => 'foobar')),
|
||||
@ -1688,7 +1690,7 @@ class RRuleTest extends PHPUnit_Framework_TestCase
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Other tests
|
||||
// RFC Strings
|
||||
|
||||
public function rfcStrings()
|
||||
{
|
||||
@ -1713,8 +1715,14 @@ class RRuleTest extends PHPUnit_Framework_TestCase
|
||||
RRULE:FREQ=MONTHLY;INTERVAL=1;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR;BYMONTHDAY=1,2,5,31,-1,-3,-15;BYSETPOS=-1,1'),
|
||||
array(' DTSTART;TZID=America/New_York:19970512T090000
|
||||
RRULE:FREQ=YEARLY;BYWEEKNO=20,30,40;BYDAY=MO'),
|
||||
array(' DTSTART;TZID=America/New_York:19970512T090000
|
||||
RRULE:FREQ=YEARLY;BYYEARDAY=1,-1,10,-50;BYDAY=MO')
|
||||
array('DTSTART;TZID=America/New_York:19970512T090000
|
||||
RRULE:FREQ=YEARLY;BYYEARDAY=1,-1,10,-50;BYDAY=MO'),
|
||||
array('DTSTART:19970512T090000Z
|
||||
RRULE:FREQ=YEARLY'),
|
||||
array('DTSTART:19970512T090000
|
||||
RRULE:FREQ=YEARLY'),
|
||||
array('DTSTART:19970512
|
||||
RRULE:FREQ=YEARLY'),
|
||||
);
|
||||
}
|
||||
|
||||
@ -1724,11 +1732,56 @@ class RRuleTest extends PHPUnit_Framework_TestCase
|
||||
public function testRfcStrings($str)
|
||||
{
|
||||
$rule = new RRule($str);
|
||||
|
||||
// test that parsing the string produces the same result
|
||||
// as generating the string from a rule
|
||||
$this->assertEquals($rule, new RRule($rule->rfcString()));
|
||||
}
|
||||
|
||||
public function invalidRfcStrings()
|
||||
{
|
||||
return array(
|
||||
// test invalid date formats
|
||||
array('DTSTART:2006-06-24
|
||||
RRULE:FREQ=DAILY'),
|
||||
array('DTSTART:2006-06-24 12:00:00
|
||||
RRULE:FREQ=DAILY'),
|
||||
array('DTSTART:20060624
|
||||
RRULE:FREQ=DAILY;UNTIL=2006-06-24'),
|
||||
|
||||
// test combinations of DTSTART and UNTIL which are invalid
|
||||
array('DTSTART;TZID=Australia/Sydney:20160624
|
||||
RRULE:FREQ=DAILY;INTERVAL=1;UNTIL=20160628'),
|
||||
array('DTSTART;TZID=America/New_York:19970512T090000Z
|
||||
RRULE:FREQ=YEARLY'),
|
||||
array('DTSTART;TZID=America/New_York:19970512T090000
|
||||
RRULE:FREQ=YEARLY;UNTIL=19970512'),
|
||||
array('DTSTART;TZID=America/New_York:19970512T090000
|
||||
RRULE:FREQ=YEARLY;UNTIL=19970512T090000'),
|
||||
array('DTSTART:19970512T090000
|
||||
RRULE:FREQ=YEARLY;UNTIL=19970512'),
|
||||
array('DTSTART:19970512T090000Z
|
||||
RRULE:FREQ=YEARLY;UNTIL=19970512'),
|
||||
array('DTSTART:19970512
|
||||
RRULE:FREQ=YEARLY;UNTIL=19970512T090000'),
|
||||
array('DTSTART:19970512
|
||||
RRULE:FREQ=YEARLY;UNTIL=19970512T090000Z'),
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
* @dataProvider invalidRfcStrings
|
||||
*/
|
||||
public function testInvalidRfcStrings($str)
|
||||
{
|
||||
$rule = new RRule($str);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Timezone
|
||||
|
||||
public function testTimezoneIsKeptIdentical()
|
||||
{
|
||||
$rrule = new RRule(array(
|
||||
@ -1812,6 +1865,56 @@ class RRuleTest extends PHPUnit_Framework_TestCase
|
||||
$this->assertTrue($rrule->occursAt(date_create('2015-12-02 07:00:00',new DateTimeZone('UTC'))), 'During winter time, Europe/Helsinki is UTC+2 (uncached)');
|
||||
}
|
||||
|
||||
public function rulesWithMismatchedTimezones()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
array('DTSTART' => new DateTime('20160624Z'),'FREQ' => 'DAILY','INTERVAL' => 1,'UNTIL' => '20160628'),
|
||||
array(
|
||||
date_create('20160624Z'),
|
||||
date_create('20160625Z'),
|
||||
date_create('20160626Z'),
|
||||
date_create('20160627Z'),
|
||||
// date_create('20160628Z') // will not return this due to timezone mismatch (unless default timezone is utc)
|
||||
)
|
||||
),
|
||||
array(
|
||||
array('DTSTART' => new DateTime('20160624Z'),'FREQ' => 'DAILY','INTERVAL' => 1,'UNTIL' => '28-06-2016'),
|
||||
array(
|
||||
date_create('20160624Z'),
|
||||
date_create('20160625Z'),
|
||||
date_create('20160626Z'),
|
||||
date_create('20160627Z'),
|
||||
// date_create('20160628Z') // will not return this due to timezone mismatch (unless default timezone is utc)
|
||||
)
|
||||
),
|
||||
array(
|
||||
array('DTSTART' => new DateTime('20160624Z'),'FREQ' => 'DAILY','INTERVAL' => 1,'UNTIL' => new DateTime('20160628', new DateTimeZone('Europe/Paris'))),
|
||||
array(
|
||||
date_create('20160624Z'),
|
||||
date_create('20160625Z'),
|
||||
date_create('20160626Z'),
|
||||
date_create('20160627Z'),
|
||||
// date_create('20160628Z') // will not return this due to timezone mismatch (unless default timezone is utc)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test bug issue #13
|
||||
* @see https://github.com/rlanvin/php-rrule/issues/13
|
||||
* @dataProvider rulesWithMismatchedTimezones
|
||||
*/
|
||||
public function testRulesWithMismatchedTimezones($rule, $occurrences)
|
||||
{
|
||||
$rrule = new RRule($rule);
|
||||
$this->assertEquals($occurrences, $rrule->getOccurrences(), 'Mismatched timezones makes for strange results');
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Other tests
|
||||
|
||||
public function testIsFinite()
|
||||
{
|
||||
$rrule = new RRule(array(
|
||||
@ -2084,7 +2187,7 @@ class RRuleTest extends PHPUnit_Framework_TestCase
|
||||
$rrule->humanReadable(array(
|
||||
'locale' => 'xx',
|
||||
'fallback' => 'xx'
|
||||
));
|
||||
)); // the locales are correctly formatted, but not such file exist, so this should throw a RuntimeException
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user