kopia lustrzana https://github.com/friendica/SG-iCalendar
Merged tpruvot's fork PHP-iCal (http://github.com/tpruvot/PHP-iCal). Great work tpruvot!
commit
c4042c1628
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
/sgical.php
|
|
@ -0,0 +1,54 @@
|
||||||
|
A simple and fast iCal parser.
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
http://github.com/fangel/SG-iCalendar
|
||||||
|
With massive help from http://github.com/tpruvot/PHP-iCal
|
||||||
|
and http://github.com/xonev/SG-iCalendar
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
A simple example :
|
||||||
|
$ical = new SG_iCalReader( "./basic.ics" );
|
||||||
|
//or
|
||||||
|
$ical = new SG_iCalReader( "http://example.com/calendar.ics" );
|
||||||
|
foreach( $ical->getEvents() As $event ) {
|
||||||
|
// Do stuff with the event $event
|
||||||
|
}
|
||||||
|
|
||||||
|
To check unit tests with phpunit, goto tests/ directory and :
|
||||||
|
phpunit AllTests
|
||||||
|
phpunit helpers/FreqTest
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
CHANGELOG :
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
current (31 oct 2010)
|
||||||
|
+ ical RDATE support (added dates in a range)
|
||||||
|
+ RDATE and EXDATE arrays support
|
||||||
|
|
||||||
|
0.7.0 (30 oct 2010)
|
||||||
|
+ ical EXDATE support (excluded dates in a range)
|
||||||
|
+ $event->isWholeDay()
|
||||||
|
+ getAllOccurrences() for repeated events
|
||||||
|
+ implemented a cache for repeated events
|
||||||
|
|
||||||
|
0.6.0 (29 oct 2010)
|
||||||
|
+ Added demo based on fullcalendar
|
||||||
|
+ Added duration unit tests
|
||||||
|
+ Support of Recurrent events in query Between()
|
||||||
|
* various fixes on actual (5) issues
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
TODO :
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
These iCal keywords are not supported for the moment :
|
||||||
|
- RECURRENCE-ID : to move one event from a recurrence
|
||||||
|
- EXRULE : to exclude multiple days by a complex rule
|
||||||
|
|
||||||
|
Also, multiple RRULE could be specified for an event,
|
||||||
|
but that is not the case for most calendar applications
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
To get more information about ical format and rules :
|
||||||
|
see http://www.ietf.org/rfc/rfc2445.txt
|
43
SG_iCal.php
43
SG_iCal.php
|
@ -1,17 +1,18 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
define('SG_ICALREADER_VERSION', '0.5');
|
define('SG_ICALREADER_VERSION', '0.7.0');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple iCal parser. Should take care of most stuff for ya
|
* A simple iCal parser. Should take care of most stuff for ya
|
||||||
|
* http://github.com/fangel/SG-iCalendar
|
||||||
*
|
*
|
||||||
* Roadmap:
|
* Roadmap:
|
||||||
* * Finish FREQUENCY-parsing.
|
* * Finish FREQUENCY-parsing.
|
||||||
* * Add API for recurring events
|
* * Add API for recurring events
|
||||||
*
|
*
|
||||||
* A simple example:
|
* A simple example:
|
||||||
* <?php
|
* <?php
|
||||||
* $ical = new SG_iCal("http://example.com/calendar.ics");
|
* $ical = new SG_iCalReader("http://example.com/calendar.ics");
|
||||||
* foreach( $ical->getEvents() As $event ) {
|
* foreach( $ical->getEvents() As $event ) {
|
||||||
* // Do stuff with the event $event
|
* // Do stuff with the event $event
|
||||||
* }
|
* }
|
||||||
|
@ -19,26 +20,32 @@ define('SG_ICALREADER_VERSION', '0.5');
|
||||||
*
|
*
|
||||||
* @package SG_iCalReader
|
* @package SG_iCalReader
|
||||||
* @author Morten Fangel (C) 2008
|
* @author Morten Fangel (C) 2008
|
||||||
|
* @author xonev (C) 2010
|
||||||
|
* @author Tanguy Pruvot (C) 2010
|
||||||
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
||||||
*/
|
*/
|
||||||
class SG_iCal {
|
class SG_iCal {
|
||||||
private $information;
|
|
||||||
private $events;
|
//objects
|
||||||
private $timezones;
|
public $information; //SG_iCal_VCalendar
|
||||||
|
public $timezones; //SG_iCal_VTimeZone
|
||||||
|
|
||||||
|
protected $events; //SG_iCal_VEvent[]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new iCalReader. You can supply the url now, or later using setUrl
|
* Constructs a new iCalReader. You can supply the url now, or later using setUrl
|
||||||
* @param $url string
|
* @param $url string
|
||||||
*/
|
*/
|
||||||
public function __construct($url = false) {
|
public function __construct($url = false) {
|
||||||
require_once dirname(__FILE__) . '/helpers/SG_iCal_Factory.php'; // BUILD: Remove line
|
|
||||||
require_once dirname(__FILE__) . '/helpers/SG_iCal_Line.php'; // BUILD: Remove line
|
require_once dirname(__FILE__) . '/helpers/SG_iCal_Line.php'; // BUILD: Remove line
|
||||||
require_once dirname(__FILE__) . '/helpers/SG_iCal_Query.php'; // BUILD: Remove line
|
require_once dirname(__FILE__) . '/helpers/SG_iCal_Duration.php'; // BUILD: Remove line
|
||||||
|
require_once dirname(__FILE__) . '/helpers/SG_iCal_Freq.php'; // BUILD: Remove line
|
||||||
|
require_once dirname(__FILE__) . '/helpers/SG_iCal_Recurrence.php'; // BUILD: Remove line
|
||||||
require_once dirname(__FILE__) . '/helpers/SG_iCal_Parser.php'; // BUILD: Remove line
|
require_once dirname(__FILE__) . '/helpers/SG_iCal_Parser.php'; // BUILD: Remove line
|
||||||
|
require_once dirname(__FILE__) . '/helpers/SG_iCal_Query.php'; // BUILD: Remove line
|
||||||
|
require_once dirname(__FILE__) . '/helpers/SG_iCal_Factory.php'; // BUILD: Remove line
|
||||||
|
|
||||||
if( $url !== false ) {
|
$this->setUrl($url);
|
||||||
SG_iCal_Parser::Parse($url, $this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,16 +57,16 @@ class SG_iCal {
|
||||||
SG_iCal_Parser::Parse($url, $this);
|
SG_iCal_Parser::Parse($url, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the main calendar info. You can then query the returned
|
* Returns the main calendar info. You can then query the returned
|
||||||
* object with ie getTitle().
|
* object with ie getTitle().
|
||||||
* @return SG_iCal_VCalendar
|
* @return SG_iCal_VCalendar
|
||||||
*/
|
*/
|
||||||
public function getCalendarInfo() {
|
public function getCalendarInfo() {
|
||||||
return $this->information;
|
return $this->information;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the calendar info for this calendar
|
* Sets the calendar info for this calendar
|
||||||
* @param SG_iCal_VCalendar $info
|
* @param SG_iCal_VCalendar $info
|
||||||
|
@ -67,8 +74,8 @@ class SG_iCal {
|
||||||
public function setCalendarInfo( SG_iCal_VCalendar $info ) {
|
public function setCalendarInfo( SG_iCal_VCalendar $info ) {
|
||||||
$this->information = $info;
|
$this->information = $info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a given timezone for the calendar. This is mainly used
|
* Returns a given timezone for the calendar. This is mainly used
|
||||||
* by VEvents to adjust their date-times if they have specified a
|
* by VEvents to adjust their date-times if they have specified a
|
||||||
|
@ -95,7 +102,7 @@ class SG_iCal {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new timezone to this calendar
|
* Adds a new timezone to this calendar
|
||||||
* @param SG_iCal_VTimeZone $tz
|
* @param SG_iCal_VTimeZone $tz
|
||||||
|
@ -103,7 +110,7 @@ class SG_iCal {
|
||||||
public function addTimeZone( SG_iCal_VTimeZone $tz ) {
|
public function addTimeZone( SG_iCal_VTimeZone $tz ) {
|
||||||
$this->timezones[] = $tz;
|
$this->timezones[] = $tz;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the events found
|
* Returns the events found
|
||||||
* @return array
|
* @return array
|
||||||
|
|
|
@ -10,17 +10,17 @@
|
||||||
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
||||||
*/
|
*/
|
||||||
class SG_iCal_VCalendar implements IteratorAggregate {
|
class SG_iCal_VCalendar implements IteratorAggregate {
|
||||||
private $data;
|
protected $data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new SG_iCal_VCalendar.
|
* Creates a new SG_iCal_VCalendar.
|
||||||
*/
|
*/
|
||||||
public function __construct($data) {
|
public function __construct($data) {
|
||||||
$this->data = $data;
|
$this->data = $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the title of the calendar. If no title is known, NULL
|
* Returns the title of the calendar. If no title is known, NULL
|
||||||
* will be returned
|
* will be returned
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
|
@ -31,7 +31,7 @@ class SG_iCal_VCalendar implements IteratorAggregate {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the description of the calendar. If no description is
|
* Returns the description of the calendar. If no description is
|
||||||
* known, NULL will be returned.
|
* known, NULL will be returned.
|
||||||
|
@ -44,7 +44,7 @@ class SG_iCal_VCalendar implements IteratorAggregate {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see IteratorAggregate.getIterator()
|
* @see IteratorAggregate.getIterator()
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
<?php // BUILD: Remove line
|
<?php // BUILD: Remove line
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The wrapper for vevents. Will reveal a unified and simple api for
|
* The wrapper for vevents. Will reveal a unified and simple api for
|
||||||
* the events, which include always finding a start and end (except
|
* the events, which include always finding a start and end (except
|
||||||
* when no end or duration is given) and checking if the event is
|
* when no end or duration is given) and checking if the event is
|
||||||
* blocking or similar.
|
* blocking or similar.
|
||||||
*
|
*
|
||||||
* Will apply the specified timezone to timestamps if a tzid is
|
* Will apply the specified timezone to timestamps if a tzid is
|
||||||
* specified
|
* specified
|
||||||
*
|
*
|
||||||
* @package SG_iCalReader
|
* @package SG_iCalReader
|
||||||
|
@ -15,22 +15,36 @@
|
||||||
*/
|
*/
|
||||||
class SG_iCal_VEvent {
|
class SG_iCal_VEvent {
|
||||||
const DEFAULT_CONFIRMED = true;
|
const DEFAULT_CONFIRMED = true;
|
||||||
private $uid;
|
|
||||||
private $start;
|
protected $uid;
|
||||||
private $end;
|
|
||||||
private $recurrence;
|
protected $start;
|
||||||
private $summary;
|
protected $end;
|
||||||
private $description;
|
|
||||||
private $location;
|
protected $summary;
|
||||||
private $data;
|
protected $description;
|
||||||
|
protected $location;
|
||||||
|
|
||||||
|
protected $laststart;
|
||||||
|
protected $lastend;
|
||||||
|
|
||||||
|
public $recurrence; //RRULE
|
||||||
|
public $recurex; //EXRULE
|
||||||
|
public $excluded; //EXDATE(s)
|
||||||
|
public $added; //RDATE(s)
|
||||||
|
|
||||||
|
public $freq; //getFrequency() SG_iCal_Freq
|
||||||
|
|
||||||
|
public $data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new SG_iCal_VEvent. Needs the SG_iCalReader
|
* Constructs a new SG_iCal_VEvent. Needs the SG_iCalReader
|
||||||
* supplied so it can query for timezones.
|
* supplied so it can query for timezones.
|
||||||
* @param SG_iCal_Line[] $data
|
* @param SG_iCal_Line[] $data
|
||||||
* @param SG_iCalReader $ical
|
* @param SG_iCalReader $ical
|
||||||
*/
|
*/
|
||||||
public function __construct($data, SG_iCal $ical ) {
|
public function __construct($data, SG_iCal $ical) {
|
||||||
|
|
||||||
$this->uid = $data['uid']->getData();
|
$this->uid = $data['uid']->getData();
|
||||||
unset($data['uid']);
|
unset($data['uid']);
|
||||||
|
|
||||||
|
@ -38,33 +52,66 @@ class SG_iCal_VEvent {
|
||||||
$this->recurrence = new SG_iCal_Recurrence($data['rrule']);
|
$this->recurrence = new SG_iCal_Recurrence($data['rrule']);
|
||||||
unset($data['rrule']);
|
unset($data['rrule']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( isset($data['exrule']) ) {
|
||||||
|
$this->recurex = new SG_iCal_Recurrence($data['exrule']);
|
||||||
|
unset($data['exrule']);
|
||||||
|
}
|
||||||
|
|
||||||
if( isset($data['dtstart']) ) {
|
if( isset($data['dtstart']) ) {
|
||||||
$this->start = $this->getTimestamp( $data['dtstart'], $ical );
|
$this->start = $this->getTimestamp($data['dtstart'], $ical);
|
||||||
unset($data['dtstart']);
|
unset($data['dtstart']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( isset($data['dtend']) ) {
|
if( isset($data['dtend']) ) {
|
||||||
$this->end = $this->getTimestamp($data['dtend'], $ical);
|
$this->end = $this->getTimestamp($data['dtend'], $ical);
|
||||||
unset($data['dtend']);
|
unset($data['dtend']);
|
||||||
} elseif( isset($data['duration']) ) {
|
} elseif( isset($data['duration']) ) {
|
||||||
require_once dirname(__FILE__).'/../helpers/SG_iCal_Duration.php'; // BUILD: Remove line
|
|
||||||
$dur = new SG_iCal_Duration( $data['duration']->getData() );
|
$dur = new SG_iCal_Duration( $data['duration']->getData() );
|
||||||
$this->end = $this->start + $dur->getDuration();
|
$this->end = $this->start + $dur->getDuration();
|
||||||
unset($data['duration']);
|
unset($data['duration']);
|
||||||
} elseif ( isset($this->recurrence) ) {
|
}
|
||||||
|
|
||||||
|
//google cal set dtend as end of initial event (duration)
|
||||||
|
if ( isset($this->recurrence) ) {
|
||||||
//if there is a recurrence rule
|
//if there is a recurrence rule
|
||||||
|
|
||||||
|
//exclusions
|
||||||
|
if ( isset($data['exdate']) ) {
|
||||||
|
foreach ($data['exdate'] as $exdate) {
|
||||||
|
foreach ($exdate->getDataAsArray() as $ts) {
|
||||||
|
$this->excluded[] = strtotime($ts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($data['exdate']);
|
||||||
|
}
|
||||||
|
//additions
|
||||||
|
if ( isset($data['rdate']) ) {
|
||||||
|
foreach ($data['rdate'] as $rdate) {
|
||||||
|
foreach ($rdate->getDataAsArray() as $ts) {
|
||||||
|
$this->added[] = strtotime($ts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($data['rdate']);
|
||||||
|
}
|
||||||
|
|
||||||
$until = $this->recurrence->getUntil();
|
$until = $this->recurrence->getUntil();
|
||||||
$count = $this->recurrence->getCount();
|
$count = $this->recurrence->getCount();
|
||||||
//check if there is either 'until' or 'count' set
|
//check if there is either 'until' or 'count' set
|
||||||
if ( $this->recurrence->getUntil() or $this->recurrence->getCount() ) {
|
if ( $until ) {
|
||||||
//if until is set, set that as the end date (using getTimeStamp)
|
//ok..
|
||||||
if ( $until ) {
|
} elseif ($count) {
|
||||||
$this->end = strtotime( $until );
|
|
||||||
}
|
|
||||||
//if count is set, then figure out the last occurrence and set that as the end date
|
//if count is set, then figure out the last occurrence and set that as the end date
|
||||||
|
$this->getFrequency();
|
||||||
|
$until = $this->freq->lastOccurrence($this->start);
|
||||||
|
} else {
|
||||||
|
//forever... limit to 3 years
|
||||||
|
$this->recurrence->setUntil('+3 years');
|
||||||
|
$until = $this->recurrence->getUntil();
|
||||||
}
|
}
|
||||||
|
//date_default_timezone_set( xx ) needed ?;
|
||||||
|
$this->laststart = strtotime($until);
|
||||||
|
$this->lastend = $this->laststart + $this->getDuration();
|
||||||
}
|
}
|
||||||
|
|
||||||
$imports = array('summary','description','location');
|
$imports = array('summary','description','location');
|
||||||
|
@ -74,10 +121,28 @@ class SG_iCal_VEvent {
|
||||||
unset($data[$import]);
|
unset($data[$import]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( isset($this->previous_tz) ) {
|
||||||
|
date_default_timezone_set($this->previous_tz);
|
||||||
|
}
|
||||||
|
|
||||||
$this->data = SG_iCal_Line::Remove_Line($data);
|
$this->data = SG_iCal_Line::Remove_Line($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Event Occurrences Iterator (if recurrence set)
|
||||||
|
* @return SG_iCal_Freq
|
||||||
|
*/
|
||||||
|
public function getFrequency() {
|
||||||
|
if (! isset($this->freq)) {
|
||||||
|
if ( isset($this->recurrence) ) {
|
||||||
|
$this->freq = new SG_iCal_Freq($this->recurrence->rrule, $this->start, $this->excluded, $this->added);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this->freq;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the UID of the event
|
* Returns the UID of the event
|
||||||
* @return string
|
* @return string
|
||||||
|
@ -85,7 +150,7 @@ class SG_iCal_VEvent {
|
||||||
public function getUID() {
|
public function getUID() {
|
||||||
return $this->uid;
|
return $this->uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the summary (or null if none is given) of the event
|
* Returns the summary (or null if none is given) of the event
|
||||||
* @return string
|
* @return string
|
||||||
|
@ -93,7 +158,7 @@ class SG_iCal_VEvent {
|
||||||
public function getSummary() {
|
public function getSummary() {
|
||||||
return $this->summary;
|
return $this->summary;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the description (or null if none is given) of the event
|
* Returns the description (or null if none is given) of the event
|
||||||
* @return string
|
* @return string
|
||||||
|
@ -101,7 +166,7 @@ class SG_iCal_VEvent {
|
||||||
public function getDescription() {
|
public function getDescription() {
|
||||||
return $this->description;
|
return $this->description;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the location (or null if none is given) of the event
|
* Returns the location (or null if none is given) of the event
|
||||||
* @return string
|
* @return string
|
||||||
|
@ -109,7 +174,7 @@ class SG_iCal_VEvent {
|
||||||
public function getLocation() {
|
public function getLocation() {
|
||||||
return $this->location;
|
return $this->location;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the event is blocking (ie not transparent)
|
* Returns true if the event is blocking (ie not transparent)
|
||||||
* @return bool
|
* @return bool
|
||||||
|
@ -117,7 +182,7 @@ class SG_iCal_VEvent {
|
||||||
public function isBlocking() {
|
public function isBlocking() {
|
||||||
return !(isset($this->data['transp']) && $this->data['transp'] == 'TRANSPARENT');
|
return !(isset($this->data['transp']) && $this->data['transp'] == 'TRANSPARENT');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the event is confirmed
|
* Returns true if the event is confirmed
|
||||||
* @return bool
|
* @return bool
|
||||||
|
@ -129,7 +194,19 @@ class SG_iCal_VEvent {
|
||||||
return $this->data['status'] == 'CONFIRMED';
|
return $this->data['status'] == 'CONFIRMED';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if duration is multiple of 86400
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isWholeDay() {
|
||||||
|
$dur = $this->getDuration();
|
||||||
|
if ($dur > 0 && ($dur % 86400) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the timestamp for the beginning of the event
|
* Returns the timestamp for the beginning of the event
|
||||||
* @return int
|
* @return int
|
||||||
|
@ -137,7 +214,7 @@ class SG_iCal_VEvent {
|
||||||
public function getStart() {
|
public function getStart() {
|
||||||
return $this->start;
|
return $this->start;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the timestamp for the end of the event
|
* Returns the timestamp for the end of the event
|
||||||
* @return int
|
* @return int
|
||||||
|
@ -145,7 +222,15 @@ class SG_iCal_VEvent {
|
||||||
public function getEnd() {
|
public function getEnd() {
|
||||||
return $this->end;
|
return $this->end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the timestamp for the end of the last event
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getRangeEnd() {
|
||||||
|
return max($this->end,$this->lastend);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the duration of this event in seconds
|
* Returns the duration of this event in seconds
|
||||||
* @return int
|
* @return int
|
||||||
|
@ -153,7 +238,7 @@ class SG_iCal_VEvent {
|
||||||
public function getDuration() {
|
public function getDuration() {
|
||||||
return $this->end - $this->start;
|
return $this->end - $this->start;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the given property of the event.
|
* Returns the given property of the event.
|
||||||
* @param string $prop
|
* @param string $prop
|
||||||
|
@ -168,19 +253,40 @@ class SG_iCal_VEvent {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set default timezone (temporary) to get timestamps
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function setLineTimeZone(SG_iCal_Line $line) {
|
||||||
|
if( isset($line['tzid']) ) {
|
||||||
|
if (!isset($this->previous_tz)) {
|
||||||
|
$this->previous_tz = @ date_default_timezone_get();
|
||||||
|
}
|
||||||
|
$this->tzid = $line['tzid'];
|
||||||
|
date_default_timezone_set($this->tzid);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the timestamp from a DT line.
|
* Calculates the timestamp from a DT line.
|
||||||
* @param $line SG_iCal_Line
|
* @param $line SG_iCal_Line
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
private function getTimestamp( SG_iCal_Line $line, SG_iCal $ical ) {
|
protected function getTimestamp( SG_iCal_Line $line, SG_iCal $ical ) {
|
||||||
$ts = strtotime($line->getData());
|
|
||||||
if( isset($line['tzid']) ) {
|
if( isset($line['tzid']) ) {
|
||||||
$tz = $ical->getTimeZoneInfo($line['tzid']);
|
$this->setLineTimeZone($line);
|
||||||
$offset = $tz->getOffset($ts);
|
//$tz = $ical->getTimeZoneInfo($line['tzid']);
|
||||||
$ts = strtotime(date('D, d M Y H:i:s', $ts) . ' ' . $offset);
|
//$offset = $tz->getOffset($ts);
|
||||||
|
//$ts = strtotime(date('D, d M Y H:i:s', $ts) . ' ' . $offset);
|
||||||
}
|
}
|
||||||
|
$ts = strtotime($line->getData());
|
||||||
|
|
||||||
return $ts;
|
return $ts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,31 +9,31 @@
|
||||||
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
||||||
*/
|
*/
|
||||||
class SG_iCal_VTimeZone {
|
class SG_iCal_VTimeZone {
|
||||||
private $tzid;
|
protected $tzid;
|
||||||
private $daylight;
|
protected $daylight;
|
||||||
private $standard;
|
protected $standard;
|
||||||
private $cache = array();
|
protected $cache = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new SG_iCal_VTimeZone
|
* Constructs a new SG_iCal_VTimeZone
|
||||||
*/
|
*/
|
||||||
public function __construct( $data ) {
|
public function __construct( $data ) {
|
||||||
require_once dirname(__FILE__).'/../helpers/SG_iCal_Freq.php'; // BUILD: Remove line
|
require_once dirname(__FILE__).'/../helpers/SG_iCal_Freq.php'; // BUILD: Remove line
|
||||||
|
|
||||||
$this->tzid = $data['tzid'];
|
$this->tzid = $data['tzid'];
|
||||||
$this->daylight = $data['daylight'];
|
$this->daylight = $data['daylight'];
|
||||||
$this->standard = $data['standard'];
|
$this->standard = $data['standard'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the timezone-id for this timezone. (Used to
|
* Returns the timezone-id for this timezone. (Used to
|
||||||
* differentiate between different tzs in a calendar)
|
* differentiate between different tzs in a calendar)
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getTimeZoneId() {
|
public function getTimeZoneId() {
|
||||||
return $this->tzid;
|
return $this->tzid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the given offset in this timezone for the given
|
* Returns the given offset in this timezone for the given
|
||||||
* timestamp. (eg +0200)
|
* timestamp. (eg +0200)
|
||||||
|
@ -44,7 +44,7 @@ class SG_iCal_VTimeZone {
|
||||||
$act = $this->getActive($ts);
|
$act = $this->getActive($ts);
|
||||||
return $this->{$act}['tzoffsetto'];
|
return $this->{$act}['tzoffsetto'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the timezone name for the given timestamp (eg CEST)
|
* Returns the timezone name for the given timestamp (eg CEST)
|
||||||
* @param int $ts
|
* @param int $ts
|
||||||
|
@ -54,7 +54,7 @@ class SG_iCal_VTimeZone {
|
||||||
$act = $this->getActive($ts);
|
$act = $this->getActive($ts);
|
||||||
return $this->{$act}['tzname'];
|
return $this->{$act}['tzname'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines which of the daylight or standard is the active
|
* Determines which of the daylight or standard is the active
|
||||||
* setting.
|
* setting.
|
||||||
|
@ -65,20 +65,31 @@ class SG_iCal_VTimeZone {
|
||||||
* @return string standard|daylight
|
* @return string standard|daylight
|
||||||
*/
|
*/
|
||||||
private function getActive( $ts ) {
|
private function getActive( $ts ) {
|
||||||
if( isset($this->cache[$ts]) ) {
|
|
||||||
|
if (class_exists('DateTimeZone')) {
|
||||||
|
|
||||||
|
//PHP >= 5.2
|
||||||
|
$tz = new DateTimeZone( $this->tzid );
|
||||||
|
$date = new DateTime("@$ts", $tz);
|
||||||
|
return ($date->format('I') == 1) ? 'daylight' : 'standard';
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if( isset($this->cache[$ts]) ) {
|
||||||
|
return $this->cache[$ts];
|
||||||
|
}
|
||||||
|
|
||||||
|
$daylight_freq = new SG_iCal_Freq($this->daylight['rrule'], strtotime($this->daylight['dtstart']));
|
||||||
|
$standard_freq = new SG_iCal_Freq($this->standard['rrule'], strtotime($this->standard['dtstart']));
|
||||||
|
$last_standard = $standard_freq->previousOccurrence($ts);
|
||||||
|
$last_dst = $daylight_freq->previousOccurrence($ts);
|
||||||
|
if( $last_dst > $last_standard ) {
|
||||||
|
$this->cache[$ts] = 'daylight';
|
||||||
|
} else {
|
||||||
|
$this->cache[$ts] = 'standard';
|
||||||
|
}
|
||||||
|
|
||||||
return $this->cache[$ts];
|
return $this->cache[$ts];
|
||||||
}
|
}
|
||||||
|
|
||||||
$daylight_freq = new SG_iCal_Freq($this->daylight['rrule'], strtotime($this->daylight['dtstart']));
|
|
||||||
$standard_freq = new SG_iCal_Freq($this->standard['rrule'], strtotime($this->standard['dtstart']));
|
|
||||||
$last_standard = $standard_freq->previousOccurrence($ts);
|
|
||||||
$last_dst = $daylight_freq->previousOccurrence($ts);
|
|
||||||
if( $last_dst > $last_standard ) {
|
|
||||||
$this->cache[$ts] = 'daylight';
|
|
||||||
} else {
|
|
||||||
$this->cache[$ts] = 'standard';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->cache[$ts];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
@SET OUTPUT=.\sgical.php
|
||||||
|
|
||||||
|
cat SG_iCal.php | grep -v "BUILD: Remove line" > %OUTPUT%
|
||||||
|
DIR /B /S helpers | grep SG_iCal | grep -v svn | sed -e "s/\\/\//g" | xargs cat | grep -v "BUILD: Remove line" >> %OUTPUT%
|
||||||
|
DIR /B /S blocks | grep SG_iCal | grep -v svn | sed -e "s/\\/\//g" | xargs cat | grep -v "BUILD: Remove line" >> %OUTPUT%
|
|
@ -0,0 +1,107 @@
|
||||||
|
BEGIN:VCALENDAR
|
||||||
|
PRODID:-//Google Inc//Google Calendar 70.9054//EN
|
||||||
|
VERSION:2.0
|
||||||
|
CALSCALE:GREGORIAN
|
||||||
|
METHOD:PUBLISH
|
||||||
|
X-WR-CALNAME:Particuliers - Grand Tour du Bassin
|
||||||
|
X-WR-TIMEZONE:Europe/Paris
|
||||||
|
X-WR-CALDESC:
|
||||||
|
BEGIN:VTIMEZONE
|
||||||
|
TZID:Europe/Paris
|
||||||
|
X-LIC-LOCATION:Europe/Paris
|
||||||
|
BEGIN:DAYLIGHT
|
||||||
|
TZOFFSETFROM:+0100
|
||||||
|
TZOFFSETTO:+0200
|
||||||
|
TZNAME:CEST
|
||||||
|
DTSTART:19700329T020000
|
||||||
|
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
|
||||||
|
END:DAYLIGHT
|
||||||
|
BEGIN:STANDARD
|
||||||
|
TZOFFSETFROM:+0200
|
||||||
|
TZOFFSETTO:+0100
|
||||||
|
TZNAME:CET
|
||||||
|
DTSTART:19701025T030000
|
||||||
|
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
|
||||||
|
END:STANDARD
|
||||||
|
END:VTIMEZONE
|
||||||
|
BEGIN:VEVENT
|
||||||
|
DTSTART;TZID=Europe/Paris:20100526T143000
|
||||||
|
DTEND;TZID=Europe/Paris:20100526T171500
|
||||||
|
DTSTAMP:20101028T215738Z
|
||||||
|
UID:ptb5jqomu2vu0sr2nm24qungag@google.com
|
||||||
|
ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Partic
|
||||||
|
uliers - Grand Tour du Bassin;X-NUM-GUESTS=0:mailto:l2n7ajiud0oaiua4qcdarg1
|
||||||
|
krg@group.calendar.google.com
|
||||||
|
RECURRENCE-ID;TZID=Europe/Paris:20100526T143000
|
||||||
|
CREATED:20100428T225030Z
|
||||||
|
DESCRIPTION:
|
||||||
|
LAST-MODIFIED:20100527T102538Z
|
||||||
|
LOCATION:Jetée Thiers\, Arcachon
|
||||||
|
SEQUENCE:0
|
||||||
|
STATUS:CONFIRMED
|
||||||
|
SUMMARY:Horaire
|
||||||
|
TRANSP:TRANSPARENT
|
||||||
|
END:VEVENT
|
||||||
|
BEGIN:VEVENT
|
||||||
|
DTSTART;TZID=Europe/Paris:20100403T143000
|
||||||
|
DTEND;TZID=Europe/Paris:20100403T171500
|
||||||
|
RRULE:FREQ=WEEKLY;WKST=MO;UNTIL=20100630T123000Z;BYDAY=SU,WE,SA
|
||||||
|
DTSTAMP:20101028T215738Z
|
||||||
|
UID:ptb5jqomu2vu0sr2nm24qungag@google.com
|
||||||
|
ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Partic
|
||||||
|
uliers - Grand Tour du Bassin;X-NUM-GUESTS=0:mailto:l2n7ajiud0oaiua4qcdarg1
|
||||||
|
krg@group.calendar.google.com
|
||||||
|
CREATED:20100428T225030Z
|
||||||
|
DESCRIPTION:
|
||||||
|
LAST-MODIFIED:20100518T052328Z
|
||||||
|
LOCATION:Jetée Thiers\, Arcachon
|
||||||
|
SEQUENCE:0
|
||||||
|
STATUS:CONFIRMED
|
||||||
|
SUMMARY:Horaire
|
||||||
|
TRANSP:TRANSPARENT
|
||||||
|
END:VEVENT
|
||||||
|
BEGIN:VEVENT
|
||||||
|
DTSTART;TZID=Europe/Paris:20101002T143000
|
||||||
|
DTEND;TZID=Europe/Paris:20101002T171500
|
||||||
|
RRULE:FREQ=WEEKLY;BYDAY=SU,SA;WKST=MO
|
||||||
|
DTSTAMP:20101028T215738Z
|
||||||
|
UID:41v060qrjvpvsv90n6ulljjeg4@google.com
|
||||||
|
CREATED:20100428T225427Z
|
||||||
|
DESCRIPTION:
|
||||||
|
LAST-MODIFIED:20100518T052328Z
|
||||||
|
LOCATION:Jetée Thiers\, Arcachon
|
||||||
|
SEQUENCE:0
|
||||||
|
STATUS:CONFIRMED
|
||||||
|
SUMMARY:Horaire
|
||||||
|
TRANSP:TRANSPARENT
|
||||||
|
END:VEVENT
|
||||||
|
BEGIN:VEVENT
|
||||||
|
DTSTART;TZID=Europe/Paris:20100703T143000
|
||||||
|
DTEND;TZID=Europe/Paris:20100703T171500
|
||||||
|
RRULE:FREQ=DAILY;UNTIL=20100930T123000Z;WKST=MO
|
||||||
|
DTSTAMP:20101028T215738Z
|
||||||
|
UID:92tmcm95ktr40ofn3okf0hhr2c@google.com
|
||||||
|
CREATED:20100428T225334Z
|
||||||
|
DESCRIPTION:
|
||||||
|
LAST-MODIFIED:20100518T052327Z
|
||||||
|
LOCATION:Jetée Thiers\, Arcachon
|
||||||
|
SEQUENCE:0
|
||||||
|
STATUS:CONFIRMED
|
||||||
|
SUMMARY:Horaire
|
||||||
|
TRANSP:TRANSPARENT
|
||||||
|
END:VEVENT
|
||||||
|
BEGIN:VEVENT
|
||||||
|
DTSTART:20100513T123000Z
|
||||||
|
DTEND:20100513T151500Z
|
||||||
|
DTSTAMP:20101028T215738Z
|
||||||
|
UID:254jd6v58v92k7bj69sgu3ulb0@google.com
|
||||||
|
CREATED:20100428T225221Z
|
||||||
|
DESCRIPTION:
|
||||||
|
LAST-MODIFIED:20100518T052327Z
|
||||||
|
LOCATION:Jetée Thiers\, Arcachon
|
||||||
|
SEQUENCE:0
|
||||||
|
STATUS:CONFIRMED
|
||||||
|
SUMMARY:Horaire
|
||||||
|
TRANSP:TRANSPARENT
|
||||||
|
END:VEVENT
|
||||||
|
END:VCALENDAR
|
|
@ -0,0 +1,43 @@
|
||||||
|
BEGIN:VCALENDAR
|
||||||
|
PRODID:-//Google Inc//Google Calendar 70.9054//EN
|
||||||
|
VERSION:2.0
|
||||||
|
CALSCALE:GREGORIAN
|
||||||
|
METHOD:PUBLISH
|
||||||
|
X-WR-CALNAME:uba.gestion@gmail.com
|
||||||
|
X-WR-TIMEZONE:Europe/Paris
|
||||||
|
BEGIN:VTIMEZONE
|
||||||
|
TZID:Europe/Paris
|
||||||
|
X-LIC-LOCATION:Europe/Paris
|
||||||
|
BEGIN:DAYLIGHT
|
||||||
|
TZOFFSETFROM:+0100
|
||||||
|
TZOFFSETTO:+0200
|
||||||
|
TZNAME:CEST
|
||||||
|
DTSTART:19700329T020000
|
||||||
|
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
|
||||||
|
END:DAYLIGHT
|
||||||
|
BEGIN:STANDARD
|
||||||
|
TZOFFSETFROM:+0200
|
||||||
|
TZOFFSETTO:+0100
|
||||||
|
TZNAME:CET
|
||||||
|
DTSTART:19701025T030000
|
||||||
|
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
|
||||||
|
END:STANDARD
|
||||||
|
END:VTIMEZONE
|
||||||
|
BEGIN:VEVENT
|
||||||
|
DTSTART;VALUE=DATE:20100907
|
||||||
|
DTEND;VALUE=DATE:20100908
|
||||||
|
RRULE:FREQ=DAILY;UNTIL=20100912
|
||||||
|
EXDATE;VALUE=DATE:20100911
|
||||||
|
EXDATE;VALUE=DATE:20100909,20100910
|
||||||
|
DTSTAMP:20101031T155459Z
|
||||||
|
UID:5oo2ridecth26kcavj8elhtd4s@google.com
|
||||||
|
CREATED:00001231T000000Z
|
||||||
|
DESCRIPTION:
|
||||||
|
LAST-MODIFIED:20101030T193954Z
|
||||||
|
LOCATION:
|
||||||
|
SEQUENCE:1
|
||||||
|
STATUS:CONFIRMED
|
||||||
|
SUMMARY:occur
|
||||||
|
TRANSP:TRANSPARENT
|
||||||
|
END:VEVENT
|
||||||
|
END:VCALENDAR
|
|
@ -0,0 +1,615 @@
|
||||||
|
/*
|
||||||
|
* FullCalendar v1.4.8-IE9 Stylesheet
|
||||||
|
*
|
||||||
|
* Feel free to edit this file to customize the look of FullCalendar.
|
||||||
|
* When upgrading to newer versions, please upgrade this file as well,
|
||||||
|
* porting over any customizations afterwards.
|
||||||
|
*
|
||||||
|
* Date: Mon Oct 25 02:35:06 2010 +0200
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* TODO: make font sizes look the same in all doctypes */
|
||||||
|
|
||||||
|
|
||||||
|
.fc,
|
||||||
|
.fc .fc-header,
|
||||||
|
.fc .fc-content {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc {
|
||||||
|
direction: ltr;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc td, .fc th {
|
||||||
|
padding: 0;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Header
|
||||||
|
------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
table.fc-header {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-header-left {
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-header-left table {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-header-center {
|
||||||
|
width: 50%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-header-center table {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-header-right {
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-header-right table {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-header-title {
|
||||||
|
margin-top: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-header-space {
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* right-to-left */
|
||||||
|
|
||||||
|
.fc-rtl .fc-header-title {
|
||||||
|
direction: rtl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Buttons
|
||||||
|
------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
.fc-header .fc-state-default,
|
||||||
|
.fc-header .ui-state-default {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-header .fc-state-default {
|
||||||
|
border-width: 1px 0;
|
||||||
|
padding: 0 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-header .fc-state-default,
|
||||||
|
.fc-header .fc-state-default a {
|
||||||
|
border-style: solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-header .fc-state-default a {
|
||||||
|
display: block;
|
||||||
|
border-width: 0 1px;
|
||||||
|
margin: 0 -1px;
|
||||||
|
width: 100%;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-header .fc-state-default span {
|
||||||
|
display: block;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px 0 1px 1px;
|
||||||
|
padding: 3px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-header .ui-state-default {
|
||||||
|
padding: 4px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-header .fc-state-default span,
|
||||||
|
.fc-header .ui-state-default span {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for adjacent buttons */
|
||||||
|
|
||||||
|
.fc-header .fc-no-right {
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-header .fc-no-right a {
|
||||||
|
margin-right: 0;
|
||||||
|
border-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-header .ui-no-right {
|
||||||
|
border-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for fake rounded corners */
|
||||||
|
|
||||||
|
.fc-header .fc-corner-left {
|
||||||
|
margin-left: 1px;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-header .fc-corner-right {
|
||||||
|
margin-right: 1px;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DEFAULT button COLORS */
|
||||||
|
|
||||||
|
.fc-header .fc-state-default,
|
||||||
|
.fc-header .fc-state-default a {
|
||||||
|
border-color: #777; /* outer border */
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-header .fc-state-default span {
|
||||||
|
border-color: #fff #fff #d1d1d1; /* inner border */
|
||||||
|
background: #e8e8e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PRESSED button COLORS (down and active) */
|
||||||
|
|
||||||
|
.fc-header .fc-state-active a {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-header .fc-state-down span,
|
||||||
|
.fc-header .fc-state-active span {
|
||||||
|
background: #888;
|
||||||
|
border-color: #808080 #808080 #909090; /* inner border */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DISABLED button COLORS */
|
||||||
|
|
||||||
|
.fc-header .fc-state-disabled a {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-header .fc-state-disabled,
|
||||||
|
.fc-header .fc-state-disabled a {
|
||||||
|
border-color: #ccc; /* outer border */
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-header .fc-state-disabled span {
|
||||||
|
border-color: #fff #fff #f0f0f0; /* inner border */
|
||||||
|
background: #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Content Area & Global Cell Styles
|
||||||
|
------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
.fc-widget-content {
|
||||||
|
border: 1px solid #ccc; /* outer border color */
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-content {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-content .fc-state-default {
|
||||||
|
border-style: solid;
|
||||||
|
border-color: #ccc; /* inner border color */
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-content .ui-state-highlight,
|
||||||
|
.fc-content .fc-state-highlight { /* today */
|
||||||
|
background: #ffd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-content .fc-not-today { /* override jq-ui highlight (TODO: ui-widget-content) */
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-content .fc-before-today {
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-cell-overlay { /* semi-transparent rectangle while dragging */
|
||||||
|
background: #9cf;
|
||||||
|
opacity: .2;
|
||||||
|
filter: alpha(opacity=20); /* for IE */
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-view { /* prevents dragging outside of widget */
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Global Event Styles
|
||||||
|
------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
.fc-event,
|
||||||
|
.fc-agenda .fc-event-time,
|
||||||
|
.fc-event a {
|
||||||
|
border-style: solid;
|
||||||
|
border-color: #36c; /* default BORDER color (probably the same as background-color) */
|
||||||
|
background-color: #36c; /* default BACKGROUND color */
|
||||||
|
color: #fff; /* default TEXT color */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use the 'className' CalEvent property and the following
|
||||||
|
* example CSS to change event color on a per-event basis:
|
||||||
|
*
|
||||||
|
* .myclass,
|
||||||
|
* .fc-agenda .myclass .fc-event-time,
|
||||||
|
* .myclass a {
|
||||||
|
* background-color: black;
|
||||||
|
* border-color: black;
|
||||||
|
* color: red;
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
.fc-event {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-event a {
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: .85em;
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-event-editable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-event-time,
|
||||||
|
.fc-event-title {
|
||||||
|
padding: 0 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for fake rounded corners */
|
||||||
|
|
||||||
|
.fc-event a {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* right-to-left */
|
||||||
|
|
||||||
|
.fc-rtl .fc-event a {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* resizable */
|
||||||
|
|
||||||
|
.fc .ui-resizable-handle {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 99999;
|
||||||
|
border: 0 !important; /* important overrides pre jquery ui 1.7 styles */
|
||||||
|
background: url(data:image/gif;base64,AAAA) !important; /* hover fix for IE */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Horizontal Events
|
||||||
|
------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
.fc-event-hori {
|
||||||
|
border-width: 1px 0;
|
||||||
|
margin-bottom: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-event-hori a {
|
||||||
|
border-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for fake rounded corners */
|
||||||
|
|
||||||
|
.fc-content .fc-corner-left {
|
||||||
|
margin-left: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-content .fc-corner-left a {
|
||||||
|
margin-left: -1px;
|
||||||
|
border-left-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-content .fc-corner-right {
|
||||||
|
margin-right: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-content .fc-corner-right a {
|
||||||
|
margin-right: -1px;
|
||||||
|
border-right-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* resizable */
|
||||||
|
|
||||||
|
.fc-event-hori .ui-resizable-e {
|
||||||
|
top: 0 !important; /* importants override pre jquery ui 1.7 styles */
|
||||||
|
right: -3px !important;
|
||||||
|
width: 7px !important;
|
||||||
|
height: 100% !important;
|
||||||
|
cursor: e-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-event-hori .ui-resizable-w {
|
||||||
|
top: 0 !important;
|
||||||
|
left: -3px !important;
|
||||||
|
width: 7px !important;
|
||||||
|
height: 100% !important;
|
||||||
|
cursor: w-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-event-hori .ui-resizable-handle {
|
||||||
|
_padding-bottom: 14px; /* IE6 had 0 height */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Month View, Basic Week View, Basic Day View
|
||||||
|
------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
.fc-grid table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc .fc-grid th {
|
||||||
|
border-width: 0 0 0 1px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc .fc-grid td {
|
||||||
|
border-width: 1px 0 0 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-grid th.fc-leftmost,
|
||||||
|
.fc-grid td.fc-leftmost {
|
||||||
|
border-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-grid .fc-day-number {
|
||||||
|
float: right;
|
||||||
|
padding: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-grid .fc-other-month .fc-day-number {
|
||||||
|
opacity: 0.3;
|
||||||
|
filter: alpha(opacity=30); /* for IE */
|
||||||
|
/* opacity with small font can sometimes look too faded
|
||||||
|
might want to set the 'color' property instead
|
||||||
|
making day-numbers bold also fixes the problem */
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-grid .fc-day-content {
|
||||||
|
clear: both;
|
||||||
|
padding: 2px 2px 0; /* distance between events and day edges */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* event styles */
|
||||||
|
|
||||||
|
.fc-grid .fc-event-time {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* right-to-left */
|
||||||
|
|
||||||
|
.fc-rtl .fc-grid {
|
||||||
|
direction: rtl;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-rtl .fc-grid .fc-day-number {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-rtl .fc-grid .fc-event-time {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* week numbers */
|
||||||
|
|
||||||
|
.fc .fc-grid th.fc-weeknumber {
|
||||||
|
border-top-width: 1px;
|
||||||
|
}
|
||||||
|
/* Agenda Week View, Agenda Day View
|
||||||
|
------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
.fc .fc-agenda th,
|
||||||
|
.fc .fc-agenda td {
|
||||||
|
border-width: 1px 0 0 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc .fc-agenda .fc-leftmost {
|
||||||
|
border-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-agenda tr.fc-first th,
|
||||||
|
.fc-agenda tr.fc-first td {
|
||||||
|
border-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-agenda-head tr.fc-last th {
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc .fc-agenda-head td,
|
||||||
|
.fc .fc-agenda-body td {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-agenda-head th {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the time axis running down the left side */
|
||||||
|
|
||||||
|
.fc-agenda .fc-axis {
|
||||||
|
width: 50px;
|
||||||
|
padding: 0 4px;
|
||||||
|
vertical-align: middle;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-align: right;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* all-day event cells at top */
|
||||||
|
|
||||||
|
.fc-agenda-head tr.fc-all-day th {
|
||||||
|
height: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-agenda-head td {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc .fc-divider div {
|
||||||
|
font-size: 1px; /* for IE6/7 */
|
||||||
|
height: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc .fc-divider .fc-state-default {
|
||||||
|
background: #eee; /* color for divider between all-day and time-slot events */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* body styles */
|
||||||
|
|
||||||
|
.fc .fc-agenda-body td div {
|
||||||
|
height: 20px; /* slot height */
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc .fc-agenda-body tr.fc-minor th,
|
||||||
|
.fc .fc-agenda-body tr.fc-minor td {
|
||||||
|
border-top-style: dotted;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-agenda .fc-day-content {
|
||||||
|
padding: 2px 2px 0; /* distance between events and day edges */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vertical background columns */
|
||||||
|
|
||||||
|
.fc .fc-agenda-bg .ui-state-highlight {
|
||||||
|
background-image: none; /* tall column, don't want repeating background image */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Vertical Events
|
||||||
|
------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
.fc-event-vert {
|
||||||
|
border-width: 0 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-event-vert a {
|
||||||
|
border-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for fake rounded corners */
|
||||||
|
|
||||||
|
.fc-content .fc-corner-top {
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-content .fc-corner-top a {
|
||||||
|
margin-top: -1px;
|
||||||
|
border-top-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-content .fc-corner-bottom {
|
||||||
|
margin-bottom: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-content .fc-corner-bottom a {
|
||||||
|
margin-bottom: -1px;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* event content */
|
||||||
|
|
||||||
|
.fc-event-vert span {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-event-vert span.fc-event-time {
|
||||||
|
white-space: nowrap;
|
||||||
|
_white-space: normal;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 0;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-event-vert span.fc-event-title {
|
||||||
|
line-height: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-event-vert span.fc-event-bg { /* makes the event lighter w/ a semi-transparent overlay */
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: #fff;
|
||||||
|
opacity: .3;
|
||||||
|
filter: alpha(opacity=30); /* for IE */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* resizable */
|
||||||
|
|
||||||
|
.fc-event-vert .ui-resizable-s {
|
||||||
|
bottom: 0 !important; /* importants override pre jquery ui 1.7 styles */
|
||||||
|
width: 100% !important;
|
||||||
|
height: 8px !important;
|
||||||
|
line-height: 8px !important;
|
||||||
|
font-size: 11px !important;
|
||||||
|
font-family: monospace;
|
||||||
|
text-align: center;
|
||||||
|
cursor: s-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* JOMRES */
|
||||||
|
.gcal-blackbooking-0,
|
||||||
|
.fc-agenda .gcal-blackbooking-0 .fc-event-time,
|
||||||
|
.gcal-blackbooking-0 a {
|
||||||
|
border-style: solid;
|
||||||
|
border-color: #400; /* default BORDER color (probably the same as background-color) */
|
||||||
|
background-color: #D60; /* default BACKGROUND color */
|
||||||
|
color: #fff; /* default TEXT color */
|
||||||
|
}
|
||||||
|
|
||||||
|
.gcal-blackbooking-1,
|
||||||
|
.fc-agenda .gcal-blackbooking-1 .fc-event-time,
|
||||||
|
.gcal-blackbooking-1 a {
|
||||||
|
border-style: solid;
|
||||||
|
border-color: #400; /* default BORDER color (probably the same as background-color) */
|
||||||
|
background-color: #800; /* default BACKGROUND color */
|
||||||
|
color: #fff; /* default TEXT color */
|
||||||
|
}
|
Plik diff jest za duży
Load Diff
|
@ -0,0 +1,122 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once('../SG_iCal.php');
|
||||||
|
|
||||||
|
function dump_t($x) {
|
||||||
|
echo "<pre>".print_r($x,true)."</pre>";
|
||||||
|
}
|
||||||
|
$ICS = "exdate.ics";
|
||||||
|
//echo dump_t(file_get_contents($ICS));
|
||||||
|
|
||||||
|
$ical = new SG_iCalReader($ICS);
|
||||||
|
$query = new SG_iCal_Query();
|
||||||
|
|
||||||
|
$evts = $ical->getEvents();
|
||||||
|
//$evts = $query->Between($ical,strtotime('20100901'),strtotime('20101131'));
|
||||||
|
|
||||||
|
|
||||||
|
$data = array();
|
||||||
|
foreach($evts as $id => $ev) {
|
||||||
|
$jsEvt = array(
|
||||||
|
"id" => ($id+1),
|
||||||
|
"title" => $ev->getProperty('summary'),
|
||||||
|
"start" => $ev->getStart(),
|
||||||
|
"end" => $ev->getEnd()-1,
|
||||||
|
"allDay" => $ev->isWholeDay()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isset($ev->recurrence)) {
|
||||||
|
$count = 0;
|
||||||
|
$start = $ev->getStart();
|
||||||
|
$freq = $ev->getFrequency();
|
||||||
|
if ($freq->firstOccurrence() == $start)
|
||||||
|
$data[] = $jsEvt;
|
||||||
|
while (($next = $freq->nextOccurrence($start)) > 0 ) {
|
||||||
|
if (!$next or $count >= 1000) break;
|
||||||
|
$count++;
|
||||||
|
$start = $next;
|
||||||
|
$jsEvt["start"] = $start;
|
||||||
|
$jsEvt["end"] = $start + $ev->getDuration()-1;
|
||||||
|
|
||||||
|
$data[] = $jsEvt;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
$data[] = $jsEvt;
|
||||||
|
|
||||||
|
}
|
||||||
|
//echo(date('Ymd\n',$data[0][start]));
|
||||||
|
//echo(date('Ymd\n',$data[1][start]));
|
||||||
|
//dump_t($data);
|
||||||
|
|
||||||
|
$events = "events:".json_encode($data).',';
|
||||||
|
|
||||||
|
?>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<title>Fullcalendar iCal Loader</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="fullcalendar.css">
|
||||||
|
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
|
||||||
|
<script type="text/javascript" src="fullcalendar.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
|
||||||
|
$('#calendar').fullCalendar({
|
||||||
|
header: {
|
||||||
|
left: 'prev,next today',
|
||||||
|
center: 'title',
|
||||||
|
right: 'month,agendaWeek,agendaDay'
|
||||||
|
},
|
||||||
|
|
||||||
|
year: 2010,
|
||||||
|
month: 9-1,
|
||||||
|
|
||||||
|
// US Holidays
|
||||||
|
//events: $.fullCalendar.gcalFeed('http://www.google.com/calendar/feeds/usa__en%40holiday.calendar.google.com/public/basic'),
|
||||||
|
|
||||||
|
<?=$events ?>
|
||||||
|
|
||||||
|
eventClick: function(event) {
|
||||||
|
// opens events in a popup window
|
||||||
|
window.open(event.url, 'gcalevent', 'width=700,height=600');
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
loading: function(bool) {
|
||||||
|
if (bool) {
|
||||||
|
$('#loading').show();
|
||||||
|
}else{
|
||||||
|
$('#loading').hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style type='text/css'>
|
||||||
|
body div {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
|
||||||
|
}
|
||||||
|
div#loading {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
right: 5px;
|
||||||
|
}
|
||||||
|
div#calendar {
|
||||||
|
width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="loading" style="display:none;">loading...</div>
|
||||||
|
<div id="calendar"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -9,8 +9,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class SG_iCal_Duration {
|
class SG_iCal_Duration {
|
||||||
private $dur;
|
protected $dur;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new SG_iCal_Duration from a duration-rule.
|
* Constructs a new SG_iCal_Duration from a duration-rule.
|
||||||
* The basic build-up of DURATIONs are:
|
* The basic build-up of DURATIONs are:
|
||||||
|
@ -20,30 +20,32 @@ class SG_iCal_Duration {
|
||||||
* @param $duration string
|
* @param $duration string
|
||||||
*/
|
*/
|
||||||
public function __construct( $duration ) {
|
public function __construct( $duration ) {
|
||||||
if( $duration{0} == 'P' || (($duration{0} == '+' || $duration{0} == '-') && $duration{1} == 'P') ) {
|
|
||||||
preg_match('/P((\d+)W)?((\d+)D)?(T)?((\d+)H)?((\d+)M)?((\d+)S)?/', $duration, $matches);
|
$ts = 0;
|
||||||
$results = array('weeks'=>(int)$matches[2],
|
|
||||||
'days'=>(int)$matches[4],
|
if (preg_match('/[\\+\\-]{0,1}P((\d+)W)?((\d+)D)?(T)?((\d+)H)?((\d+)M)?((\d+)S)?/', $duration, $matches) === 1) {
|
||||||
'hours'=>(int)$matches[7],
|
$results = array(
|
||||||
'minutes'=>(int)$matches[9],
|
'weeks'=> (int)@ $matches[2],
|
||||||
'seconds'=>(int)$matches[11]);
|
'days'=> (int)@ $matches[4],
|
||||||
|
'hours'=> (int)@ $matches[7],
|
||||||
$ts = 0;
|
'minutes'=>(int)@ $matches[9],
|
||||||
|
'seconds'=>(int)@ $matches[11]
|
||||||
|
);
|
||||||
|
|
||||||
$ts += $results['seconds'];
|
$ts += $results['seconds'];
|
||||||
$ts += 60 * $results['minutes'];
|
$ts += 60 * $results['minutes'];
|
||||||
$ts += 60 * 60 * $results['hours'];
|
$ts += 60 * 60 * $results['hours'];
|
||||||
$ts += 24 * 60 * 60 * $results['days'];
|
$ts += 24 * 60 * 60 * $results['days'];
|
||||||
$ts += 7 * 24 * 60 * 60 * $results['weeks'];
|
$ts += 7 * 24 * 60 * 60 * $results['weeks'];
|
||||||
|
|
||||||
$dir = ($duration{0} == '-') ? -1 : 1;
|
|
||||||
|
|
||||||
$this->dur = $dir * $ts;
|
|
||||||
} else {
|
} else {
|
||||||
// Invalid duration!
|
// Invalid duration!
|
||||||
$this->dur = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$dir = ($duration{0} == '-') ? -1 : 1;
|
||||||
|
|
||||||
|
$this->dur = $dir * $ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the duration in seconds
|
* Returns the duration in seconds
|
||||||
* @return int
|
* @return int
|
||||||
|
|
|
@ -13,7 +13,7 @@ class SG_iCal_Factory {
|
||||||
/**
|
/**
|
||||||
* Returns a new block-object for the section/data-pair. The list
|
* Returns a new block-object for the section/data-pair. The list
|
||||||
* of returned objects is:
|
* of returned objects is:
|
||||||
*
|
*
|
||||||
* vcalendar => SG_iCal_VCalendar
|
* vcalendar => SG_iCal_VCalendar
|
||||||
* vtimezone => SG_iCal_VTimeZone
|
* vtimezone => SG_iCal_VTimeZone
|
||||||
* vevent => SG_iCal_VEvent
|
* vevent => SG_iCal_VEvent
|
||||||
|
@ -34,7 +34,7 @@ class SG_iCal_Factory {
|
||||||
case "vevent":
|
case "vevent":
|
||||||
require_once dirname(__FILE__).'/../blocks/SG_iCal_VEvent.php'; // BUILD: Remove line
|
require_once dirname(__FILE__).'/../blocks/SG_iCal_VEvent.php'; // BUILD: Remove line
|
||||||
return new SG_iCal_VEvent($data, $ical );
|
return new SG_iCal_VEvent($data, $ical );
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return new ArrayObject(SG_iCal_Line::Remove_Line((array) $data) );
|
return new ArrayObject(SG_iCal_Line::Remove_Line((array) $data) );
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<?php // BUILD: Remove line
|
<?php // BUILD: Remove line
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class to store Frequency-rules in. Will allow a easy way to find the
|
* A class to store Frequency-rules in. Will allow a easy way to find the
|
||||||
* last and next occurrence of the rule.
|
* last and next occurrence of the rule.
|
||||||
*
|
*
|
||||||
* No - this is so not pretty. But.. ehh.. You do it better, and I will
|
* No - this is so not pretty. But.. ehh.. You do it better, and I will
|
||||||
* gladly accept patches.
|
* gladly accept patches.
|
||||||
*
|
*
|
||||||
* Created by trail-and-error on the examples given in the RFC.
|
* Created by trail-and-error on the examples given in the RFC.
|
||||||
|
@ -12,10 +12,10 @@
|
||||||
* TODO: Update to a better way of doing calculating the different options.
|
* TODO: Update to a better way of doing calculating the different options.
|
||||||
* Instead of only keeping track of the best of the current dates found
|
* Instead of only keeping track of the best of the current dates found
|
||||||
* it should instead keep a array of all the calculated dates within the
|
* it should instead keep a array of all the calculated dates within the
|
||||||
* period.
|
* period.
|
||||||
* This should fix the issues with multi-rule + multi-rule interference,
|
* This should fix the issues with multi-rule + multi-rule interference,
|
||||||
* and make it possible to implement the SETPOS rule.
|
* and make it possible to implement the SETPOS rule.
|
||||||
* By pushing the next period onto the stack as the last option will
|
* By pushing the next period onto the stack as the last option will
|
||||||
* (hopefully) remove the need for the awful simpleMode
|
* (hopefully) remove the need for the awful simpleMode
|
||||||
*
|
*
|
||||||
* @package SG_iCalReader
|
* @package SG_iCalReader
|
||||||
|
@ -23,22 +23,31 @@
|
||||||
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
||||||
*/
|
*/
|
||||||
class SG_iCal_Freq {
|
class SG_iCal_Freq {
|
||||||
private $weekdays = array('MO'=>'monday', 'TU'=>'tuesday', 'WE'=>'wednesday', 'TH'=>'thursday', 'FR'=>'friday', 'SA'=>'saturday', 'SU'=>'sunday');
|
protected $weekdays = array('MO'=>'monday', 'TU'=>'tuesday', 'WE'=>'wednesday', 'TH'=>'thursday', 'FR'=>'friday', 'SA'=>'saturday', 'SU'=>'sunday');
|
||||||
private $knownRules = array('month', 'weekno', 'day', 'monthday', 'yearday', 'hour', 'minute');
|
protected $knownRules = array('month', 'weekno', 'day', 'monthday', 'yearday', 'hour', 'minute'); //others : 'setpos', 'second'
|
||||||
private $simpleMode = true;
|
protected $ruleModifiers = array('wkst');
|
||||||
|
protected $simpleMode = true;
|
||||||
private $rules = array('freq'=>'yearly', 'interval'=>1);
|
|
||||||
private $start = 0;
|
protected $rules = array('freq'=>'yearly', 'interval'=>1);
|
||||||
private $freq = '';
|
protected $start = 0;
|
||||||
|
protected $freq = '';
|
||||||
|
|
||||||
|
protected $excluded; //EXDATE
|
||||||
|
protected $added; //RDATE
|
||||||
|
|
||||||
|
protected $cache; // getAllOccurrences()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new Freqency-rule
|
* Constructs a new Freqency-rule
|
||||||
* @param $rule string
|
* @param $rule string
|
||||||
* @param $start int Unix-timestamp (important!)
|
* @param $start int Unix-timestamp (important : Need to be the start of Event)
|
||||||
|
* @param $excluded array of int (timestamps), see EXDATE documentation
|
||||||
|
* @param $added array of int (timestamps), see RDATE documentation
|
||||||
*/
|
*/
|
||||||
public function __construct( $rule, $start ) {
|
public function __construct( $rule, $start, $excluded=array(), $added=array()) {
|
||||||
$this->start = $start;
|
$this->start = $start;
|
||||||
|
$this->excluded = array();
|
||||||
|
|
||||||
$rules = array();
|
$rules = array();
|
||||||
foreach( explode(';', $rule) AS $v) {
|
foreach( explode(';', $rule) AS $v) {
|
||||||
list($k, $v) = explode('=', $v);
|
list($k, $v) = explode('=', $v);
|
||||||
|
@ -49,7 +58,6 @@ class SG_iCal_Freq {
|
||||||
$this->rules['until'] = strtotime($this->rules['until']);
|
$this->rules['until'] = strtotime($this->rules['until']);
|
||||||
}
|
}
|
||||||
$this->freq = strtolower($this->rules['freq']);
|
$this->freq = strtolower($this->rules['freq']);
|
||||||
|
|
||||||
|
|
||||||
foreach( $this->knownRules AS $rule ) {
|
foreach( $this->knownRules AS $rule ) {
|
||||||
if( isset($this->rules['by' . $rule]) ) {
|
if( isset($this->rules['by' . $rule]) ) {
|
||||||
|
@ -58,22 +66,64 @@ class SG_iCal_Freq {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$this->simpleMode) {
|
if(!$this->simpleMode) {
|
||||||
if(! (isset($this->rules['byday']) || isset($this->rules['bymonthday']) || isset($this->rules['byyearday']))) {
|
if(! (isset($this->rules['byday']) || isset($this->rules['bymonthday']) || isset($this->rules['byyearday']))) {
|
||||||
$this->rules['bymonthday'] = date('d', $this->start);
|
$this->rules['bymonthday'] = date('d', $this->start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//set until, and cache
|
||||||
if( isset($this->rules['count']) ) {
|
if( isset($this->rules['count']) ) {
|
||||||
$n = $start;
|
|
||||||
for($i=0;$i<$this->rules['count'];$i++) {
|
$cache[$ts] = $ts = $this->start;
|
||||||
$n = $this->findNext($n);
|
for($n=1; $n < $this->rules['count']; $n++) {
|
||||||
|
$ts = $this->findNext($ts);
|
||||||
|
$cache[$ts] = $ts;
|
||||||
}
|
}
|
||||||
$this->rules['until'] = $n;
|
$this->rules['until'] = $ts;
|
||||||
|
|
||||||
|
//EXDATE
|
||||||
|
if (!empty($excluded)) {
|
||||||
|
foreach($excluded as $ts) {
|
||||||
|
unset($cache[$ts]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//RDATE
|
||||||
|
if (!empty($added)) {
|
||||||
|
$cache = $cache + $added;
|
||||||
|
asort($cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->cache = array_values($cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->excluded = $excluded;
|
||||||
|
$this->added = $added;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all timestamps array(), build the cache if not made before
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAllOccurrences() {
|
||||||
|
if (empty($this->cache)) {
|
||||||
|
//build cache
|
||||||
|
$next = $this->firstOccurrence();
|
||||||
|
while ($next) {
|
||||||
|
$cache[] = $next;
|
||||||
|
$next = $this->findNext($next);
|
||||||
|
}
|
||||||
|
if (!empty($this->added)) {
|
||||||
|
$cache = $cache + $this->added;
|
||||||
|
asort($cache);
|
||||||
|
}
|
||||||
|
$this->cache = $cache;
|
||||||
|
}
|
||||||
|
return $this->cache;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the previous (most recent) occurrence of the rule from the
|
* Returns the previous (most recent) occurrence of the rule from the
|
||||||
* given offset
|
* given offset
|
||||||
|
@ -81,68 +131,95 @@ class SG_iCal_Freq {
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function previousOccurrence( $offset ) {
|
public function previousOccurrence( $offset ) {
|
||||||
$t1 = $this->start;
|
if (!empty($this->cache)) {
|
||||||
while( ($t2 = $this->findNext($t1)) < $offset) {
|
$t2=$this->start;
|
||||||
if( $t2 == false ){
|
foreach($this->cache as $ts) {
|
||||||
break;
|
if ($ts >= $offset)
|
||||||
|
return $t2;
|
||||||
|
$t2 = $ts;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$ts = $this->start;
|
||||||
|
while( ($t2 = $this->findNext($ts)) < $offset) {
|
||||||
|
if( $t2 == false ){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$ts = $t2;
|
||||||
}
|
}
|
||||||
$t1 = $t2;
|
|
||||||
}
|
}
|
||||||
return $t1;
|
return $ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the next occurrence of this rule after the given offset
|
* Returns the next occurrence of this rule after the given offset
|
||||||
* @param int $offset
|
* @param int $offset
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function nextOccurrence( $offset ) {
|
public function nextOccurrence( $offset ) {
|
||||||
return $this->findNext( $this->previousOccurrence( $offset) );
|
if ($offset < $this->start)
|
||||||
|
return $this->firstOccurrence();
|
||||||
|
return $this->findNext($offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the first occurrence of the rule.
|
||||||
|
* @return int timestamp
|
||||||
|
*/
|
||||||
|
public function firstOccurrence() {
|
||||||
|
$t = $this->start;
|
||||||
|
if (in_array($t, $this->excluded))
|
||||||
|
$t = $this->findNext($t);
|
||||||
|
return $t;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the absolute last occurrence of the rule from the given offset.
|
* Finds the absolute last occurrence of the rule from the given offset.
|
||||||
|
* Builds also the cache, if not set before...
|
||||||
* @return int timestamp
|
* @return int timestamp
|
||||||
*/
|
*/
|
||||||
public function lastOccurrence() {
|
public function lastOccurrence() {
|
||||||
$temp_timestamp = $this->findNext($this->start);
|
//build cache if not done
|
||||||
$timestamp = 0;
|
$this->getAllOccurrences();
|
||||||
while ($temp_timestamp) {
|
//return last timestamp in cache
|
||||||
$timestamp = $temp_timestamp;
|
return end($this->cache);
|
||||||
$temp_timestamp = $this->findNext($temp_timestamp);
|
|
||||||
}
|
|
||||||
return $timestamp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the next time after the given offset that the rule
|
* Calculates the next time after the given offset that the rule
|
||||||
* will apply.
|
* will apply.
|
||||||
*
|
*
|
||||||
* The approach to finding the next is as follows:
|
* The approach to finding the next is as follows:
|
||||||
* First we establish a timeframe to find timestamps in. This is
|
* First we establish a timeframe to find timestamps in. This is
|
||||||
* between $offset and the end of the period that $offset is in.
|
* between $offset and the end of the period that $offset is in.
|
||||||
*
|
*
|
||||||
* We then loop though all the rules (that is a Prerule in the
|
* We then loop though all the rules (that is a Prerule in the
|
||||||
* current freq.), and finds the smallest timestamp inside the
|
* current freq.), and finds the smallest timestamp inside the
|
||||||
* timeframe.
|
* timeframe.
|
||||||
*
|
*
|
||||||
* If we find something, we check if the date is a valid recurrence
|
* If we find something, we check if the date is a valid recurrence
|
||||||
* (with validDate). If it is, we return it. Otherwise we try to
|
* (with validDate). If it is, we return it. Otherwise we try to
|
||||||
* find a new date inside the same timeframe (but using the new-
|
* find a new date inside the same timeframe (but using the new-
|
||||||
* found date as offset)
|
* found date as offset)
|
||||||
*
|
*
|
||||||
* If no new timestamps were found in the period, we try in the
|
* If no new timestamps were found in the period, we try in the
|
||||||
* next period
|
* next period
|
||||||
*
|
*
|
||||||
* @param int $offset
|
* @param int $offset
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function findNext($offset) {
|
public function findNext($offset) {
|
||||||
$echo = false;
|
if (!empty($this->cache)) {
|
||||||
|
foreach($this->cache as $ts) {
|
||||||
|
if ($ts > $offset)
|
||||||
|
return $ts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$debug = false;
|
||||||
|
|
||||||
//make sure the offset is valid
|
//make sure the offset is valid
|
||||||
if( $offset === false || (isset($this->rules['until']) && $this->rules['until'] <= $offset) ) {
|
if( $offset === false || (isset($this->rules['until']) && $offset > $this->rules['until']) ) {
|
||||||
if($echo) echo 'STOP: ' . date('r', $offset) . "\n";
|
if($debug) echo 'STOP: ' . date('r', $offset) . "\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,26 +227,29 @@ class SG_iCal_Freq {
|
||||||
|
|
||||||
//set the timestamp of the offset (ignoring hours and minutes unless we want them to be
|
//set the timestamp of the offset (ignoring hours and minutes unless we want them to be
|
||||||
//part of the calculations.
|
//part of the calculations.
|
||||||
if($echo) echo 'O: ' . date('r', $offset) . "\n";
|
if($debug) echo 'O: ' . date('r', $offset) . "\n";
|
||||||
$hour = (in_array($this->freq, array('hourly','minutely')) && $offset > $this->start) ? date('H', $offset) : date('H', $this->start);
|
$hour = (in_array($this->freq, array('hourly','minutely')) && $offset > $this->start) ? date('H', $offset) : date('H', $this->start);
|
||||||
$minute = (($this->freq == 'minutely' || isset($this->rules['byminute'])) && $offset > $this->start) ? date('i', $offset) : date('i', $this->start);
|
$minute = (($this->freq == 'minutely' || isset($this->rules['byminute'])) && $offset > $this->start) ? date('i', $offset) : date('i', $this->start);
|
||||||
$t = mktime($hour, $minute, date('s', $this->start), date('m', $offset), date('d', $offset), date('Y',$offset));
|
$t = mktime($hour, $minute, date('s', $this->start), date('m', $offset), date('d', $offset), date('Y',$offset));
|
||||||
if($echo) echo 'START: ' . date('r', $t) . "\n";
|
if($debug) echo 'START: ' . date('r', $t) . "\n";
|
||||||
|
|
||||||
if( $this->simpleMode ) {
|
if( $this->simpleMode ) {
|
||||||
if( $offset < $t ) {
|
if( $offset < $t ) {
|
||||||
return $t;
|
$ts = $t;
|
||||||
|
if ($ts && in_array($ts, $this->excluded))
|
||||||
|
$ts = $this->findNext($ts);
|
||||||
|
} else {
|
||||||
|
$ts = $this->findStartingPoint( $t, $this->rules['interval'], false );
|
||||||
|
if( !$this->validDate( $ts ) ) {
|
||||||
|
$ts = $this->findNext($ts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$next = $this->findStartingPoint( $t, $this->rules['interval'], false );
|
return $ts;
|
||||||
if( !$this->validDate( $next ) ) {
|
|
||||||
return $this->findNext($next);
|
|
||||||
}
|
|
||||||
return $next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$eop = $this->findEndOfPeriod($offset);
|
$eop = $this->findEndOfPeriod($offset);
|
||||||
if($echo) echo 'EOP: ' . date('r', $eop) . "\n";
|
if($debug) echo 'EOP: ' . date('r', $eop) . "\n";
|
||||||
|
|
||||||
foreach( $this->knownRules AS $rule ) {
|
foreach( $this->knownRules AS $rule ) {
|
||||||
if( $found && isset($this->rules['by' . $rule]) ) {
|
if( $found && isset($this->rules['by' . $rule]) ) {
|
||||||
if( $this->isPrerule($rule, $this->freq) ) {
|
if( $this->isPrerule($rule, $this->freq) ) {
|
||||||
|
@ -180,7 +260,7 @@ class SG_iCal_Freq {
|
||||||
if( $imm === false ) {
|
if( $imm === false ) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if($echo) echo strtoupper($rule) . ': ' . date('r', $imm) . ' A: ' . ((int) ($imm > $offset && $imm < $eop)) . "\n";
|
if($debug) echo strtoupper($rule) . ': ' . date('r', $imm) . ' A: ' . ((int) ($imm > $offset && $imm < $eop)) . "\n";
|
||||||
if( $imm > $offset && $imm < $eop && ($_t == null || $imm < $_t) ) {
|
if( $imm > $offset && $imm < $eop && ($_t == null || $imm < $_t) ) {
|
||||||
$_t = $imm;
|
$_t = $imm;
|
||||||
}
|
}
|
||||||
|
@ -194,22 +274,26 @@ class SG_iCal_Freq {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( $this->start > $offset && $this->start < $t ) {
|
if( $offset < $this->start && $this->start < $t ) {
|
||||||
return $this->start;
|
$ts = $this->start;
|
||||||
} else if( $found && ($t != $offset)) {
|
} else if( $found && ($t != $offset)) {
|
||||||
if( $this->validDate( $t ) ) {
|
if( $this->validDate( $t ) ) {
|
||||||
if($echo) echo 'OK' . "\n";
|
if($debug) echo 'OK' . "\n";
|
||||||
return $t;
|
$ts = $t;
|
||||||
} else {
|
} else {
|
||||||
if($echo) echo 'Invalid' . "\n";
|
if($debug) echo 'Invalid' . "\n";
|
||||||
return $this->findNext($t);
|
$ts = $this->findNext($t);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if($echo) echo 'Not found' . "\n";
|
if($debug) echo 'Not found' . "\n";
|
||||||
return $this->findNext( $this->findStartingPoint( $offset, $this->rules['interval'] ) );
|
$ts = $this->findNext( $this->findStartingPoint( $offset, $this->rules['interval'] ) );
|
||||||
}
|
}
|
||||||
|
if ($ts && in_array($ts, $this->excluded))
|
||||||
|
return $this->findNext($ts);
|
||||||
|
|
||||||
|
return $ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the starting point for the next rule. It goes $interval
|
* Finds the starting point for the next rule. It goes $interval
|
||||||
* 'freq' forward in time since the given offset
|
* 'freq' forward in time since the given offset
|
||||||
|
@ -229,14 +313,14 @@ class SG_iCal_Freq {
|
||||||
}
|
}
|
||||||
|
|
||||||
$sp = strtotime($t, $offset);
|
$sp = strtotime($t, $offset);
|
||||||
|
|
||||||
if( $truncate ) {
|
if( $truncate ) {
|
||||||
$sp = $this->truncateToPeriod($sp, $this->freq);
|
$sp = $this->truncateToPeriod($sp, $this->freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $sp;
|
return $sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the earliest timestamp posible outside this perioid
|
* Finds the earliest timestamp posible outside this perioid
|
||||||
* @param int $offset
|
* @param int $offset
|
||||||
|
@ -245,11 +329,11 @@ class SG_iCal_Freq {
|
||||||
public function findEndOfPeriod($offset) {
|
public function findEndOfPeriod($offset) {
|
||||||
return $this->findStartingPoint($offset, 1);
|
return $this->findStartingPoint($offset, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resets the timestamp to the beginning of the
|
* Resets the timestamp to the beginning of the
|
||||||
* period specified by freq
|
* period specified by freq
|
||||||
*
|
*
|
||||||
* Yes - the fall-through is on purpose!
|
* Yes - the fall-through is on purpose!
|
||||||
*
|
*
|
||||||
* @param int $time
|
* @param int $time
|
||||||
|
@ -283,7 +367,7 @@ class SG_iCal_Freq {
|
||||||
$d = mktime($date['hours'], $date['minutes'], $date['seconds'], $date['mon'], $date['mday'], $date['year']);
|
$d = mktime($date['hours'], $date['minutes'], $date['seconds'], $date['mon'], $date['mday'], $date['year']);
|
||||||
return $d;
|
return $d;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies the BYDAY rule to the given timestamp
|
* Applies the BYDAY rule to the given timestamp
|
||||||
* @param string $rule
|
* @param string $rule
|
||||||
|
@ -293,24 +377,24 @@ class SG_iCal_Freq {
|
||||||
private function ruleByday($rule, $t) {
|
private function ruleByday($rule, $t) {
|
||||||
$dir = ($rule{0} == '-') ? -1 : 1;
|
$dir = ($rule{0} == '-') ? -1 : 1;
|
||||||
$dir_t = ($dir == 1) ? 'next' : 'last';
|
$dir_t = ($dir == 1) ? 'next' : 'last';
|
||||||
|
|
||||||
|
|
||||||
$d = $this->weekdays[substr($rule,-2)];
|
$d = $this->weekdays[substr($rule,-2)];
|
||||||
$s = $dir_t . ' ' . $d . ' ' . date('H:i:s',$t);
|
$s = $dir_t . ' ' . $d . ' ' . date('H:i:s',$t);
|
||||||
|
|
||||||
if( $rule == substr($rule, -2) ) {
|
if( $rule == substr($rule, -2) ) {
|
||||||
if( date('l', $t) == ucfirst($d) ) {
|
if( date('l', $t) == ucfirst($d) ) {
|
||||||
$s = 'today ' . date('H:i:s',$t);
|
$s = 'today ' . date('H:i:s',$t);
|
||||||
}
|
}
|
||||||
|
|
||||||
$_t = strtotime($s, $t);
|
$_t = strtotime($s, $t);
|
||||||
|
|
||||||
if( $_t == $t && in_array($this->freq, array('monthly', 'yearly')) ) {
|
if( $_t == $t && in_array($this->freq, array('monthly', 'yearly')) ) {
|
||||||
// Yes. This is not a great idea.. but hey, it works.. for now
|
// Yes. This is not a great idea.. but hey, it works.. for now
|
||||||
$s = 'next ' . $d . ' ' . date('H:i:s',$t);
|
$s = 'next ' . $d . ' ' . date('H:i:s',$t);
|
||||||
$_t = strtotime($s, $_t);
|
$_t = strtotime($s, $_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $_t;
|
return $_t;
|
||||||
} else {
|
} else {
|
||||||
$_f = $this->freq;
|
$_f = $this->freq;
|
||||||
|
@ -323,10 +407,10 @@ class SG_iCal_Freq {
|
||||||
$_t = $this->truncateToPeriod($t, $this->freq);
|
$_t = $this->truncateToPeriod($t, $this->freq);
|
||||||
}
|
}
|
||||||
$this->freq = $_f;
|
$this->freq = $_f;
|
||||||
|
|
||||||
$c = preg_replace('/[^0-9]/','',$rule);
|
$c = preg_replace('/[^0-9]/','',$rule);
|
||||||
$c = ($c == '') ? 1 : $c;
|
$c = ($c == '') ? 1 : $c;
|
||||||
|
|
||||||
$n = $_t;
|
$n = $_t;
|
||||||
while($c > 0 ) {
|
while($c > 0 ) {
|
||||||
if( $dir == 1 && $c == 1 && date('l', $t) == ucfirst($d) ) {
|
if( $dir == 1 && $c == 1 && date('l', $t) == ucfirst($d) ) {
|
||||||
|
@ -335,11 +419,11 @@ class SG_iCal_Freq {
|
||||||
$n = strtotime($s, $n);
|
$n = strtotime($s, $n);
|
||||||
$c--;
|
$c--;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $n;
|
return $n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function ruleBymonth($rule, $t) {
|
private function ruleBymonth($rule, $t) {
|
||||||
$_t = mktime(date('H',$t), date('i',$t), date('s',$t), $rule, date('d', $t), date('Y', $t));
|
$_t = mktime(date('H',$t), date('i',$t), date('s',$t), $rule, date('d', $t), date('Y', $t));
|
||||||
if( $t == $_t && isset($this->rules['byday']) ) {
|
if( $t == $_t && isset($this->rules['byday']) ) {
|
||||||
|
@ -349,14 +433,14 @@ class SG_iCal_Freq {
|
||||||
return $_t;
|
return $_t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function ruleBymonthday($rule, $t) {
|
private function ruleBymonthday($rule, $t) {
|
||||||
if( $rule < 0 ) {
|
if( $rule < 0 ) {
|
||||||
$rule = date('t', $t) + $rule + 1;
|
$rule = date('t', $t) + $rule + 1;
|
||||||
}
|
}
|
||||||
return mktime(date('H',$t), date('i',$t), date('s',$t), date('m', $t), $rule, date('Y', $t));
|
return mktime(date('H',$t), date('i',$t), date('s',$t), date('m', $t), $rule, date('Y', $t));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function ruleByyearday($rule, $t) {
|
private function ruleByyearday($rule, $t) {
|
||||||
if( $rule < 0 ) {
|
if( $rule < 0 ) {
|
||||||
$_t = $this->findEndOfPeriod();
|
$_t = $this->findEndOfPeriod();
|
||||||
|
@ -376,12 +460,12 @@ class SG_iCal_Freq {
|
||||||
} else {
|
} else {
|
||||||
$_t = $this->truncateToPeriod($t, $this->freq);
|
$_t = $this->truncateToPeriod($t, $this->freq);
|
||||||
$d = '+';
|
$d = '+';
|
||||||
}
|
}
|
||||||
|
|
||||||
$sub = (date('W', $_t) == 1) ? 2 : 1;
|
$sub = (date('W', $_t) == 1) ? 2 : 1;
|
||||||
$s = $d . abs($rule - $sub) . ' weeks ' . date('H:i:s',$t);
|
$s = $d . abs($rule - $sub) . ' weeks ' . date('H:i:s',$t);
|
||||||
$_t = strtotime($s, $_t);
|
$_t = strtotime($s, $_t);
|
||||||
|
|
||||||
return $_t;
|
return $_t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,17 +473,21 @@ class SG_iCal_Freq {
|
||||||
$_t = mktime($rule, date('i',$t), date('s',$t), date('m',$t), date('d', $t), date('Y', $t));
|
$_t = mktime($rule, date('i',$t), date('s',$t), date('m',$t), date('d', $t), date('Y', $t));
|
||||||
return $_t;
|
return $_t;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function ruleByminute($rule, $t) {
|
private function ruleByminute($rule, $t) {
|
||||||
$_t = mktime(date('h',$t), $rule, date('s',$t), date('m',$t), date('d', $t), date('Y', $t));
|
$_t = mktime(date('h',$t), $rule, date('s',$t), date('m',$t), date('d', $t), date('Y', $t));
|
||||||
return $_t;
|
return $_t;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function validDate( $t ) {
|
private function validDate( $t ) {
|
||||||
if( isset($this->rules['until']) && $this->rules['until'] <= $t ) {
|
if( isset($this->rules['until']) && $t > $this->rules['until'] ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (in_array($t, $this->excluded)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if( isset($this->rules['bymonth']) ) {
|
if( isset($this->rules['bymonth']) ) {
|
||||||
$months = explode(',', $this->rules['bymonth']);
|
$months = explode(',', $this->rules['bymonth']);
|
||||||
if( !in_array(date('m', $t), $months)) {
|
if( !in_array(date('m', $t), $months)) {
|
||||||
|
@ -438,10 +526,10 @@ class SG_iCal_Freq {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function isPrerule($rule, $freq) {
|
private function isPrerule($rule, $freq) {
|
||||||
if( $rule == 'year')
|
if( $rule == 'year')
|
||||||
return false;
|
return false;
|
||||||
|
@ -456,11 +544,11 @@ class SG_iCal_Freq {
|
||||||
return true;
|
return true;
|
||||||
if( $rule == 'day' && in_array($freq, array('yearly', 'monthly', 'weekly')))
|
if( $rule == 'day' && in_array($freq, array('yearly', 'monthly', 'weekly')))
|
||||||
return true;
|
return true;
|
||||||
if( $rule == 'hour' && in_array($freq, array('yearly', 'monthly', 'weekly', 'daily')))
|
if( $rule == 'hour' && in_array($freq, array('yearly', 'monthly', 'weekly', 'daily')))
|
||||||
return true;
|
return true;
|
||||||
if( $rule == 'minute' )
|
if( $rule == 'minute' )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* A class for storing a single (complete) line of the iCal file.
|
* A class for storing a single (complete) line of the iCal file.
|
||||||
* Will find the line-type, the arguments and the data of the file and
|
* Will find the line-type, the arguments and the data of the file and
|
||||||
* store them.
|
* store them.
|
||||||
*
|
*
|
||||||
* The line-type can be found by querying getIdent(), data via either
|
* The line-type can be found by querying getIdent(), data via either
|
||||||
* getData() or typecasting to a string.
|
* getData() or typecasting to a string.
|
||||||
* Params can be access via the ArrayAccess. A iterator is also avilable
|
* Params can be access via the ArrayAccess. A iterator is also avilable
|
||||||
|
@ -15,12 +15,12 @@
|
||||||
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
||||||
*/
|
*/
|
||||||
class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
||||||
private $ident;
|
protected $ident;
|
||||||
private $data;
|
protected $data;
|
||||||
private $params = array();
|
protected $params = array();
|
||||||
|
|
||||||
private $replacements = array('from'=>array('\\,', '\\n', '\\;', '\\:', '\\"'), 'to'=>array(',', "\n", ';', ':', '"'));
|
protected $replacements = array('from'=>array('\\,', '\\n', '\\;', '\\:', '\\"'), 'to'=>array(',', "\n", ';', ':', '"'));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new line.
|
* Constructs a new line.
|
||||||
*/
|
*/
|
||||||
|
@ -28,21 +28,21 @@ class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
||||||
$split = strpos($line, ':');
|
$split = strpos($line, ':');
|
||||||
$idents = explode(';', substr($line, 0, $split));
|
$idents = explode(';', substr($line, 0, $split));
|
||||||
$ident = strtolower(array_shift($idents));
|
$ident = strtolower(array_shift($idents));
|
||||||
|
|
||||||
$data = trim(substr($line, $split+1));
|
$data = trim(substr($line, $split+1));
|
||||||
$data = str_replace($this->replacements['from'], $this->replacements['to'], $data);
|
$data = str_replace($this->replacements['from'], $this->replacements['to'], $data);
|
||||||
|
|
||||||
$params = array();
|
$params = array();
|
||||||
foreach( $idents AS $v) {
|
foreach( $idents AS $v) {
|
||||||
list($k, $v) = explode('=', $v);
|
list($k, $v) = explode('=', $v);
|
||||||
$params[ strtolower($k) ] = $v;
|
$params[ strtolower($k) ] = $v;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->ident = $ident;
|
$this->ident = $ident;
|
||||||
$this->params = $params;
|
$this->params = $params;
|
||||||
$this->data = $data;
|
$this->data = $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this line the begining of a new block?
|
* Is this line the begining of a new block?
|
||||||
* @return bool
|
* @return bool
|
||||||
|
@ -50,7 +50,7 @@ class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
||||||
public function isBegin() {
|
public function isBegin() {
|
||||||
return $this->ident == 'begin';
|
return $this->ident == 'begin';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this line the end of a block?
|
* Is this line the end of a block?
|
||||||
* @return bool
|
* @return bool
|
||||||
|
@ -58,7 +58,7 @@ class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
||||||
public function isEnd() {
|
public function isEnd() {
|
||||||
return $this->ident == 'end';
|
return $this->ident == 'end';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the line-type (ident) of the line
|
* Returns the line-type (ident) of the line
|
||||||
* @return string
|
* @return string
|
||||||
|
@ -66,7 +66,7 @@ class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
||||||
public function getIdent() {
|
public function getIdent() {
|
||||||
return $this->ident;
|
return $this->ident;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the content of the line
|
* Returns the content of the line
|
||||||
* @return string
|
* @return string
|
||||||
|
@ -74,7 +74,19 @@ class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
||||||
public function getData() {
|
public function getData() {
|
||||||
return $this->data;
|
return $this->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the content of the line
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getDataAsArray() {
|
||||||
|
if (strpos($this->data,",") !== false) {
|
||||||
|
return explode(",",$this->data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return array($this->data);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A static helper to get a array of SG_iCal_Line's, and calls
|
* A static helper to get a array of SG_iCal_Line's, and calls
|
||||||
* getData() on each of them to lay the data "bare"..
|
* getData() on each of them to lay the data "bare"..
|
||||||
|
@ -95,14 +107,14 @@ class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
||||||
}
|
}
|
||||||
return $rtn;
|
return $rtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see ArrayAccess.offsetExists
|
* @see ArrayAccess.offsetExists
|
||||||
*/
|
*/
|
||||||
public function offsetExists( $param ) {
|
public function offsetExists( $param ) {
|
||||||
return isset($this->params[ strtolower($param) ]);
|
return isset($this->params[ strtolower($param) ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see ArrayAccess.offsetGet
|
* @see ArrayAccess.offsetGet
|
||||||
*/
|
*/
|
||||||
|
@ -112,7 +124,7 @@ class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
||||||
return $this->params[ $index ];
|
return $this->params[ $index ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disabled ArrayAccess requirement
|
* Disabled ArrayAccess requirement
|
||||||
* @see ArrayAccess.offsetSet
|
* @see ArrayAccess.offsetSet
|
||||||
|
@ -120,7 +132,7 @@ class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
||||||
public function offsetSet( $param, $val ) {
|
public function offsetSet( $param, $val ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disabled ArrayAccess requirement
|
* Disabled ArrayAccess requirement
|
||||||
* @see ArrayAccess.offsetUnset
|
* @see ArrayAccess.offsetUnset
|
||||||
|
@ -128,7 +140,7 @@ class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
||||||
public function offsetUnset( $param ) {
|
public function offsetUnset( $param ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* toString method.
|
* toString method.
|
||||||
* @see getData()
|
* @see getData()
|
||||||
|
@ -136,14 +148,14 @@ class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
||||||
public function __toString() {
|
public function __toString() {
|
||||||
return $this->getData();
|
return $this->getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Countable.count
|
* @see Countable.count
|
||||||
*/
|
*/
|
||||||
public function count() {
|
public function count() {
|
||||||
return count($this->params);
|
return count($this->params);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see IteratorAggregate.getIterator
|
* @see IteratorAggregate.getIterator
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?php
|
<?php // BUILD: Remove line
|
||||||
|
|
||||||
class SG_iCal_Parser {
|
class SG_iCal_Parser {
|
||||||
/**
|
/**
|
||||||
|
@ -11,7 +11,7 @@ class SG_iCal_Parser {
|
||||||
$content = self::UnfoldLines($content);
|
$content = self::UnfoldLines($content);
|
||||||
self::_Parse( $content, $ical );
|
self::_Parse( $content, $ical );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Passes a text string on to be parsed
|
* Passes a text string on to be parsed
|
||||||
* @param string $content
|
* @param string $content
|
||||||
|
@ -21,7 +21,7 @@ class SG_iCal_Parser {
|
||||||
$content = self::UnfoldLines($content);
|
$content = self::UnfoldLines($content);
|
||||||
self::_Parse( $content, $ical );
|
self::_Parse( $content, $ical );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches a resource and tries to make sure it's UTF8
|
* Fetches a resource and tries to make sure it's UTF8
|
||||||
* encoded
|
* encoded
|
||||||
|
@ -29,7 +29,7 @@ class SG_iCal_Parser {
|
||||||
*/
|
*/
|
||||||
protected static function Fetch( $resource ) {
|
protected static function Fetch( $resource ) {
|
||||||
$is_utf8 = true;
|
$is_utf8 = true;
|
||||||
|
|
||||||
if( is_file( $resource ) ) {
|
if( is_file( $resource ) ) {
|
||||||
// The resource is a local file
|
// The resource is a local file
|
||||||
$content = file_get_contents($resource);
|
$content = file_get_contents($resource);
|
||||||
|
@ -59,16 +59,16 @@ class SG_iCal_Parser {
|
||||||
$is_utf8 = false;
|
$is_utf8 = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !$is_utf8 ) {
|
if( !$is_utf8 ) {
|
||||||
$content = utf8_encode($content);
|
$content = utf8_encode($content);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes the string $content, and creates a array of iCal lines.
|
* Takes the string $content, and creates a array of iCal lines.
|
||||||
* This includes unfolding multi-line entries into a single line.
|
* This includes unfolding multi-line entries into a single line.
|
||||||
* @param $content string
|
* @param $content string
|
||||||
*/
|
*/
|
||||||
|
@ -93,6 +93,7 @@ class SG_iCal_Parser {
|
||||||
*/
|
*/
|
||||||
private static function _Parse( $content, SG_iCal $ical ) {
|
private static function _Parse( $content, SG_iCal $ical ) {
|
||||||
$main_sections = array('vevent', 'vjournal', 'vtodo', 'vtimezone', 'vcalendar');
|
$main_sections = array('vevent', 'vjournal', 'vtodo', 'vtimezone', 'vcalendar');
|
||||||
|
$array_idents = array('exdate','rdate');
|
||||||
$sections = array();
|
$sections = array();
|
||||||
$section = '';
|
$section = '';
|
||||||
$current_data = array();
|
$current_data = array();
|
||||||
|
@ -119,11 +120,16 @@ class SG_iCal_Parser {
|
||||||
if( array_search($s, $sections) !== false ) {
|
if( array_search($s, $sections) !== false ) {
|
||||||
// This section is in the main section
|
// This section is in the main section
|
||||||
if( $section == $s ) {
|
if( $section == $s ) {
|
||||||
// It _is_ the main section
|
// It _is_ the main section else
|
||||||
$current_data[$s][$line->getIdent()] = $line;
|
if (in_array($line->getIdent(), $array_idents))
|
||||||
|
//exdate could appears more that once
|
||||||
|
$current_data[$s][$line->getIdent()][] = $line;
|
||||||
|
else {
|
||||||
|
$current_data[$s][$line->getIdent()] = $line;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Sub section
|
// Sub section
|
||||||
$current_data[$s][$section][$line->getIdent()] = $line;
|
$current_data[$s][$section][$line->getIdent()] = $line;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -155,10 +161,10 @@ class SG_iCal_Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This functions does some regexp checking to see if the value is
|
* This functions does some regexp checking to see if the value is
|
||||||
* valid UTF-8.
|
* valid UTF-8.
|
||||||
*
|
*
|
||||||
* The function is from the book "Building Scalable Web Sites" by
|
* The function is from the book "Building Scalable Web Sites" by
|
||||||
* Cal Henderson.
|
* Cal Henderson.
|
||||||
*
|
*
|
||||||
* @param string $data
|
* @param string $data
|
||||||
|
@ -181,7 +187,7 @@ class SG_iCal_Parser {
|
||||||
$rx .= '|^[\x80-\xBF]';
|
$rx .= '|^[\x80-\xBF]';
|
||||||
|
|
||||||
return ( ! (bool) preg_match('!'.$rx.'!', $data) );
|
return ( ! (bool) preg_match('!'.$rx.'!', $data) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,23 +22,23 @@ class SG_iCal_Query {
|
||||||
if( $ical instanceof SG_iCalReader ) {
|
if( $ical instanceof SG_iCalReader ) {
|
||||||
$ical = $ical->getEvents();
|
$ical = $ical->getEvents();
|
||||||
}
|
}
|
||||||
if( !is_array($evs) ) {
|
if( !is_array($ical) ) {
|
||||||
throw new Exception('SG_iCal_Query::Between called with invalid input!');
|
throw new Exception('SG_iCal_Query::Between called with invalid input!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$rtn = array();
|
$rtn = array();
|
||||||
foreach( $evs AS $e ) {
|
foreach( $ical AS $e ) {
|
||||||
if( ($start <= $e->getStart() && $e->getStart() < $end)
|
if( ($start <= $e->getStart() && $e->getStart() < $end)
|
||||||
|| ($start < $e->getEnd() && $e->getEnd() <= $end) ) {
|
|| ($start < $e->getRangeEnd() && $e->getRangeEnd() <= $end) ) {
|
||||||
$rtn[] = $e;
|
$rtn[] = $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $rtn;
|
return $rtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all events from the calendar after a given timestamp
|
* Returns all events from the calendar after a given timestamp
|
||||||
*
|
*
|
||||||
* @param SG_iCalReader|array $ical The calendar to query
|
* @param SG_iCalReader|array $ical The calendar to query
|
||||||
* @param int $start
|
* @param int $start
|
||||||
* @return SG_iCal_VEvent[]
|
* @return SG_iCal_VEvent[]
|
||||||
|
@ -50,19 +50,19 @@ class SG_iCal_Query {
|
||||||
if( !is_array($ical) ) {
|
if( !is_array($ical) ) {
|
||||||
throw new Exception('SG_iCal_Query::After called with invalid input!');
|
throw new Exception('SG_iCal_Query::After called with invalid input!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$rtn = array();
|
$rtn = array();
|
||||||
foreach( $ical AS $e ) {
|
foreach( $ical AS $e ) {
|
||||||
if( $start <= $e->getStart() ) {
|
if($e->getStart() >= $start || $e->getRangeEnd() >= $start) {
|
||||||
$rtn[] = $e;
|
$rtn[] = $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $rtn;
|
return $rtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorts the events from the calendar after the specified column.
|
* Sorts the events from the calendar after the specified column.
|
||||||
* Column can be all valid entires that getProperty can return.
|
* Column can be all valid entires that getProperty can return.
|
||||||
* So stuff like uid, start, end, summary etc.
|
* So stuff like uid, start, end, summary etc.
|
||||||
* @param SG_iCalReader|array $ical The calendar to query
|
* @param SG_iCalReader|array $ical The calendar to query
|
||||||
* @param string $column
|
* @param string $column
|
||||||
|
@ -75,7 +75,7 @@ class SG_iCal_Query {
|
||||||
if( !is_array($ical) ) {
|
if( !is_array($ical) ) {
|
||||||
throw new Exception('SG_iCal_Query::Sort called with invalid input!');
|
throw new Exception('SG_iCal_Query::Sort called with invalid input!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$cmp = create_function('$a, $b', 'return strcmp($a->getProperty("' . $column . '"), $b->getProperty("' . $column . '"));');
|
$cmp = create_function('$a, $b', 'return strcmp($a->getProperty("' . $column . '"), $b->getProperty("' . $column . '"));');
|
||||||
usort($ical, $cmp);
|
usort($ical, $cmp);
|
||||||
return $ical;
|
return $ical;
|
||||||
|
|
|
@ -14,11 +14,13 @@
|
||||||
*/
|
*/
|
||||||
class SG_iCal_Recurrence {
|
class SG_iCal_Recurrence {
|
||||||
|
|
||||||
|
public $rrule;
|
||||||
|
|
||||||
protected $freq;
|
protected $freq;
|
||||||
|
|
||||||
protected $until;
|
protected $until;
|
||||||
protected $count;
|
protected $count;
|
||||||
|
|
||||||
protected $interval;
|
protected $interval;
|
||||||
protected $bysecond;
|
protected $bysecond;
|
||||||
protected $byminute;
|
protected $byminute;
|
||||||
|
@ -29,6 +31,7 @@ class SG_iCal_Recurrence {
|
||||||
protected $byyearno;
|
protected $byyearno;
|
||||||
protected $bymonth;
|
protected $bymonth;
|
||||||
protected $bysetpos;
|
protected $bysetpos;
|
||||||
|
|
||||||
protected $wkst;
|
protected $wkst;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,7 +43,6 @@ class SG_iCal_Recurrence {
|
||||||
'byyearday', 'byyearno', 'bymonth', 'bysetpos'
|
'byyearday', 'byyearno', 'bymonth', 'bysetpos'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an recurrence object with a passed in line. Parses the line.
|
* Creates an recurrence object with a passed in line. Parses the line.
|
||||||
* @param object $line an SG_iCal_Line object which will be parsed to get the
|
* @param object $line an SG_iCal_Line object which will be parsed to get the
|
||||||
|
@ -56,6 +58,8 @@ class SG_iCal_Recurrence {
|
||||||
* @param string $line the line to be parsed
|
* @param string $line the line to be parsed
|
||||||
*/
|
*/
|
||||||
protected function parseLine($line) {
|
protected function parseLine($line) {
|
||||||
|
$this->rrule = $line;
|
||||||
|
|
||||||
//split up the properties
|
//split up the properties
|
||||||
$recurProperties = explode(';', $line);
|
$recurProperties = explode(';', $line);
|
||||||
$recur = array();
|
$recur = array();
|
||||||
|
@ -77,6 +81,18 @@ class SG_iCal_Recurrence {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the $until member
|
||||||
|
* @param mixed timestamp (int) / Valid DateTime format (string)
|
||||||
|
*/
|
||||||
|
public function setUntil($ts) {
|
||||||
|
if ( is_int($ts) )
|
||||||
|
$dt = new DateTime('@'.$ts);
|
||||||
|
else
|
||||||
|
$dt = new DateTime($ts);
|
||||||
|
$this->until = $dt->format('Ymd\THisO');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the desired member variable and returns it (if it's set)
|
* Retrieves the desired member variable and returns it (if it's set)
|
||||||
* @param string $member name of the member variable
|
* @param string $member name of the member variable
|
||||||
|
@ -103,7 +119,6 @@ class SG_iCal_Recurrence {
|
||||||
* @return mixed string if the member has been set, false otherwise
|
* @return mixed string if the member has been set, false otherwise
|
||||||
*/
|
*/
|
||||||
public function getUntil() {
|
public function getUntil() {
|
||||||
|
|
||||||
return $this->getMember('until');
|
return $this->getMember('until');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,6 @@ class VEventTest extends PHPUnit_Framework_TestCase {
|
||||||
|
|
||||||
date_default_timezone_set('America/New_York');
|
date_default_timezone_set('America/New_York');
|
||||||
$event = new SG_iCal_VEvent($data, $ical);
|
$event = new SG_iCal_VEvent($data, $ical);
|
||||||
$this->assertEquals(strtotime('20091030T090000'), $event->getEnd());
|
$this->assertEquals(strtotime('20091030T090000'), $event->getProperty('laststart'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
require_once 'PHPUnit/Framework.php';
|
require_once 'PHPUnit/Framework.php';
|
||||||
require_once dirname(__FILE__).'/FreqTest.php';
|
require_once dirname(__FILE__).'/FreqTest.php';
|
||||||
require_once dirname(__FILE__).'/RecurrenceTest.php';
|
require_once dirname(__FILE__).'/RecurrenceTest.php';
|
||||||
|
require_once dirname(__FILE__).'/DurationTest.php';
|
||||||
|
|
||||||
class Helpers_AllTests {
|
class Helpers_AllTests {
|
||||||
|
|
||||||
|
@ -9,6 +10,7 @@ class Helpers_AllTests {
|
||||||
$suite = new PHPUnit_Framework_TestSuite('Helpers');
|
$suite = new PHPUnit_Framework_TestSuite('Helpers');
|
||||||
$suite->addTestSuite('FreqTest');
|
$suite->addTestSuite('FreqTest');
|
||||||
$suite->addTestSuite('RecurrenceTest');
|
$suite->addTestSuite('RecurrenceTest');
|
||||||
|
$suite->addTestSuite('DurationTest');
|
||||||
|
|
||||||
return $suite;
|
return $suite;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
require_once dirname(__FILE__) . '/../common.php';
|
||||||
|
require_once 'PHPUnit/Framework.php';
|
||||||
|
|
||||||
|
class DurationTest extends PHPUnit_Framework_TestCase {
|
||||||
|
|
||||||
|
public function setUp() {
|
||||||
|
$this->secsMin = 60;
|
||||||
|
$this->secsHour = 60 * 60;
|
||||||
|
$this->secsDay = 24 * 60 * 60;
|
||||||
|
$this->secsWeek = 7 * 24 * 60 * 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDurationDateTime() {
|
||||||
|
|
||||||
|
//A duration of 10 days, 6 hours and 20 seconds
|
||||||
|
$dur = new SG_iCal_Duration('P10DT6H0M20S');
|
||||||
|
$this->assertEquals($this->secsDay*10 + $this->secsHour*6 + 20, $dur->getDuration() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDurationWeek() {
|
||||||
|
|
||||||
|
//A duration of 2 weeks
|
||||||
|
$dur = new SG_iCal_Duration('P2W');
|
||||||
|
$this->assertEquals($this->secsWeek * 2, $dur->getDuration() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDurationNegative() {
|
||||||
|
|
||||||
|
//A duration of -1 day
|
||||||
|
$dur = new SG_iCal_Duration('-P1D');
|
||||||
|
$this->assertEquals(-1 * $this->secsDay, $dur->getDuration() );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -23,12 +23,12 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
873961200,
|
873961200,
|
||||||
-1
|
-1
|
||||||
);
|
);
|
||||||
|
|
||||||
$rule = 'FREQ=DAILY;COUNT=10';
|
$rule = 'FREQ=DAILY;COUNT=10';
|
||||||
$start = strtotime('19970902T090000');
|
$start = strtotime('19970902T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDailyUntil() {
|
public function testDailyUntil() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
873183600,
|
873183600,
|
||||||
|
@ -43,15 +43,15 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
873961200,
|
873961200,
|
||||||
874047600
|
874047600
|
||||||
);
|
);
|
||||||
|
|
||||||
$rule = 'FREQ=DAILY;UNTIL=19971224T000000Z';
|
$rule = 'FREQ=DAILY;UNTIL=19971224T000000Z';
|
||||||
$start = strtotime('19970902T090000');
|
$start = strtotime('19970902T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
|
|
||||||
$freq = new SG_iCal_Freq($rule, $start);
|
$freq = new SG_iCal_Freq($rule, $start);
|
||||||
$this->assertEquals(882864000, $freq->previousOccurrence(time()));
|
$this->assertEquals(882864000, $freq->previousOccurrence(time()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDailyInterval() {
|
public function testDailyInterval() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
873183600,
|
873183600,
|
||||||
|
@ -66,7 +66,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19970902T090000');
|
$start = strtotime('19970902T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDailyIntervalCount() {
|
public function testDailyIntervalCount() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
873183600,
|
873183600,
|
||||||
|
@ -80,7 +80,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19970902T090000');
|
$start = strtotime('19970902T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDailyBydayBymonthUntil() {
|
public function testDailyBydayBymonthUntil() {
|
||||||
$rules = array(
|
$rules = array(
|
||||||
'FREQ=YEARLY;UNTIL=20000131T090000Z;BYMONTH=1;BYDAY=SU,MO,TU,WE,TH,FR,SA',
|
'FREQ=YEARLY;UNTIL=20000131T090000Z;BYMONTH=1;BYDAY=SU,MO,TU,WE,TH,FR,SA',
|
||||||
|
@ -106,22 +106,22 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
946972800
|
946972800
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach( $rules As $rule ) {
|
foreach( $rules As $rule ) {
|
||||||
$start = strtotime('19980101T090000');
|
$start = strtotime('19980101T090000');
|
||||||
$this->assertRule( $rule, $start, $datesets[0]);
|
$this->assertRule( $rule, $start, $datesets[0]);
|
||||||
|
|
||||||
$start = strtotime('+1 year', $start);
|
$start = strtotime('+1 year', $start);
|
||||||
$this->assertRule( $rule, $start, $datesets[1]);
|
$this->assertRule( $rule, $start, $datesets[1]);
|
||||||
|
|
||||||
$start = strtotime('+1 year', $start);
|
$start = strtotime('+1 year', $start);
|
||||||
$this->assertRule( $rule, $start, $datesets[2]);
|
$this->assertRule( $rule, $start, $datesets[2]);
|
||||||
|
|
||||||
$freq = new SG_iCal_Freq($rule, $start);
|
$freq = new SG_iCal_Freq($rule, $start);
|
||||||
$this->assertEquals(949305600, $freq->previousOccurrence(time()));
|
$this->assertEquals(949305600, $freq->previousOccurrence(time()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testWeeklyCount() {
|
public function testWeeklyCount() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
873183600,
|
873183600,
|
||||||
|
@ -140,7 +140,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19970902T090000');
|
$start = strtotime('19970902T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testWeeklyUntil() {
|
public function testWeeklyUntil() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
873183600,
|
873183600,
|
||||||
|
@ -158,11 +158,11 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$rule = 'FREQ=WEEKLY;UNTIL=19971224T000000Z';
|
$rule = 'FREQ=WEEKLY;UNTIL=19971224T000000Z';
|
||||||
$start = strtotime('19970902T090000');
|
$start = strtotime('19970902T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
|
|
||||||
$freq = new SG_iCal_Freq($rule, $start);
|
$freq = new SG_iCal_Freq($rule, $start);
|
||||||
$this->assertEquals(882864000, $freq->previousOccurrence(time()), 'Failed getting correct end date');
|
$this->assertEquals(882864000, $freq->previousOccurrence(time()), 'Failed getting correct end date');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testWeeklyBydayLimit() {
|
public function testWeeklyBydayLimit() {
|
||||||
$rules = array(
|
$rules = array(
|
||||||
'FREQ=WEEKLY;UNTIL=19971007T000000Z;WKST=SU;BYDAY=TU,TH',
|
'FREQ=WEEKLY;UNTIL=19971007T000000Z;WKST=SU;BYDAY=TU,TH',
|
||||||
|
@ -186,7 +186,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testWeeklyIntervalUntilByday() {
|
public function testWeeklyIntervalUntilByday() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
873183600,
|
873183600,
|
||||||
|
@ -204,11 +204,11 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$rule = 'FREQ=WEEKLY;INTERVAL=2;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR';
|
$rule = 'FREQ=WEEKLY;INTERVAL=2;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR';
|
||||||
$start = strtotime('19970902T090000');
|
$start = strtotime('19970902T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
|
|
||||||
$freq = new SG_iCal_Freq($rule, $start);
|
$freq = new SG_iCal_Freq($rule, $start);
|
||||||
$this->assertEquals(882777600, $freq->previousOccurrence(time()), 'Failed getting correct end date');
|
$this->assertEquals(882777600, $freq->previousOccurrence(time()), 'Failed getting correct end date');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testWeeklyIntervalBydayCount() {
|
public function testWeeklyIntervalBydayCount() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
873183600,
|
873183600,
|
||||||
|
@ -225,7 +225,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19970902T090000');
|
$start = strtotime('19970902T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMonthlyBydayCount() {
|
public function testMonthlyBydayCount() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
873442800,
|
873442800,
|
||||||
|
@ -244,7 +244,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19970905T090000');
|
$start = strtotime('19970905T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMonthlyBydayUntil() {
|
public function testMonthlyBydayUntil() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
873442800,
|
873442800,
|
||||||
|
@ -257,7 +257,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19970905T090000');
|
$start = strtotime('19970905T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMonthlyIntervalBydayCount2() {
|
public function testMonthlyIntervalBydayCount2() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
873615600,
|
873615600,
|
||||||
|
@ -291,7 +291,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19970922T090000');
|
$start = strtotime('19970922T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMonthlyBymonthday() {
|
public function testMonthlyBymonthday() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
875430000,
|
875430000,
|
||||||
|
@ -305,7 +305,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19970928T090000');
|
$start = strtotime('19970928T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMonthlyBymonthdayCount() {
|
public function testMonthlyBymonthdayCount() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
873183600,
|
873183600,
|
||||||
|
@ -324,7 +324,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19970902T090000');
|
$start = strtotime('19970902T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMonthlyBymonthdayCount2() {
|
public function testMonthlyBymonthdayCount2() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
875602800,
|
875602800,
|
||||||
|
@ -343,7 +343,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19970930T090000');
|
$start = strtotime('19970930T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMonthlyIntervalBymonthdayCount() {
|
public function testMonthlyIntervalBymonthdayCount() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
873874800,
|
873874800,
|
||||||
|
@ -362,7 +362,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19970910T090000');
|
$start = strtotime('19970910T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMonthlyIntervalByday() {
|
public function testMonthlyIntervalByday() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
873183600,
|
873183600,
|
||||||
|
@ -380,7 +380,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19970902T090000');
|
$start = strtotime('19970902T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testYearlyCountBymonth() {
|
public function testYearlyCountBymonth() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
865926000,
|
865926000,
|
||||||
|
@ -399,7 +399,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19970610T090000');
|
$start = strtotime('19970610T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testYearlyIntervalCountBymonth() {
|
public function testYearlyIntervalCountBymonth() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
857980800,
|
857980800,
|
||||||
|
@ -418,7 +418,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19970310T090000');
|
$start = strtotime('19970310T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testYearlyIntervalCountByyearday() {
|
public function testYearlyIntervalCountByyearday() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
852105600,
|
852105600,
|
||||||
|
@ -437,7 +437,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19970101T090000');
|
$start = strtotime('19970101T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testYearlyByday() {
|
public function testYearlyByday() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
864025200,
|
864025200,
|
||||||
|
@ -448,7 +448,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19970519T090000');
|
$start = strtotime('19970519T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testYearlyByweeknoByday() {
|
public function testYearlyByweeknoByday() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
863420400,
|
863420400,
|
||||||
|
@ -509,7 +509,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19970902T090000');
|
$start = strtotime('19970902T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testYearlyBydayBymonthday2() {
|
public function testYearlyBydayBymonthday2() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
874134000,
|
874134000,
|
||||||
|
@ -527,7 +527,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19970913T090000');
|
$start = strtotime('19970913T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testYearlyIntervalBymonthBydayBymonthday() {
|
public function testYearlyIntervalBymonthBydayBymonthday() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
847180800,
|
847180800,
|
||||||
|
@ -538,9 +538,9 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19961105T090000');
|
$start = strtotime('19961105T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: SETPOS rules
|
// TODO: SETPOS rules
|
||||||
|
|
||||||
public function testHourlyIntervalUntil() {
|
public function testHourlyIntervalUntil() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
873183600,
|
873183600,
|
||||||
|
@ -552,7 +552,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19970902T090000');
|
$start = strtotime('19970902T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMinutelyIntervalCount() {
|
public function testMinutelyIntervalCount() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
873183600,
|
873183600,
|
||||||
|
@ -567,7 +567,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19970902T090000');
|
$start = strtotime('19970902T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMinutelyIntervalCount2() {
|
public function testMinutelyIntervalCount2() {
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
873183600,
|
873183600,
|
||||||
|
@ -580,11 +580,11 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
$start = strtotime('19970902T090000');
|
$start = strtotime('19970902T090000');
|
||||||
$this->assertRule( $rule, $start, $dateset);
|
$this->assertRule( $rule, $start, $dateset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMinutelyIntervalByhour() {
|
public function testMinutelyIntervalByhour() {
|
||||||
$rules = array(
|
$rules = array(
|
||||||
'FREQ=MINUTELY;INTERVAL=20;BYHOUR=9,10,11,12,13,14,15,16'/*,
|
'FREQ=MINUTELY;INTERVAL=20;BYHOUR=9,10,11,12,13,14,15,16'/*,
|
||||||
'FREQ=DAILY;BYHOUR=9,10,11,12,13,14,15,16;BYMINUTE=0,20,40'*/
|
'FREQ=DAILY;BYHOUR=9,10,11,12,13,14,15,16;BYMINUTE=0,20,40'*/
|
||||||
);
|
);
|
||||||
// TODO: Fix it so multi byhour and byminute will work
|
// TODO: Fix it so multi byhour and byminute will work
|
||||||
$dateset = array(
|
$dateset = array(
|
||||||
|
@ -605,25 +605,68 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testLastOccurrence() {
|
/*
|
||||||
|
weird : in this test $start is not a matched occurrence but...
|
||||||
|
|
||||||
|
to do something like that, we need EXDATE :
|
||||||
|
DTSTART;TZID=US-Eastern:19970902T090000
|
||||||
|
EXDATE;TZID=US-Eastern:19970902T090000
|
||||||
|
RRULE:FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function testFirstOccurrencesByYearDay() {
|
||||||
$rule = 'FREQ=YEARLY;INTERVAL=2;BYYEARDAY=1;COUNT=5';
|
$rule = 'FREQ=YEARLY;INTERVAL=2;BYYEARDAY=1;COUNT=5';
|
||||||
$start = strtotime('2009-10-27T090000');
|
$start = strtotime('2009-10-27T090000');
|
||||||
$freq = new SG_iCal_Freq($rule, $start);
|
$freq = new SG_iCal_Freq($rule, $start);
|
||||||
$this->assertEquals(strtotime('2018-01-01T09:00:00'), $freq->lastOccurrence());
|
$this->assertEquals(strtotime('2009-10-27T09:00:00'), $freq->firstOccurrence());
|
||||||
|
$this->assertEquals(strtotime('2011-01-01T09:00:00'), $freq->nextOccurrence($start));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: WKST rule
|
public function testFirstOccurrencesByYearDayWithoutFirstDate() {
|
||||||
|
$rule = 'FREQ=YEARLY;INTERVAL=2;BYYEARDAY=1;COUNT=5';
|
||||||
|
$start = strtotime('2009-10-27T090000');
|
||||||
|
$freq = new SG_iCal_Freq($rule, $start, array($start));
|
||||||
|
$this->assertEquals(strtotime('2011-01-01T09:00:00'), $freq->firstOccurrence());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLastOccurrenceByYearDay() {
|
||||||
|
$rule = 'FREQ=YEARLY;INTERVAL=2;BYYEARDAY=1;COUNT=5';
|
||||||
|
$start = strtotime('2011-01-01T090000');
|
||||||
|
$freq = new SG_iCal_Freq($rule, $start);
|
||||||
|
$this->assertEquals(strtotime('2019-01-01T09:00:00'), $freq->lastOccurrence());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCacheCount() {
|
||||||
|
$rule = 'FREQ=YEARLY;INTERVAL=2;BYYEARDAY=1;COUNT=5';
|
||||||
|
$start = strtotime('2011-01-01T090000');
|
||||||
|
$freq = new SG_iCal_Freq($rule, $start);
|
||||||
|
$this->assertEquals(5, count($freq->getAllOccurrences()));
|
||||||
|
$this->assertEquals(strtotime('2019-01-01T09:00:00'), $freq->lastOccurrence());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: BYSETPOS rule :
|
||||||
|
The 3rd instance into the month of one of Tuesday, Wednesday or
|
||||||
|
Thursday, for the next 3 months:
|
||||||
|
|
||||||
|
DTSTART;TZID=US-Eastern:19970904T090000
|
||||||
|
RRULE:FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=3
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* TODO: WKST rule
|
||||||
|
*/
|
||||||
|
|
||||||
|
//check a serie of dates
|
||||||
private function assertRule( $rule, $start, $dateset ) {
|
private function assertRule( $rule, $start, $dateset ) {
|
||||||
$freq = new SG_iCal_Freq($rule, $start);
|
$freq = new SG_iCal_Freq($rule, $start);
|
||||||
reset($dateset);
|
reset($dateset);
|
||||||
$n = $start - 1;
|
$n = $start - 1;
|
||||||
do {
|
do {
|
||||||
$n = $freq->findNext($n);
|
$n = $freq->findNext($n);
|
||||||
|
//echo date('Y-m-d H:i:sO ',$n);
|
||||||
$e = (current($dateset) != -1) ? current($dateset) : false;
|
$e = (current($dateset) != -1) ? current($dateset) : false;
|
||||||
$this->assertEquals($e, $n);
|
$this->assertEquals($e, $n);
|
||||||
} while( next($dateset) !== false );
|
} while( next($dateset) !== false );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# aptitude install phpunit
|
||||||
|
|
||||||
|
phpunit AllTests.php
|
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
TIMESTAMP=$1
|
||||||
|
|
||||||
|
php -r "echo date('Y-m-d H:i:s O',$TIMESTAMP); echo \"\n\"; "
|
||||||
|
|
Ładowanie…
Reference in New Issue