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
|
||||
|
||||
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
|
||||
* http://github.com/fangel/SG-iCalendar
|
||||
*
|
||||
* Roadmap:
|
||||
* * Finish FREQUENCY-parsing.
|
||||
* * Add API for recurring events
|
||||
*
|
||||
*
|
||||
* A simple example:
|
||||
* <?php
|
||||
* $ical = new SG_iCal("http://example.com/calendar.ics");
|
||||
* $ical = new SG_iCalReader("http://example.com/calendar.ics");
|
||||
* foreach( $ical->getEvents() As $event ) {
|
||||
* // Do stuff with the event $event
|
||||
* }
|
||||
|
@ -19,26 +20,32 @@ define('SG_ICALREADER_VERSION', '0.5');
|
|||
*
|
||||
* @package SG_iCalReader
|
||||
* @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
|
||||
*/
|
||||
class SG_iCal {
|
||||
private $information;
|
||||
private $events;
|
||||
private $timezones;
|
||||
|
||||
//objects
|
||||
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
|
||||
* @param $url string
|
||||
*/
|
||||
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_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_Query.php'; // BUILD: Remove line
|
||||
require_once dirname(__FILE__) . '/helpers/SG_iCal_Factory.php'; // BUILD: Remove line
|
||||
|
||||
if( $url !== false ) {
|
||||
SG_iCal_Parser::Parse($url, $this);
|
||||
}
|
||||
$this->setUrl($url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -50,16 +57,16 @@ class SG_iCal {
|
|||
SG_iCal_Parser::Parse($url, $this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the main calendar info. You can then query the returned
|
||||
* object with ie getTitle().
|
||||
* object with ie getTitle().
|
||||
* @return SG_iCal_VCalendar
|
||||
*/
|
||||
public function getCalendarInfo() {
|
||||
return $this->information;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the calendar info for this calendar
|
||||
* @param SG_iCal_VCalendar $info
|
||||
|
@ -67,8 +74,8 @@ class SG_iCal {
|
|||
public function setCalendarInfo( SG_iCal_VCalendar $info ) {
|
||||
$this->information = $info;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns a given timezone for the calendar. This is mainly used
|
||||
* by VEvents to adjust their date-times if they have specified a
|
||||
|
@ -95,7 +102,7 @@ class SG_iCal {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a new timezone to this calendar
|
||||
* @param SG_iCal_VTimeZone $tz
|
||||
|
@ -103,7 +110,7 @@ class SG_iCal {
|
|||
public function addTimeZone( SG_iCal_VTimeZone $tz ) {
|
||||
$this->timezones[] = $tz;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the events found
|
||||
* @return array
|
||||
|
|
|
@ -10,17 +10,17 @@
|
|||
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
||||
*/
|
||||
class SG_iCal_VCalendar implements IteratorAggregate {
|
||||
private $data;
|
||||
|
||||
protected $data;
|
||||
|
||||
/**
|
||||
* Creates a new SG_iCal_VCalendar.
|
||||
*/
|
||||
public function __construct($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
|
||||
* @return string
|
||||
*/
|
||||
|
@ -31,7 +31,7 @@ class SG_iCal_VCalendar implements IteratorAggregate {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the description of the calendar. If no description is
|
||||
* known, NULL will be returned.
|
||||
|
@ -44,7 +44,7 @@ class SG_iCal_VCalendar implements IteratorAggregate {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see IteratorAggregate.getIterator()
|
||||
*/
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<?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
|
||||
* 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.
|
||||
*
|
||||
* Will apply the specified timezone to timestamps if a tzid is
|
||||
* Will apply the specified timezone to timestamps if a tzid is
|
||||
* specified
|
||||
*
|
||||
* @package SG_iCalReader
|
||||
|
@ -15,22 +15,36 @@
|
|||
*/
|
||||
class SG_iCal_VEvent {
|
||||
const DEFAULT_CONFIRMED = true;
|
||||
private $uid;
|
||||
private $start;
|
||||
private $end;
|
||||
private $recurrence;
|
||||
private $summary;
|
||||
private $description;
|
||||
private $location;
|
||||
private $data;
|
||||
|
||||
|
||||
protected $uid;
|
||||
|
||||
protected $start;
|
||||
protected $end;
|
||||
|
||||
protected $summary;
|
||||
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.
|
||||
* @param SG_iCal_Line[] $data
|
||||
* @param SG_iCalReader $ical
|
||||
*/
|
||||
public function __construct($data, SG_iCal $ical ) {
|
||||
public function __construct($data, SG_iCal $ical) {
|
||||
|
||||
$this->uid = $data['uid']->getData();
|
||||
unset($data['uid']);
|
||||
|
||||
|
@ -38,33 +52,66 @@ class SG_iCal_VEvent {
|
|||
$this->recurrence = new SG_iCal_Recurrence($data['rrule']);
|
||||
unset($data['rrule']);
|
||||
}
|
||||
|
||||
|
||||
if ( isset($data['exrule']) ) {
|
||||
$this->recurex = new SG_iCal_Recurrence($data['exrule']);
|
||||
unset($data['exrule']);
|
||||
}
|
||||
|
||||
if( isset($data['dtstart']) ) {
|
||||
$this->start = $this->getTimestamp( $data['dtstart'], $ical );
|
||||
$this->start = $this->getTimestamp($data['dtstart'], $ical);
|
||||
unset($data['dtstart']);
|
||||
}
|
||||
|
||||
|
||||
if( isset($data['dtend']) ) {
|
||||
$this->end = $this->getTimestamp($data['dtend'], $ical);
|
||||
unset($data['dtend']);
|
||||
} elseif( isset($data['duration']) ) {
|
||||
require_once dirname(__FILE__).'/../helpers/SG_iCal_Duration.php'; // BUILD: Remove line
|
||||
$dur = new SG_iCal_Duration( $data['duration']->getData() );
|
||||
$this->end = $this->start + $dur->getDuration();
|
||||
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
|
||||
|
||||
//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();
|
||||
$count = $this->recurrence->getCount();
|
||||
//check if there is either 'until' or 'count' set
|
||||
if ( $this->recurrence->getUntil() or $this->recurrence->getCount() ) {
|
||||
//if until is set, set that as the end date (using getTimeStamp)
|
||||
if ( $until ) {
|
||||
$this->end = strtotime( $until );
|
||||
}
|
||||
if ( $until ) {
|
||||
//ok..
|
||||
} elseif ($count) {
|
||||
//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');
|
||||
|
@ -74,10 +121,28 @@ class SG_iCal_VEvent {
|
|||
unset($data[$import]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( isset($this->previous_tz) ) {
|
||||
date_default_timezone_set($this->previous_tz);
|
||||
}
|
||||
|
||||
$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
|
||||
* @return string
|
||||
|
@ -85,7 +150,7 @@ class SG_iCal_VEvent {
|
|||
public function getUID() {
|
||||
return $this->uid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the summary (or null if none is given) of the event
|
||||
* @return string
|
||||
|
@ -93,7 +158,7 @@ class SG_iCal_VEvent {
|
|||
public function getSummary() {
|
||||
return $this->summary;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the description (or null if none is given) of the event
|
||||
* @return string
|
||||
|
@ -101,7 +166,7 @@ class SG_iCal_VEvent {
|
|||
public function getDescription() {
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the location (or null if none is given) of the event
|
||||
* @return string
|
||||
|
@ -109,7 +174,7 @@ class SG_iCal_VEvent {
|
|||
public function getLocation() {
|
||||
return $this->location;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the event is blocking (ie not transparent)
|
||||
* @return bool
|
||||
|
@ -117,7 +182,7 @@ class SG_iCal_VEvent {
|
|||
public function isBlocking() {
|
||||
return !(isset($this->data['transp']) && $this->data['transp'] == 'TRANSPARENT');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the event is confirmed
|
||||
* @return bool
|
||||
|
@ -129,7 +194,19 @@ class SG_iCal_VEvent {
|
|||
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
|
||||
* @return int
|
||||
|
@ -137,7 +214,7 @@ class SG_iCal_VEvent {
|
|||
public function getStart() {
|
||||
return $this->start;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the timestamp for the end of the event
|
||||
* @return int
|
||||
|
@ -145,7 +222,15 @@ class SG_iCal_VEvent {
|
|||
public function getEnd() {
|
||||
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
|
||||
* @return int
|
||||
|
@ -153,7 +238,7 @@ class SG_iCal_VEvent {
|
|||
public function getDuration() {
|
||||
return $this->end - $this->start;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the given property of the event.
|
||||
* @param string $prop
|
||||
|
@ -168,19 +253,40 @@ class SG_iCal_VEvent {
|
|||
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.
|
||||
* @param $line SG_iCal_Line
|
||||
* @return int
|
||||
*/
|
||||
private function getTimestamp( SG_iCal_Line $line, SG_iCal $ical ) {
|
||||
$ts = strtotime($line->getData());
|
||||
protected function getTimestamp( SG_iCal_Line $line, SG_iCal $ical ) {
|
||||
|
||||
if( isset($line['tzid']) ) {
|
||||
$tz = $ical->getTimeZoneInfo($line['tzid']);
|
||||
$offset = $tz->getOffset($ts);
|
||||
$ts = strtotime(date('D, d M Y H:i:s', $ts) . ' ' . $offset);
|
||||
$this->setLineTimeZone($line);
|
||||
//$tz = $ical->getTimeZoneInfo($line['tzid']);
|
||||
//$offset = $tz->getOffset($ts);
|
||||
//$ts = strtotime(date('D, d M Y H:i:s', $ts) . ' ' . $offset);
|
||||
}
|
||||
$ts = strtotime($line->getData());
|
||||
|
||||
return $ts;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,31 +9,31 @@
|
|||
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
||||
*/
|
||||
class SG_iCal_VTimeZone {
|
||||
private $tzid;
|
||||
private $daylight;
|
||||
private $standard;
|
||||
private $cache = array();
|
||||
|
||||
protected $tzid;
|
||||
protected $daylight;
|
||||
protected $standard;
|
||||
protected $cache = array();
|
||||
|
||||
/**
|
||||
* Constructs a new SG_iCal_VTimeZone
|
||||
*/
|
||||
public function __construct( $data ) {
|
||||
require_once dirname(__FILE__).'/../helpers/SG_iCal_Freq.php'; // BUILD: Remove line
|
||||
|
||||
|
||||
$this->tzid = $data['tzid'];
|
||||
$this->daylight = $data['daylight'];
|
||||
$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)
|
||||
* @return string
|
||||
*/
|
||||
public function getTimeZoneId() {
|
||||
return $this->tzid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the given offset in this timezone for the given
|
||||
* timestamp. (eg +0200)
|
||||
|
@ -44,7 +44,7 @@ class SG_iCal_VTimeZone {
|
|||
$act = $this->getActive($ts);
|
||||
return $this->{$act}['tzoffsetto'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the timezone name for the given timestamp (eg CEST)
|
||||
* @param int $ts
|
||||
|
@ -54,7 +54,7 @@ class SG_iCal_VTimeZone {
|
|||
$act = $this->getActive($ts);
|
||||
return $this->{$act}['tzname'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines which of the daylight or standard is the active
|
||||
* setting.
|
||||
|
@ -65,20 +65,31 @@ class SG_iCal_VTimeZone {
|
|||
* @return string standard|daylight
|
||||
*/
|
||||
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];
|
||||
}
|
||||
|
||||
$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 {
|
||||
private $dur;
|
||||
|
||||
protected $dur;
|
||||
|
||||
/**
|
||||
* Constructs a new SG_iCal_Duration from a duration-rule.
|
||||
* The basic build-up of DURATIONs are:
|
||||
|
@ -20,30 +20,32 @@ class SG_iCal_Duration {
|
|||
* @param $duration string
|
||||
*/
|
||||
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);
|
||||
$results = array('weeks'=>(int)$matches[2],
|
||||
'days'=>(int)$matches[4],
|
||||
'hours'=>(int)$matches[7],
|
||||
'minutes'=>(int)$matches[9],
|
||||
'seconds'=>(int)$matches[11]);
|
||||
|
||||
$ts = 0;
|
||||
|
||||
$ts = 0;
|
||||
|
||||
if (preg_match('/[\\+\\-]{0,1}P((\d+)W)?((\d+)D)?(T)?((\d+)H)?((\d+)M)?((\d+)S)?/', $duration, $matches) === 1) {
|
||||
$results = array(
|
||||
'weeks'=> (int)@ $matches[2],
|
||||
'days'=> (int)@ $matches[4],
|
||||
'hours'=> (int)@ $matches[7],
|
||||
'minutes'=>(int)@ $matches[9],
|
||||
'seconds'=>(int)@ $matches[11]
|
||||
);
|
||||
|
||||
$ts += $results['seconds'];
|
||||
$ts += 60 * $results['minutes'];
|
||||
$ts += 60 * 60 * $results['hours'];
|
||||
$ts += 24 * 60 * 60 * $results['days'];
|
||||
$ts += 7 * 24 * 60 * 60 * $results['weeks'];
|
||||
|
||||
$dir = ($duration{0} == '-') ? -1 : 1;
|
||||
|
||||
$this->dur = $dir * $ts;
|
||||
$ts += 7 * 24 * 60 * 60 * $results['weeks'];
|
||||
} else {
|
||||
// Invalid duration!
|
||||
$this->dur = 0;
|
||||
}
|
||||
|
||||
$dir = ($duration{0} == '-') ? -1 : 1;
|
||||
|
||||
$this->dur = $dir * $ts;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the duration in seconds
|
||||
* @return int
|
||||
|
|
|
@ -13,7 +13,7 @@ class SG_iCal_Factory {
|
|||
/**
|
||||
* Returns a new block-object for the section/data-pair. The list
|
||||
* of returned objects is:
|
||||
*
|
||||
*
|
||||
* vcalendar => SG_iCal_VCalendar
|
||||
* vtimezone => SG_iCal_VTimeZone
|
||||
* vevent => SG_iCal_VEvent
|
||||
|
@ -34,7 +34,7 @@ class SG_iCal_Factory {
|
|||
case "vevent":
|
||||
require_once dirname(__FILE__).'/../blocks/SG_iCal_VEvent.php'; // BUILD: Remove line
|
||||
return new SG_iCal_VEvent($data, $ical );
|
||||
|
||||
|
||||
default:
|
||||
return new ArrayObject(SG_iCal_Line::Remove_Line((array) $data) );
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<?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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* 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
|
||||
* period.
|
||||
* This should fix the issues with multi-rule + multi-rule interference,
|
||||
* period.
|
||||
* This should fix the issues with multi-rule + multi-rule interference,
|
||||
* 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
|
||||
*
|
||||
* @package SG_iCalReader
|
||||
|
@ -23,22 +23,31 @@
|
|||
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
||||
*/
|
||||
class SG_iCal_Freq {
|
||||
private $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');
|
||||
private $simpleMode = true;
|
||||
|
||||
private $rules = array('freq'=>'yearly', 'interval'=>1);
|
||||
private $start = 0;
|
||||
private $freq = '';
|
||||
|
||||
protected $weekdays = array('MO'=>'monday', 'TU'=>'tuesday', 'WE'=>'wednesday', 'TH'=>'thursday', 'FR'=>'friday', 'SA'=>'saturday', 'SU'=>'sunday');
|
||||
protected $knownRules = array('month', 'weekno', 'day', 'monthday', 'yearday', 'hour', 'minute'); //others : 'setpos', 'second'
|
||||
protected $ruleModifiers = array('wkst');
|
||||
protected $simpleMode = true;
|
||||
|
||||
protected $rules = array('freq'=>'yearly', 'interval'=>1);
|
||||
protected $start = 0;
|
||||
protected $freq = '';
|
||||
|
||||
protected $excluded; //EXDATE
|
||||
protected $added; //RDATE
|
||||
|
||||
protected $cache; // getAllOccurrences()
|
||||
|
||||
/**
|
||||
* Constructs a new Freqency-rule
|
||||
* @param $rule string
|
||||
* @param $start int Unix-timestamp (important!)
|
||||
* @param $rule string
|
||||
* @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->excluded = array();
|
||||
|
||||
$rules = array();
|
||||
foreach( explode(';', $rule) AS $v) {
|
||||
list($k, $v) = explode('=', $v);
|
||||
|
@ -49,7 +58,6 @@ class SG_iCal_Freq {
|
|||
$this->rules['until'] = strtotime($this->rules['until']);
|
||||
}
|
||||
$this->freq = strtolower($this->rules['freq']);
|
||||
|
||||
|
||||
foreach( $this->knownRules AS $rule ) {
|
||||
if( isset($this->rules['by' . $rule]) ) {
|
||||
|
@ -58,22 +66,64 @@ class SG_iCal_Freq {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!$this->simpleMode) {
|
||||
if(! (isset($this->rules['byday']) || isset($this->rules['bymonthday']) || isset($this->rules['byyearday']))) {
|
||||
$this->rules['bymonthday'] = date('d', $this->start);
|
||||
}
|
||||
}
|
||||
|
||||
//set until, and cache
|
||||
if( isset($this->rules['count']) ) {
|
||||
$n = $start;
|
||||
for($i=0;$i<$this->rules['count'];$i++) {
|
||||
$n = $this->findNext($n);
|
||||
|
||||
$cache[$ts] = $ts = $this->start;
|
||||
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
|
||||
* given offset
|
||||
|
@ -81,68 +131,95 @@ class SG_iCal_Freq {
|
|||
* @return int
|
||||
*/
|
||||
public function previousOccurrence( $offset ) {
|
||||
$t1 = $this->start;
|
||||
while( ($t2 = $this->findNext($t1)) < $offset) {
|
||||
if( $t2 == false ){
|
||||
break;
|
||||
if (!empty($this->cache)) {
|
||||
$t2=$this->start;
|
||||
foreach($this->cache as $ts) {
|
||||
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
|
||||
* @param int $offset
|
||||
* @return int
|
||||
*/
|
||||
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.
|
||||
* Builds also the cache, if not set before...
|
||||
* @return int timestamp
|
||||
*/
|
||||
public function lastOccurrence() {
|
||||
$temp_timestamp = $this->findNext($this->start);
|
||||
$timestamp = 0;
|
||||
while ($temp_timestamp) {
|
||||
$timestamp = $temp_timestamp;
|
||||
$temp_timestamp = $this->findNext($temp_timestamp);
|
||||
}
|
||||
return $timestamp;
|
||||
//build cache if not done
|
||||
$this->getAllOccurrences();
|
||||
//return last timestamp in cache
|
||||
return end($this->cache);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the next time after the given offset that the rule
|
||||
* Calculates the next time after the given offset that the rule
|
||||
* will apply.
|
||||
*
|
||||
* The approach to finding the next is as follows:
|
||||
* First we establish a timeframe to find timestamps in. This is
|
||||
* 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
|
||||
* timeframe.
|
||||
*
|
||||
* 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-
|
||||
* 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
|
||||
*
|
||||
* @param int $offset
|
||||
* @return int
|
||||
*/
|
||||
public function findNext($offset) {
|
||||
$echo = false;
|
||||
public function findNext($offset) {
|
||||
if (!empty($this->cache)) {
|
||||
foreach($this->cache as $ts) {
|
||||
if ($ts > $offset)
|
||||
return $ts;
|
||||
}
|
||||
}
|
||||
|
||||
$debug = false;
|
||||
|
||||
//make sure the offset is valid
|
||||
if( $offset === false || (isset($this->rules['until']) && $this->rules['until'] <= $offset) ) {
|
||||
if($echo) echo 'STOP: ' . date('r', $offset) . "\n";
|
||||
if( $offset === false || (isset($this->rules['until']) && $offset > $this->rules['until']) ) {
|
||||
if($debug) echo 'STOP: ' . date('r', $offset) . "\n";
|
||||
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
|
||||
//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);
|
||||
$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));
|
||||
if($echo) echo 'START: ' . date('r', $t) . "\n";
|
||||
|
||||
if($debug) echo 'START: ' . date('r', $t) . "\n";
|
||||
|
||||
if( $this->simpleMode ) {
|
||||
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 );
|
||||
if( !$this->validDate( $next ) ) {
|
||||
return $this->findNext($next);
|
||||
}
|
||||
return $next;
|
||||
return $ts;
|
||||
}
|
||||
|
||||
|
||||
$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 ) {
|
||||
if( $found && isset($this->rules['by' . $rule]) ) {
|
||||
if( $this->isPrerule($rule, $this->freq) ) {
|
||||
|
@ -180,7 +260,7 @@ class SG_iCal_Freq {
|
|||
if( $imm === false ) {
|
||||
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) ) {
|
||||
$_t = $imm;
|
||||
}
|
||||
|
@ -194,22 +274,26 @@ class SG_iCal_Freq {
|
|||
}
|
||||
}
|
||||
|
||||
if( $this->start > $offset && $this->start < $t ) {
|
||||
return $this->start;
|
||||
if( $offset < $this->start && $this->start < $t ) {
|
||||
$ts = $this->start;
|
||||
} else if( $found && ($t != $offset)) {
|
||||
if( $this->validDate( $t ) ) {
|
||||
if($echo) echo 'OK' . "\n";
|
||||
return $t;
|
||||
if($debug) echo 'OK' . "\n";
|
||||
$ts = $t;
|
||||
} else {
|
||||
if($echo) echo 'Invalid' . "\n";
|
||||
return $this->findNext($t);
|
||||
if($debug) echo 'Invalid' . "\n";
|
||||
$ts = $this->findNext($t);
|
||||
}
|
||||
} else {
|
||||
if($echo) echo 'Not found' . "\n";
|
||||
return $this->findNext( $this->findStartingPoint( $offset, $this->rules['interval'] ) );
|
||||
}
|
||||
if($debug) echo 'Not found' . "\n";
|
||||
$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
|
||||
* 'freq' forward in time since the given offset
|
||||
|
@ -229,14 +313,14 @@ class SG_iCal_Freq {
|
|||
}
|
||||
|
||||
$sp = strtotime($t, $offset);
|
||||
|
||||
|
||||
if( $truncate ) {
|
||||
$sp = $this->truncateToPeriod($sp, $this->freq);
|
||||
}
|
||||
|
||||
|
||||
return $sp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds the earliest timestamp posible outside this perioid
|
||||
* @param int $offset
|
||||
|
@ -245,11 +329,11 @@ class SG_iCal_Freq {
|
|||
public function findEndOfPeriod($offset) {
|
||||
return $this->findStartingPoint($offset, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resets the timestamp to the beginning of the
|
||||
* period specified by freq
|
||||
*
|
||||
*
|
||||
* Yes - the fall-through is on purpose!
|
||||
*
|
||||
* @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']);
|
||||
return $d;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Applies the BYDAY rule to the given timestamp
|
||||
* @param string $rule
|
||||
|
@ -293,24 +377,24 @@ class SG_iCal_Freq {
|
|||
private function ruleByday($rule, $t) {
|
||||
$dir = ($rule{0} == '-') ? -1 : 1;
|
||||
$dir_t = ($dir == 1) ? 'next' : 'last';
|
||||
|
||||
|
||||
|
||||
|
||||
$d = $this->weekdays[substr($rule,-2)];
|
||||
$s = $dir_t . ' ' . $d . ' ' . date('H:i:s',$t);
|
||||
|
||||
|
||||
if( $rule == substr($rule, -2) ) {
|
||||
if( date('l', $t) == ucfirst($d) ) {
|
||||
$s = 'today ' . date('H:i:s',$t);
|
||||
}
|
||||
|
||||
|
||||
$_t = strtotime($s, $t);
|
||||
|
||||
|
||||
if( $_t == $t && in_array($this->freq, array('monthly', 'yearly')) ) {
|
||||
// Yes. This is not a great idea.. but hey, it works.. for now
|
||||
$s = 'next ' . $d . ' ' . date('H:i:s',$t);
|
||||
$_t = strtotime($s, $_t);
|
||||
}
|
||||
|
||||
|
||||
return $_t;
|
||||
} else {
|
||||
$_f = $this->freq;
|
||||
|
@ -323,10 +407,10 @@ class SG_iCal_Freq {
|
|||
$_t = $this->truncateToPeriod($t, $this->freq);
|
||||
}
|
||||
$this->freq = $_f;
|
||||
|
||||
|
||||
$c = preg_replace('/[^0-9]/','',$rule);
|
||||
$c = ($c == '') ? 1 : $c;
|
||||
|
||||
|
||||
$n = $_t;
|
||||
while($c > 0 ) {
|
||||
if( $dir == 1 && $c == 1 && date('l', $t) == ucfirst($d) ) {
|
||||
|
@ -335,11 +419,11 @@ class SG_iCal_Freq {
|
|||
$n = strtotime($s, $n);
|
||||
$c--;
|
||||
}
|
||||
|
||||
|
||||
return $n;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function ruleBymonth($rule, $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']) ) {
|
||||
|
@ -349,14 +433,14 @@ class SG_iCal_Freq {
|
|||
return $_t;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function ruleBymonthday($rule, $t) {
|
||||
if( $rule < 0 ) {
|
||||
$rule = date('t', $t) + $rule + 1;
|
||||
}
|
||||
return mktime(date('H',$t), date('i',$t), date('s',$t), date('m', $t), $rule, date('Y', $t));
|
||||
}
|
||||
|
||||
|
||||
private function ruleByyearday($rule, $t) {
|
||||
if( $rule < 0 ) {
|
||||
$_t = $this->findEndOfPeriod();
|
||||
|
@ -376,12 +460,12 @@ class SG_iCal_Freq {
|
|||
} else {
|
||||
$_t = $this->truncateToPeriod($t, $this->freq);
|
||||
$d = '+';
|
||||
}
|
||||
}
|
||||
|
||||
$sub = (date('W', $_t) == 1) ? 2 : 1;
|
||||
$s = $d . abs($rule - $sub) . ' weeks ' . date('H:i:s',$t);
|
||||
$_t = strtotime($s, $_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));
|
||||
return $_t;
|
||||
}
|
||||
|
||||
|
||||
private function ruleByminute($rule, $t) {
|
||||
$_t = mktime(date('h',$t), $rule, date('s',$t), date('m',$t), date('d', $t), date('Y', $t));
|
||||
return $_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;
|
||||
}
|
||||
|
||||
|
||||
if (in_array($t, $this->excluded)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if( isset($this->rules['bymonth']) ) {
|
||||
$months = explode(',', $this->rules['bymonth']);
|
||||
if( !in_array(date('m', $t), $months)) {
|
||||
|
@ -438,10 +526,10 @@ class SG_iCal_Freq {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private function isPrerule($rule, $freq) {
|
||||
if( $rule == 'year')
|
||||
return false;
|
||||
|
@ -456,11 +544,11 @@ class SG_iCal_Freq {
|
|||
return true;
|
||||
if( $rule == 'day' && in_array($freq, array('yearly', 'monthly', 'weekly')))
|
||||
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;
|
||||
if( $rule == 'minute' )
|
||||
if( $rule == 'minute' )
|
||||
return true;
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* 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
|
||||
* store them.
|
||||
*
|
||||
*
|
||||
* The line-type can be found by querying getIdent(), data via either
|
||||
* getData() or typecasting to a string.
|
||||
* 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
|
||||
*/
|
||||
class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
||||
private $ident;
|
||||
private $data;
|
||||
private $params = array();
|
||||
|
||||
private $replacements = array('from'=>array('\\,', '\\n', '\\;', '\\:', '\\"'), 'to'=>array(',', "\n", ';', ':', '"'));
|
||||
|
||||
protected $ident;
|
||||
protected $data;
|
||||
protected $params = array();
|
||||
|
||||
protected $replacements = array('from'=>array('\\,', '\\n', '\\;', '\\:', '\\"'), 'to'=>array(',', "\n", ';', ':', '"'));
|
||||
|
||||
/**
|
||||
* Constructs a new line.
|
||||
*/
|
||||
|
@ -28,21 +28,21 @@ class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
|||
$split = strpos($line, ':');
|
||||
$idents = explode(';', substr($line, 0, $split));
|
||||
$ident = strtolower(array_shift($idents));
|
||||
|
||||
|
||||
$data = trim(substr($line, $split+1));
|
||||
$data = str_replace($this->replacements['from'], $this->replacements['to'], $data);
|
||||
|
||||
|
||||
$params = array();
|
||||
foreach( $idents AS $v) {
|
||||
list($k, $v) = explode('=', $v);
|
||||
$params[ strtolower($k) ] = $v;
|
||||
}
|
||||
|
||||
|
||||
$this->ident = $ident;
|
||||
$this->params = $params;
|
||||
$this->params = $params;
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Is this line the begining of a new block?
|
||||
* @return bool
|
||||
|
@ -50,7 +50,7 @@ class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
|||
public function isBegin() {
|
||||
return $this->ident == 'begin';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Is this line the end of a block?
|
||||
* @return bool
|
||||
|
@ -58,7 +58,7 @@ class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
|||
public function isEnd() {
|
||||
return $this->ident == 'end';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the line-type (ident) of the line
|
||||
* @return string
|
||||
|
@ -66,7 +66,7 @@ class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
|||
public function getIdent() {
|
||||
return $this->ident;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the content of the line
|
||||
* @return string
|
||||
|
@ -74,7 +74,19 @@ class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
|||
public function getData() {
|
||||
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
|
||||
* getData() on each of them to lay the data "bare"..
|
||||
|
@ -95,14 +107,14 @@ class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
|||
}
|
||||
return $rtn;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see ArrayAccess.offsetExists
|
||||
*/
|
||||
public function offsetExists( $param ) {
|
||||
return isset($this->params[ strtolower($param) ]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see ArrayAccess.offsetGet
|
||||
*/
|
||||
|
@ -112,7 +124,7 @@ class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
|||
return $this->params[ $index ];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Disabled ArrayAccess requirement
|
||||
* @see ArrayAccess.offsetSet
|
||||
|
@ -120,7 +132,7 @@ class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
|||
public function offsetSet( $param, $val ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Disabled ArrayAccess requirement
|
||||
* @see ArrayAccess.offsetUnset
|
||||
|
@ -128,7 +140,7 @@ class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
|||
public function offsetUnset( $param ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* toString method.
|
||||
* @see getData()
|
||||
|
@ -136,14 +148,14 @@ class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
|||
public function __toString() {
|
||||
return $this->getData();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see Countable.count
|
||||
*/
|
||||
public function count() {
|
||||
return count($this->params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see IteratorAggregate.getIterator
|
||||
*/
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?php
|
||||
<?php // BUILD: Remove line
|
||||
|
||||
class SG_iCal_Parser {
|
||||
/**
|
||||
|
@ -11,7 +11,7 @@ class SG_iCal_Parser {
|
|||
$content = self::UnfoldLines($content);
|
||||
self::_Parse( $content, $ical );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Passes a text string on to be parsed
|
||||
* @param string $content
|
||||
|
@ -21,7 +21,7 @@ class SG_iCal_Parser {
|
|||
$content = self::UnfoldLines($content);
|
||||
self::_Parse( $content, $ical );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fetches a resource and tries to make sure it's UTF8
|
||||
* encoded
|
||||
|
@ -29,7 +29,7 @@ class SG_iCal_Parser {
|
|||
*/
|
||||
protected static function Fetch( $resource ) {
|
||||
$is_utf8 = true;
|
||||
|
||||
|
||||
if( is_file( $resource ) ) {
|
||||
// The resource is a local file
|
||||
$content = file_get_contents($resource);
|
||||
|
@ -59,16 +59,16 @@ class SG_iCal_Parser {
|
|||
$is_utf8 = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( !$is_utf8 ) {
|
||||
$content = utf8_encode($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.
|
||||
* @param $content string
|
||||
*/
|
||||
|
@ -93,6 +93,7 @@ class SG_iCal_Parser {
|
|||
*/
|
||||
private static function _Parse( $content, SG_iCal $ical ) {
|
||||
$main_sections = array('vevent', 'vjournal', 'vtodo', 'vtimezone', 'vcalendar');
|
||||
$array_idents = array('exdate','rdate');
|
||||
$sections = array();
|
||||
$section = '';
|
||||
$current_data = array();
|
||||
|
@ -119,11 +120,16 @@ class SG_iCal_Parser {
|
|||
if( array_search($s, $sections) !== false ) {
|
||||
// This section is in the main section
|
||||
if( $section == $s ) {
|
||||
// It _is_ the main section
|
||||
$current_data[$s][$line->getIdent()] = $line;
|
||||
// It _is_ the main section else
|
||||
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 {
|
||||
// Sub section
|
||||
$current_data[$s][$section][$line->getIdent()] = $line;
|
||||
$current_data[$s][$section][$line->getIdent()] = $line;
|
||||
}
|
||||
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.
|
||||
*
|
||||
* The function is from the book "Building Scalable Web Sites" by
|
||||
* The function is from the book "Building Scalable Web Sites" by
|
||||
* Cal Henderson.
|
||||
*
|
||||
* @param string $data
|
||||
|
@ -181,7 +187,7 @@ class SG_iCal_Parser {
|
|||
$rx .= '|^[\x80-\xBF]';
|
||||
|
||||
return ( ! (bool) preg_match('!'.$rx.'!', $data) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -22,23 +22,23 @@ class SG_iCal_Query {
|
|||
if( $ical instanceof SG_iCalReader ) {
|
||||
$ical = $ical->getEvents();
|
||||
}
|
||||
if( !is_array($evs) ) {
|
||||
if( !is_array($ical) ) {
|
||||
throw new Exception('SG_iCal_Query::Between called with invalid input!');
|
||||
}
|
||||
|
||||
|
||||
$rtn = array();
|
||||
foreach( $evs AS $e ) {
|
||||
foreach( $ical AS $e ) {
|
||||
if( ($start <= $e->getStart() && $e->getStart() < $end)
|
||||
|| ($start < $e->getEnd() && $e->getEnd() <= $end) ) {
|
||||
|| ($start < $e->getRangeEnd() && $e->getRangeEnd() <= $end) ) {
|
||||
$rtn[] = $e;
|
||||
}
|
||||
}
|
||||
return $rtn;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns all events from the calendar after a given timestamp
|
||||
*
|
||||
*
|
||||
* @param SG_iCalReader|array $ical The calendar to query
|
||||
* @param int $start
|
||||
* @return SG_iCal_VEvent[]
|
||||
|
@ -50,19 +50,19 @@ class SG_iCal_Query {
|
|||
if( !is_array($ical) ) {
|
||||
throw new Exception('SG_iCal_Query::After called with invalid input!');
|
||||
}
|
||||
|
||||
|
||||
$rtn = array();
|
||||
foreach( $ical AS $e ) {
|
||||
if( $start <= $e->getStart() ) {
|
||||
if($e->getStart() >= $start || $e->getRangeEnd() >= $start) {
|
||||
$rtn[] = $e;
|
||||
}
|
||||
}
|
||||
return $rtn;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param SG_iCalReader|array $ical The calendar to query
|
||||
* @param string $column
|
||||
|
@ -75,7 +75,7 @@ class SG_iCal_Query {
|
|||
if( !is_array($ical) ) {
|
||||
throw new Exception('SG_iCal_Query::Sort called with invalid input!');
|
||||
}
|
||||
|
||||
|
||||
$cmp = create_function('$a, $b', 'return strcmp($a->getProperty("' . $column . '"), $b->getProperty("' . $column . '"));');
|
||||
usort($ical, $cmp);
|
||||
return $ical;
|
||||
|
|
|
@ -14,11 +14,13 @@
|
|||
*/
|
||||
class SG_iCal_Recurrence {
|
||||
|
||||
public $rrule;
|
||||
|
||||
protected $freq;
|
||||
|
||||
protected $until;
|
||||
protected $count;
|
||||
|
||||
|
||||
protected $interval;
|
||||
protected $bysecond;
|
||||
protected $byminute;
|
||||
|
@ -29,6 +31,7 @@ class SG_iCal_Recurrence {
|
|||
protected $byyearno;
|
||||
protected $bymonth;
|
||||
protected $bysetpos;
|
||||
|
||||
protected $wkst;
|
||||
|
||||
/**
|
||||
|
@ -40,7 +43,6 @@ class SG_iCal_Recurrence {
|
|||
'byyearday', 'byyearno', 'bymonth', 'bysetpos'
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -56,6 +58,8 @@ class SG_iCal_Recurrence {
|
|||
* @param string $line the line to be parsed
|
||||
*/
|
||||
protected function parseLine($line) {
|
||||
$this->rrule = $line;
|
||||
|
||||
//split up the properties
|
||||
$recurProperties = explode(';', $line);
|
||||
$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)
|
||||
* @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
|
||||
*/
|
||||
public function getUntil() {
|
||||
|
||||
return $this->getMember('until');
|
||||
}
|
||||
|
||||
|
|
|
@ -116,6 +116,6 @@ class VEventTest extends PHPUnit_Framework_TestCase {
|
|||
|
||||
date_default_timezone_set('America/New_York');
|
||||
$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 dirname(__FILE__).'/FreqTest.php';
|
||||
require_once dirname(__FILE__).'/RecurrenceTest.php';
|
||||
require_once dirname(__FILE__).'/DurationTest.php';
|
||||
|
||||
class Helpers_AllTests {
|
||||
|
||||
|
@ -9,6 +10,7 @@ class Helpers_AllTests {
|
|||
$suite = new PHPUnit_Framework_TestSuite('Helpers');
|
||||
$suite->addTestSuite('FreqTest');
|
||||
$suite->addTestSuite('RecurrenceTest');
|
||||
$suite->addTestSuite('DurationTest');
|
||||
|
||||
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,
|
||||
-1
|
||||
);
|
||||
|
||||
|
||||
$rule = 'FREQ=DAILY;COUNT=10';
|
||||
$start = strtotime('19970902T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testDailyUntil() {
|
||||
$dateset = array(
|
||||
873183600,
|
||||
|
@ -43,15 +43,15 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
873961200,
|
||||
874047600
|
||||
);
|
||||
|
||||
|
||||
$rule = 'FREQ=DAILY;UNTIL=19971224T000000Z';
|
||||
$start = strtotime('19970902T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
|
||||
|
||||
$freq = new SG_iCal_Freq($rule, $start);
|
||||
$this->assertEquals(882864000, $freq->previousOccurrence(time()));
|
||||
}
|
||||
|
||||
|
||||
public function testDailyInterval() {
|
||||
$dateset = array(
|
||||
873183600,
|
||||
|
@ -66,7 +66,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19970902T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testDailyIntervalCount() {
|
||||
$dateset = array(
|
||||
873183600,
|
||||
|
@ -80,7 +80,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19970902T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testDailyBydayBymonthUntil() {
|
||||
$rules = array(
|
||||
'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
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
foreach( $rules As $rule ) {
|
||||
$start = strtotime('19980101T090000');
|
||||
$this->assertRule( $rule, $start, $datesets[0]);
|
||||
|
||||
|
||||
$start = strtotime('+1 year', $start);
|
||||
$this->assertRule( $rule, $start, $datesets[1]);
|
||||
|
||||
|
||||
$start = strtotime('+1 year', $start);
|
||||
$this->assertRule( $rule, $start, $datesets[2]);
|
||||
|
||||
|
||||
$freq = new SG_iCal_Freq($rule, $start);
|
||||
$this->assertEquals(949305600, $freq->previousOccurrence(time()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function testWeeklyCount() {
|
||||
$dateset = array(
|
||||
873183600,
|
||||
|
@ -140,7 +140,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19970902T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testWeeklyUntil() {
|
||||
$dateset = array(
|
||||
873183600,
|
||||
|
@ -158,11 +158,11 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$rule = 'FREQ=WEEKLY;UNTIL=19971224T000000Z';
|
||||
$start = strtotime('19970902T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
|
||||
|
||||
$freq = new SG_iCal_Freq($rule, $start);
|
||||
$this->assertEquals(882864000, $freq->previousOccurrence(time()), 'Failed getting correct end date');
|
||||
}
|
||||
|
||||
|
||||
public function testWeeklyBydayLimit() {
|
||||
$rules = array(
|
||||
'FREQ=WEEKLY;UNTIL=19971007T000000Z;WKST=SU;BYDAY=TU,TH',
|
||||
|
@ -186,7 +186,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function testWeeklyIntervalUntilByday() {
|
||||
$dateset = array(
|
||||
873183600,
|
||||
|
@ -204,11 +204,11 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$rule = 'FREQ=WEEKLY;INTERVAL=2;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR';
|
||||
$start = strtotime('19970902T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
|
||||
|
||||
$freq = new SG_iCal_Freq($rule, $start);
|
||||
$this->assertEquals(882777600, $freq->previousOccurrence(time()), 'Failed getting correct end date');
|
||||
}
|
||||
|
||||
|
||||
public function testWeeklyIntervalBydayCount() {
|
||||
$dateset = array(
|
||||
873183600,
|
||||
|
@ -225,7 +225,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19970902T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testMonthlyBydayCount() {
|
||||
$dateset = array(
|
||||
873442800,
|
||||
|
@ -244,7 +244,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19970905T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testMonthlyBydayUntil() {
|
||||
$dateset = array(
|
||||
873442800,
|
||||
|
@ -257,7 +257,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19970905T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testMonthlyIntervalBydayCount2() {
|
||||
$dateset = array(
|
||||
873615600,
|
||||
|
@ -291,7 +291,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19970922T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testMonthlyBymonthday() {
|
||||
$dateset = array(
|
||||
875430000,
|
||||
|
@ -305,7 +305,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19970928T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testMonthlyBymonthdayCount() {
|
||||
$dateset = array(
|
||||
873183600,
|
||||
|
@ -324,7 +324,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19970902T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testMonthlyBymonthdayCount2() {
|
||||
$dateset = array(
|
||||
875602800,
|
||||
|
@ -343,7 +343,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19970930T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testMonthlyIntervalBymonthdayCount() {
|
||||
$dateset = array(
|
||||
873874800,
|
||||
|
@ -362,7 +362,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19970910T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testMonthlyIntervalByday() {
|
||||
$dateset = array(
|
||||
873183600,
|
||||
|
@ -380,7 +380,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19970902T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testYearlyCountBymonth() {
|
||||
$dateset = array(
|
||||
865926000,
|
||||
|
@ -399,7 +399,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19970610T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testYearlyIntervalCountBymonth() {
|
||||
$dateset = array(
|
||||
857980800,
|
||||
|
@ -418,7 +418,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19970310T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testYearlyIntervalCountByyearday() {
|
||||
$dateset = array(
|
||||
852105600,
|
||||
|
@ -437,7 +437,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19970101T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testYearlyByday() {
|
||||
$dateset = array(
|
||||
864025200,
|
||||
|
@ -448,7 +448,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19970519T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testYearlyByweeknoByday() {
|
||||
$dateset = array(
|
||||
863420400,
|
||||
|
@ -509,7 +509,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19970902T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testYearlyBydayBymonthday2() {
|
||||
$dateset = array(
|
||||
874134000,
|
||||
|
@ -527,7 +527,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19970913T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testYearlyIntervalBymonthBydayBymonthday() {
|
||||
$dateset = array(
|
||||
847180800,
|
||||
|
@ -538,9 +538,9 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19961105T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
// TODO: SETPOS rules
|
||||
|
||||
|
||||
public function testHourlyIntervalUntil() {
|
||||
$dateset = array(
|
||||
873183600,
|
||||
|
@ -552,7 +552,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19970902T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testMinutelyIntervalCount() {
|
||||
$dateset = array(
|
||||
873183600,
|
||||
|
@ -567,7 +567,7 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19970902T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testMinutelyIntervalCount2() {
|
||||
$dateset = array(
|
||||
873183600,
|
||||
|
@ -580,11 +580,11 @@ class FreqTest extends PHPUnit_Framework_TestCase {
|
|||
$start = strtotime('19970902T090000');
|
||||
$this->assertRule( $rule, $start, $dateset);
|
||||
}
|
||||
|
||||
|
||||
public function testMinutelyIntervalByhour() {
|
||||
$rules = array(
|
||||
'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
|
||||
$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';
|
||||
$start = strtotime('2009-10-27T090000');
|
||||
$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 ) {
|
||||
$freq = new SG_iCal_Freq($rule, $start);
|
||||
reset($dateset);
|
||||
$n = $start - 1;
|
||||
do {
|
||||
$n = $freq->findNext($n);
|
||||
//echo date('Y-m-d H:i:sO ',$n);
|
||||
$e = (current($dateset) != -1) ? current($dateset) : false;
|
||||
$this->assertEquals($e, $n);
|
||||
} 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