diff --git a/LICENSE b/LICENSE index 4280d79..f72a2c5 100755 --- a/LICENSE +++ b/LICENSE @@ -20,8 +20,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------ -Based on Python's dateutil. +------------------------ +Based on python-dateutil. LICENSE: dateutil - Extensions to the standard Python datetime module. diff --git a/README.md b/README.md index bb34e9a..855d9a7 100755 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # RRULE for PHP -Lightweight and fast implementation of recurrence rules for PHP (RFC 5545). +Lightweight and fast implementation of recurrence rules for PHP (RFC 5545), to easily work with recurring dates and events (such as in a calendar). +This library is heavily based on [python-dateutil](https://labix.org/python-dateutil). [![Build Status](https://travis-ci.org/rlanvin/php-rrule.svg?branch=master)](https://travis-ci.org/rlanvin/php-rrule) @@ -38,7 +39,7 @@ Complete doc is available in [the wiki](https://github.com/rlanvin/php-rrule/wik ## Installation This is still a work in progress, use at your own risk! -In particular, HOURLY, MINUTELY and SECONDELY frequencies are not implemented. +In particular, HOURLY, MINUTELY and SECONDLY frequencies are not implemented. The recommended way is to install the lib [through Composer](http://getcomposer.org/). @@ -63,7 +64,8 @@ require 'vendor/autoload.php'; ### Alternative method -You can download `src/RRule.php` and require it. +Since it's a no-nonsense implementation, there is only one class. +So you can just download `src/RRule.php` and require it. ## Note @@ -71,12 +73,12 @@ I started this library because I wasn't happy with the existing implementations in PHP. The ones I tested were slow and/or had a very awkward/verbose API that I didn't like to use. They were also all missing a generator/iterator, which I think is key. So I thought it would be a good learning project to port the -Python dateutil/rrule.py class into PHP. +python-dateutil rrule implementation into PHP. -The Python lib was a bit difficult to understand at first. The algorithms -used are very smart (and fast), but they not commented and the variables are -very opaque (I'm looking at you `lno1wkst`). I tried to comment and -explain most of the algorithm in this PHP port, so feel free to check the code. +The Python lib was a bit difficult to understand because the algorithms (very smart by the way), +are not commented and the variables are very opaque (I'm looking at +you `lno1wkst`). I tried to comment and explain as much of the algorithm as possible +in this PHP port, so feel free to check the code if you're interested. The lib differs from the python version in various aspects, notably in the respect of the RFC. This version is strictier and will not accept many diff --git a/src/RRule.php b/src/RRule.php index 9b8de77..7a061c9 100755 --- a/src/RRule.php +++ b/src/RRule.php @@ -1,25 +1,19 @@ + * @link https://github.com/rlanvin/php-rrule */ namespace RRule; /** + * Check that a variable is not empty. 0 and '0' are considered NOT empty + * * @return bool */ function not_empty($var) @@ -54,6 +48,7 @@ function pymod($a, $b) } /** + * Check is a year is a leap year. * @return bool */ function is_leap_year($year) @@ -71,7 +66,22 @@ function is_leap_year($year) } /** - * Main class. + * Implementation of RRULE as defined by RFC 5545. + * Heavily based on python-dateutil/rrule + * + * Some useful terms to understand the algorithms and variables naming: + * + * yearday = day of the year, from 0 to 365 (on leap years) - date('z') + * weekday = day of the week (ISO-8601), from 1 (MO) to 7 (SU) - date('N') + * monthday = day of the month, from 1 to 31 + * wkst = week start, the weekday (1 to 7) which is the first day of week. + * Default is Monday (1). In some countries it's Sunday (7). + * weekno = number of the week in the year (ISO-8601) + * + * CAREFUL with this bug: https://bugs.php.net/bug.php?id=62476 + * + * @see https://tools.ietf.org/html/rfc5545 + * @see https://labix.org/python-dateutil */ class RRule implements \Iterator, \ArrayAccess { @@ -950,7 +960,7 @@ class RRule implements \Iterator, \ArrayAccess } /** - * This is the main method, where all of the logic happens. + * This is the main method, where all of the magic happens. * * This method is a generator that works for PHP 5.3/5.4 (using static variables) */ @@ -1125,10 +1135,8 @@ class RRule implements \Iterator, \ArrayAccess // at the same time, we check the end condition and return null if // we need to stop while ( ($yearday = current($current_set)) !== false ) { - // $occurrence = date('Y-m-d', mktime(0, 0, 0, 1, ($yearday + 1), $year)); -// echo "\t occurrence (mktime) = ", $occurrence,"\n"; $occurrence = \DateTime::createFromFormat('Y z', "$year $yearday"); -// echo "\t occurrence (before time) =", $occurrence->format('r'),"\n"; + while ( ($time = current($timeset)) !== false ) { $occurrence->setTime($time[0], $time[1], $time[2]); // consider end conditions @@ -1169,13 +1177,11 @@ class RRule implements \Iterator, \ArrayAccess } break; case self::WEEKLY: - // here we take a little shortcut from the Python version, by using date/time methods - // list($year,$month,$day) = explode('-',date('Y-m-d',strtotime('+'.($this->interval*7).'day', mktime(0,0,0,$month,$day,$year)))); + // here we take a little shortcut from the Python version, by using DateTime list($year,$month,$day) = explode('-',(new \DateTime("$year-$month-$day"))->modify('+'.($this->interval*7).'day')->format('Y-n-j')); break; case self::DAILY: - // here we take a little shortcut from the Python version, by using date/time methods - // list($year,$month,$day) = explode('-',date('Y-m-d',strtotime('+'.$this->interval.'day', mktime(0,0,0,$month,$day,$year)))); + // here we take a little shortcut from the Python version, by using DateTime list($year,$month,$day) = explode('-',(new \DateTime("$year-$month-$day"))->modify('+'.$this->interval.'day')->format('Y-n-j')); break; case self::HOURLY: