Giter Site home page Giter Site logo

simshaun / recurr Goto Github PK

View Code? Open in Web Editor NEW
1.2K 34.0 132.0 346 KB

PHP library for working with recurrence rules (RRULE); meant to help with recurring calendar events.

License: Other

PHP 99.83% PowerShell 0.09% Shell 0.09%
php recurring-events recurrence recurrence-rules

recurr's Introduction

Recurr

tests Latest Stable Version Total Downloads Latest Unstable Version License

Recurr is a PHP library for working with recurrence rules (RRULE) and converting them in to DateTime objects.

Recurr was developed as a precursor for a calendar with recurring events, and is heavily inspired by rrule.js.

Installing Recurr

The recommended way to install Recurr is through Composer.

composer require simshaun/recurr

Using Recurr

Creating RRULE rule objects

You can create a new Rule object by passing the (RRULE) string or an array with the rule parts, the start date, end date (optional) and timezone.

$timezone    = 'America/New_York';
$startDate   = new \DateTime('2013-06-12 20:00:00', new \DateTimeZone($timezone));
$endDate     = new \DateTime('2013-06-14 20:00:00', new \DateTimeZone($timezone)); // Optional
$rule        = new \Recurr\Rule('FREQ=MONTHLY;COUNT=5', $startDate, $endDate, $timezone);

You can also use chained methods to build your rule programmatically and get the resulting RRULE.

$rule = (new \Recurr\Rule)
    ->setStartDate($startDate)
    ->setTimezone($timezone)
    ->setFreq('DAILY')
    ->setByDay(['MO', 'TU'])
    ->setUntil(new \DateTime('2017-12-31'))
;

echo $rule->getString(); //FREQ=DAILY;UNTIL=20171231T000000;BYDAY=MO,TU

RRULE to DateTime objects

$transformer = new \Recurr\Transformer\ArrayTransformer();

print_r($transformer->transform($rule));
  1. $transformer->transform(...) returns a RecurrenceCollection of Recurrence objects.
  2. Each Recurrence has getStart() and getEnd() methods that return a \DateTime object.
  3. If the transformed Rule lacks an end date, getEnd() will return a \DateTime object equal to that of getStart().

Note: The transformer has a "virtual" limit (default 732) on the number of objects it generates. This prevents the script from crashing on an infinitely recurring rule. You can change the virtual limit with an ArrayTransformerConfig object that you pass to ArrayTransformer.

Transformation Constraints

Constraints are used by the ArrayTransformer to allow or prevent certain dates from being added to a RecurrenceCollection. Recurr provides the following constraints:

  • AfterConstraint(\DateTime $after, $inc = false)
  • BeforeConstraint(\DateTime $before, $inc = false)
  • BetweenConstraint(\DateTime $after, \DateTime $before, $inc = false)

$inc defines what happens if $after or $before are themselves recurrences. If $inc = true, they will be included in the collection. For example,

$startDate   = new \DateTime('2014-06-17 04:00:00');
$rule        = new \Recurr\Rule('FREQ=MONTHLY;COUNT=5', $startDate);
$transformer = new \Recurr\Transformer\ArrayTransformer();

$constraint = new \Recurr\Transformer\Constraint\BeforeConstraint(new \DateTime('2014-08-01 00:00:00'));
print_r($transformer->transform($rule, $constraint));

Note: If building your own constraint, it is important to know that dates which do not meet the constraint's requirements do not count toward the transformer's virtual limit. If you manually set your constraint's $stopsTransformer property to false, the transformer might crash via an infinite loop. See the BetweenConstraint for an example on how to prevent that.

Post-Transformation RecurrenceCollection Filters

RecurrenceCollection provides the following chainable helper methods to filter out recurrences:

  • startsBetween(\DateTime $after, \DateTime $before, $inc = false)
  • startsBefore(\DateTime $before, $inc = false)
  • startsAfter(\DateTime $after, $inc = false)
  • endsBetween(\DateTime $after, \DateTime $before, $inc = false)
  • endsBefore(\DateTime $before, $inc = false)
  • endsAfter(\DateTime $after, $inc = false)

$inc defines what happens if $after or $before are themselves recurrences. If $inc = true, they will be included in the filtered collection. For example,

pseudo...
2014-06-01 startsBetween(2014-06-01, 2014-06-20) // false
2014-06-01 startsBetween(2014-06-01, 2014-06-20, true) // true

Note: RecurrenceCollection extends the Doctrine project's ArrayCollection class.

RRULE to Text

Recurr supports transforming some recurrence rules into human readable text. This feature is still in beta and only supports yearly, monthly, weekly, and daily frequencies.

$rule = new Rule('FREQ=YEARLY;INTERVAL=2;COUNT=3;', new \DateTime());

$textTransformer = new TextTransformer();
echo $textTransformer->transform($rule);

If you need more than English you can pass in a translator with one of the supported locales (see translations folder).

$rule = new Rule('FREQ=YEARLY;INTERVAL=2;COUNT=3;', new \DateTime());

$textTransformer = new TextTransformer(
    new \Recurr\Transformer\Translator('de')
);
echo $textTransformer->transform($rule);

Warnings

  • **Monthly recurring rules ** By default, if your start date is on the 29th, 30th, or 31st, Recurr will skip following months that don't have at least that many days. (e.g. Jan 31 + 1 month = March)

This behavior is configurable:

$timezone    = 'America/New_York';
$startDate   = new \DateTime('2013-01-31 20:00:00', new \DateTimeZone($timezone));
$rule        = new \Recurr\Rule('FREQ=MONTHLY;COUNT=5', $startDate, null, $timezone);
$transformer = new \Recurr\Transformer\ArrayTransformer();

$transformerConfig = new \Recurr\Transformer\ArrayTransformerConfig();
$transformerConfig->enableLastDayOfMonthFix();
$transformer->setConfig($transformerConfig);

print_r($transformer->transform($rule));
// 2013-01-31, 2013-02-28, 2013-03-31, 2013-04-30, 2013-05-31

Contribute

Feel free to comment or make pull requests. Please include tests with PRs.

License

Recurr is licensed under the MIT License. See the LICENSE file for details.

recurr's People

Contributors

a-am avatar agonirena avatar ankurk91 avatar anvyst avatar avr avatar barryvdh avatar codeartisanorg avatar dragosprotung avatar efiware avatar ektarum avatar emnsen avatar fentie avatar foaly-nr1 avatar houseoftech avatar inghamn avatar inmula avatar jarofgreen avatar joakimhising avatar libertjeremy avatar mandclu-acquia avatar pborreli avatar pmeth avatar robinvda avatar romainnorberg avatar scullwm avatar seldaek avatar simshaun avatar spapad avatar sspruijt avatar williamdes avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

recurr's Issues

Fatal error: Uncaught exception 'Exception' with message 'DateTime::__construct() expects parameter 1 to be string, object given' in .../vendor/simshaun/recurr/src/Recurr/Rule.php:1072

Fatal error: Uncaught exception 'Exception' with message 'DateTime::__construct() expects parameter 1 to be string, object given' in /var/www/misc/vendor/simshaun/recurr/src/Recurr/Rule.php:1072
Stack trace:
#0 /var/www/misc/vendor/simshaun/recurr/src/Recurr/Rule.php(1072): DateTime->__construct(Object(Recurr\DateExclusion), Object(DateTimeZone))
#1 /var/www/misc/recurr.php(15): Recurr\Rule->setExDates(Array)
#2 {main}
  thrown in .../vendor/simshaun/recurr/src/Recurr/Rule.php on line 1072

Solution is easy

public function setExDates(array $exDates)
{
    $timezone = new \DateTimeZone($this->getTimezone());

    foreach ($exDates as $key => $val) {
        if ($val instanceof DateExclusion) {
            $val->date = $this->convertZtoUtc($val->date);
        } else {
            $date          = new \DateTime($val, $timezone);
            $exDates[$key] = new DateExclusion(
                $this->convertZtoUtc($date),
                strpos($val, 'T') !== false,
                strpos($val, 'Z') !== false
            );
        }
    }

    $this->exDates = $exDates;
}

No support for weekno of monthly recurrence?

Standard recurrence have the option to specify a week number for a monthly recurrence. Creating such a recurrence in Google calendar provides an RRule such as this for the first Wednesday of the every month

FREQ=MONTHLY;BYDAY=1WE;INTERVAL=1

From what I can tell, there is no support for this, although I do see this.byweekday.someWeeks in nlp.js, which seems to perhaps be this support, though I cannot figure out how to modify this property to get it to work correctly.

Any help would be much appreciated.

Constraint doesn't consider RRULE COUNT part

\Recurr\Transformer\Constraint\* doesn't consider RRULE COUNT value. Also notice if I replace COUNT with UNTIL - it works!

So here's example

$timezone  = 'America/Vancouver';
$startDate = new \DateTime('2014-08-01 15:00:00', new \DateTimeZone($timezone));
$endDate   = new \DateTime('2014-08-01 17:00:00', new \DateTimeZone($timezone));
$rule      = new \Recurr\Rule('FREQ=DAILY;COUNT=2', $startDate, $endDate, $timezone);
// $rule      = new \Recurr\Rule('FREQ=DAILY;UNTIL=20140802T170000', $startDate, $endDate, $timezone);


$after      = new \DateTime('2014-08-03 00:00:00', new \DateTimeZone($timezone));
$before     = new \DateTime('2014-08-10 00:00:00', new \DateTimeZone($timezone));
$constraint = new \Recurr\Transformer\Constraint\BetweenConstraint($after, $before, true);


$transformer = new \Recurr\Transformer\ArrayTransformer();
// expect 0 instances, actually 2 returned
print_r($transformer->transform($rule, null, $constraint));

Request: Iteration in recurrence object

Is there any way you could add another property to the recurrence class? An iteration that lets me know which instance of the recurring event I am referring to.

You see, I am generating events based on a recurring rule, and need to be able to reference the specific event instance.

Right now, I am doing that based on the start time, but this is difficult working with timezones, and if for whatever reason the start time is changed, it will no longer reference correctly.

I need something to uniquely identify that specific recurrence. I'm only a junior programmer, but if there were a way you could generate a a series of unique keys for each instance that could be referenced by and event key, that would be great.

for example

$rule = new \Recurr\Rule($event->rrule, $startDate, $endDate, $timezone, $event->unique_id);

$recurrence = $transformer->transform($rule, NULL, $this->constraint);

foreach($recurrence as $occurrence) {
    $occurrence->unique_id = /*some hashed id that will always be the same even if I constrain it*/;
}

I'm not even entirely sure this is possible, but it would be a very useful addition. Thanks for the great package. :)

Refactor

Several classes need major cleanup. Most importantly, RecurrenceRuleTransformer.

I plan on releasing the refactored code base in v0.2. It most likely will not contain any BC breaks.

Clarification required on endDate

Could someone please explain the following to me. The following example returns 5 results for me. Whilst I understand that the rule has a count of 5 I don't understand why the endDate would be ignored.

If I change the endDate to be 2014-06-14 20:00:00 with no count I was expect 12 dates but I get 731. I read in the documentation that this would only occur if no endDate was suppplied. Am I missing something? Thank you in advanced.

 $timezone    = 'America/New_York';
 $startDate   = new \DateTime('2013-06-12 20:00:00', new \DateTimeZone($timezone));
 $endDate     = new \DateTime('2013-06-14 20:00:00', new \DateTimeZone($timezone)); // Optional
 $rule        = new \Recurr\Rule('FREQ=MONTHLY;COUNT=5', $startDate, $endDate, $timezone);
 $transformer = new \Recurr\Transformer\ArrayTransformer();

 print_r($transformer->transform($rule));

Last commit not tagged

Hello,

Can you drop a 0.1.1 tag on the last bugfix you made ?
This way it will be much easier to integrate with composer.

Thanks !

enableLastDayOfMonthFix() Bug

It seems that enableLastDayOfMonthFix() is erroneously adding additional days to 30-day months when instantiated for a monthly event on the 29th. Commenting out the fix method produces the expected result.

Code:

$timezone    = 'America/New_York';

$startDate   = new \DateTime('2014-08-29 16:30:00', new \DateTimeZone($timezone));
$endDate     = new \DateTime('2014-08-29 18:30:00', new \DateTimeZone($timezone)); // Optional
$rule        = new \Recurr\Rule('FREQ=MONTHLY;COUNT=50', $startDate, $endDate, $timezone);
$transformer = new \Recurr\Transformer\ArrayTransformer();

$transformerConfig = new \Recurr\Transformer\ArrayTransformerConfig();
$transformerConfig->enableLastDayOfMonthFix();
$transformer->setConfig($transformerConfig);

print_r($transformer->transform($rule));

Result (partial):

[date] => 2014-08-29 16:30:00.000000
โ€ฆ
[date] => 2014-09-29 16:30:00.000000
โ€ฆ
[date] => 2014-09-30 16:30:00.000000
โ€ฆ
[date] => 2014-10-29 14:30:00.000000

Request: Support for Rdate

It would be fantastic if you included support for RDATE (as defined in rfc 5545). As EXDATE is already implemented, it is quite natural also to include RDATE.

Looping Recurring Dates Return Empty

Hi,

I want to loop through recurring dates but always return empty when to print date variable. But the strange one is if I turn on the "print_r", the date variable can be echoed out.

I'm using PHP 5.4.25

$timezone    = 'America/New_York';
$startDate   = new \DateTime('2013-06-12 20:00:00', new \DateTimeZone($timezone));
$rule        = new \Recurr\RecurrenceRule('FREQ=MONTHLY;COUNT=5', $startDate, $timezone);
$transformer = new \Recurr\RecurrenceRuleTransformer($rule);

$recurrDates = $transformer->getComputedArray();

//print_r($recurrDates); // if it is not commented, the "->date" can be echoed out

foreach($recurrDates as $recurrDate) {          
      echo $recurrDate->date . '<br />'; // always return empty
}

is anybody has same problem?

Thank you

Apply before/after/between to Transformer instead of it's results?

I hoped that between/before/after feature will help to make collection returned by the transformer to be smaller, but it looks like that those methods are applied to transformer result instead. Would it be possible to apply the new features mentioned to the transformer instead?

If for example I have a daily recurring event that started 10 years ago and I pass that start date into the transformer, I won't be able to retrieve event for today because of the virtual limit, (more than 732 events before today's one). I guess I could raise the limit via setVirtualLimit(), but I don't think that's the solution, since the same problem would appear after a few years. I've even also tried with using different start date for transformer, but that seems to change events times. Is there a workaround for this that I'm missing?

Conflict with Doctrine

I'm having this issue while trying to install Recurr via composer:

  Problem 1
    - Installation request for simshaun/recurr ^0.4.4 -> satisfiable by simshaun/recurr[v0.4.4].
    - Conclusion: remove doctrine/collections v1.3.0
    - Conclusion: don't install doctrine/collections v1.3.0
    - simshaun/recurr v0.4.4 requires doctrine/collections 1.2.* -> satisfiable by doctrine/collections[v1.2, v1.2.1].
    - Can only install one of: doctrine/collections[v1.2, v1.3.0].
    - Can only install one of: doctrine/collections[v1.2.1, v1.3.0].
    - Installation request for doctrine/collections == 1.3.0.0 -> satisfiable by doctrine/collections[v1.3.0].

It seems like a bad idea to downgrade Doctrine ... Have you guys any intention of fixing the conflict ?

setStartDate and php versions

Hi,

When I use setStartDate from Rule class, I got differents results depending on PHP version (5.3 vs 5.4).
For example

$rule = Recurr\Rule::createFromString('FREQ=WEEKLY;COUNT=30;WKST=MO;BYDAY=WE,TH,FR');
$rule->setStartDate(new \Datetime('monday next week'));
$transformer = new \Recurr\Transformer\ArrayTransformer();
$datecollection = $transformer->transform($rule);

In php 5.3 first results are '2015-11-07', '2015-11-08' and they are wrong.
In php 5.4 first results are '2015-11-04', '2015-11-05', '2015-11-05' and they are right.

Any idea on how to store the recurrence events information in database

First of all, thanks for such a great library.

I would like to store the event information in RDMS. I am not sure in which format can store the recurring events (especially events which has no end date). If any one has any idea, then please share your ideas and it would be much appreciated.

Thanks

Rule with BYDAY throws error.

Whenever I have a rule with weekly and the days it throws an error on line 133 of the DateUtil.php.

FREQ=WEEKLY;DTSTART=20140128T070000Z;COUNT=25;BYDAY=MO,WE,FR

ArrayTransformer on counted rule

Hi,

I have something strange while generating recurr.
My recurrence rule is pretty simple:
It start and end the same day, few week ago, and have a count at 1 (repeat one) daily.
Here is the Rule Object : https://www.dropbox.com/s/tdzf9e7jf1oh5qo/Capture%20d%27%C3%A9cran%202014-12-04%2018.17.07.png?dl=0

But when I use the transform with this rule, with date selected this week, I should not have a recurr generated, i should get an empty collection. (rule on november 1, on daily recurrence, count = 1, BetweenConstraint('2014-12-04 00:00:00', '2014-12-09 00:00:00') )
But it still "transform" one element with the current day...

Any idea ?

FREQ is required in a complex recurrence

Why I get this kind of recurrence by Google Calendar and how have I to handle them?
schermata 2015-01-12 alle 19 14 44

array (size=2)
  0 => string 'EXDATE;TZID=Europe/Prague:20131028T210000,20131111T210000' (length=57)
  1 => string 'RRULE:FREQ=WEEKLY;UNTIL=20131124T225959Z;BYDAY=MO' (length=49)

Support for DTEND value

Hi,

Are you planning to add support for DTEND value? I find it pretty useful, especially when you render events on a "day" calendar layout.

Until date should be inclusive

Inside ArrayTransformer the comparison:

foreach ($datesAdj as $dtTmp) {
                    if (null !== $until && $dtTmp > $until) {
                        $continue = false;
                        break;
                    }

$until date isn't included. I checked behavior of rrule.js and Google Calendar and they include the until date.

BetweenConstraint bug

BetweenConstraint doesnot count "RRULE:COUNT" from the startDate, it's counting recurrences from the $after variable

$startDate    = '2015-05-30';
$rrule        = 'FREQ=WEEKLY;COUNT=3;BYDAY=SA';
$rule         = new \Recurr\Rule($rrule, $startDate);
$transformer  = new \Recurr\Transformer\ArrayTransformer();

$result = $transformer->transform($rule, null, null);

OUTPUT:
2015-05-30
2015-06-06
2015-06-13

$after        = '2015-06-01';
$before       = '2015-07-06';

$rule         = new \Recurr\Rule($rrule, $startDate);
$transformer  = new \Recurr\Transformer\ArrayTransformer();
$constraint   = new \Recurr\Transformer\Constraint\BetweenConstraint(new \DateTime($after), new  \DateTime($before), true);

$result = $transformer->transform($rule, null, $constraint);

OUTPUT:
2015-06-06
2015-06-13
2015-06-20

determining if a rule is currently valid

I am currently storing a series of events that are defined by rrules

I'd like to know what is the best way to check if a rrule is "valid" ie: the event should be triggered.

Effectively I need to check is time() is greater than any of the rrule entries in an rrule collection.

I don't expect there to be thousands of rrules so I'm assuming I could

  • query the db every minutes for the events
  • generate a collection
  • check if time() > rrule
  • if so trigger event

Does this make sense ? Is there a better approach.

Thinking aloud can I ask for the next event as defined by an rrule ?

Provide friendly text output

I just implemented this in a new project - working great so far. Thanks!

I was wondering if you have thought about providing a way to convert a RRULE to friendly text. I.E. "Every month on the 1st and 15th".

I've looked at the JS library you reference, but I'd rather do this server side instead of including extra JS.

Wrong dates returnd

rrule i have : FREQ=YEARLY;DTSTART=20120229T023000Z;COUNT=5

I didn't make any (config) changes to library and assuming see the below comments in library code.

/**
 * By default, January 30 + 1 month results in March 30 because February doesn't have 30 days.
 *
 * Enabling this fix tells Recurr that +1 month means "last day of next month".
 */
public function enableLastDayOfMonthFix()
{
    $this->lastDayOfMonthFix = true;
}

I was expecting every 4 years as it was on feb29, but it gives below, am i missing any configuration.

array(

[0] => DateTime Object
    (
        [date] => 2012-02-29 08:00:00
        [timezone_type] => 3
        [timezone] => Asia/Kolkata
    )

[1] => DateTime Object
    (
        [date] => 2013-02-28 08:00:00
        [timezone_type] => 3
        [timezone] => Asia/Kolkata
    )

[2] => DateTime Object
    (
        [date] => 2014-02-28 08:00:00
        [timezone_type] => 3
        [timezone] => Asia/Kolkata
    )

[3] => DateTime Object
    (
        [date] => 2015-02-28 08:00:00
        [timezone_type] => 3
        [timezone] => Asia/Kolkata
    )

[4] => DateTime Object
    (
        [date] => 2016-02-29 08:00:00
        [timezone_type] => 3
        [timezone] => Asia/Kolkata
    )

)

BetweenConstraint 'after' DateTime object returning current time

I am having an issue with the restraint system. I can get the correct recurrences without a restraint, but once I try creating one, it defaults the 'after' Date Time object to the current date/time, and the 'before' DateTime keeps it's 10 day distance, but not from the date I provided, it is now from the current date/time... Here is the code I am using.

$endRestraint = new DateTime($this->day_definition);

$constraint = new \Recurr\Transformer\Constraint\BetweenConstraint(new DateTime($this->day_definition, new \DateTimeZone($timezone)), $endRestraint->add(new DateInterval('P10D')), TRUE); 
            $recurr = $transformer->transform($rule, NULL,  $constraint);

It's probably not a bug, but rather my own mistake, but any help is greatly appreciated.

Is there any way to handle multiple specific dates of a month every year?

I've been playing around with a variety of attempts to get this working but can't see a way to make it happen.

Example: recurring every year on the 9th January and the 15th of March

If I use

FREQ=YEARLY;BYMONTH=1,3;BYMONTHDAY=9,15;

Then I get, as expected, 9th Jan, 15th Jan, and 9th Mar, 15th Mar.

If I try

FREQ=YEARLY;BYYEARDAY=9,74;

Then it works for for this year, but next year is the March date is different due to a differing number of days in Feb (again this is expected!).

I've been digging through the rule examples and can't find any that would match the example at the top though.

For the time being I'm just going to force the user to create different recurring schedules for each 'by year date' rule, but I'd be intrigued to see if this sort of dynamic recurring rule on different dates per month could be handled.

Thanks again for all your work on this package - saves me such a lot of headache!

RecurrenceRuleTransformer retrieval methods

Are you planning to add between, before and after methods to the RecurrenceRuleTransformer by analogy to the rrule.js#occurrence-retrieval-methods?
The most important is between as we usually return recurring events for a certain period. $virtualLimit does not help here as I don't know how many instances fall into the period.

And while I'm at it, how about BC breaking refactor for RecurrenceRuleTransformer!? It accepts TransformerConfig and $virtualLimit in constructor and recurrence rule in getComputedArray method lest to instantiate it on every rule. Additionally getComputedArray can accept $virtualLimit as an optional second parameter for flexibility.

Also I'm not sure I understand why RecurrenceRule::createFromString is not a static method which eventually returns an instance of RecurrenceRule?

Minimum version of PHP?

What is the minimum version of PHP safe to use recurr with?

I ask because I would like to use it in a WordPress plugin. Since the minimum version of WordPress is 5.2.4, there will likely be users on servers still running 5.2.

Thank you.

EXDATE dates not being excluded

Here is an output of of the rule. FREQ=DAILY;COUNT=4;DTSTART=20140813T180000Z;EXDATE=20140814T000000Z
Here it is in Recurr\Rule from PHP.

 Recurr\Rule#1
(
    [*:timezone] => 'UTC'
    [*:startDate] => DateTime#2
    (
        [date] => '2014-08-13 18:00:00'
        [timezone_type] => 2
        [timezone] => 'Z'
    )
    [*:endDate] => null
    [*:isStartDateFromDtstart] => true
    [*:freq] => 3
    [*:interval] => 1
    [*:until] => null
    [*:count] => 4
    [*:bySecond] => null
    [*:byMinute] => null
    [*:byHour] => null
    [*:byDay] => null
    [*:byMonthDay] => null
    [*:byYearDay] => null
    [*:byWeekNumber] => null
    [*:byMonth] => null
    [*:weekStart] => 'MO'
    [*:days] => array
    (
        'MO' => 0
        'TU' => 1
        'WE' => 2
        'TH' => 3
        'FR' => 4
        'SA' => 5
        'SU' => 6
    )
    [*:bySetPosition] => null
    [*:exDates] => array
    (
        0 => Recurr\DateExclusion#3
        (
            [date] => DateTime#4
            (
                [date] => '2014-08-14 00:00:00'
                [timezone_type] => 3
                [timezone] => 'UTC'
            )
            [hasTime] => true
            [isUtcExplicit] => true
        )
    )
)

When I run the transform the date is not excluded from the set. Not sure if this is a bug or something I am not doing properly. I have the latest stable version installed.

Using TextTransformer on rules that use +X syntax

The TextTransformer is an awesome idea but I came across an issue where it throws an exception with certain rule types.

So

$rule = new Rule('FREQ=WEEKLY;INTERVAL=2;BYDAY=SU;UNTIL=2014-12-31;', new \DateTime());
$textTransformer = new TextTransformer();
return $textTransformer->transform($rule);

this works fine, and as expected states "every 2 weeks on Sunday until December 31, 2014"

However if I have a rule that is set to recurr on the 1st and 3rd Sundays of each month, eg:

$rule = new Rule('FREQ=MONTHLY;BYDAY=+1SU,+3SU;UNTIL=2015-01-01 00:00:00', new \DateTime());

$textTransformer = new TextTransformer();
return $textTransformer->transform($rule);

Then this throws an exception "byDay +1SU could not be transformed".

Perhaps I'm going about creating this RRule in the wrong way?

I've been compiling some sample rules so I could get my head around things. I think the only ones that might be causing issues are the nth specifications.

// Every year on the 1st of June
$sampleRule = 'FREQ=YEARLY;BYMONTH=6;BYMONTHDAY=1;UNTIL=2016-01-01 00:00:00';

// Every year on the 2nd Sunday of the Year
$sampleRule = 'FREQ=YEARLY;BYDAY=+2SU;UNTIL=2016-01-01 00:00:00';

// Every Sunday
$sampleRule = 'FREQ=WEEKLY;BYDAY=SU;UNTIL=2014-02-01 00:00:00';

// Every Second Sunday
$sampleRule = 'FREQ=WEEKLY;INTERVAL=2;BYDAY=SU;UNTIL=2014-02-01 00:00:00';

// Every day of the week
$sampleRule = 'FREQ=DAILY;UNTIL=2014-01-07 00:00:00';

// Every day of the week except Saturdays and Sundays
$sampleRule = 'FREQ=DAILY;BYDAY=MO,TU,WE,TH,FR;UNTIL=2014-01-07 00:00:00';

// Every Month on the 31st of the month (automatically skips months that don't have that date)
$sampleRule = 'FREQ=MONTHLY;BYMONTHDAY=31;UNTIL=2015-01-01 00:00:00';

// First Sunday of every month
$sampleRule = 'FREQ=MONTHLY;BYDAY=+1SU;UNTIL=2015-01-01 00:00:00';

// First and third Sunday of every month
$sampleRule = 'FREQ=MONTHLY;BYDAY=+1SU,+3SU;UNTIL=2015-01-01 00:00:00';

// Fortnightly on Thursdays and Saturdays
$sampleRule = 'FREQ=WEEKLY;INTERVAL=2;BYDAY=TH,SA;UNTIL=2014-06-01 00:00:00';

Skips months

Just FYI, I recently had to roll my own recurrence library before I found yours. I was checking out yours to possibly replace the one I wrote. After looking at it, I found a few issues with calculating future dates based on a monthly recurrence.


If my start date is on the 31st, it'll skip all the months that don't have 31 days.

Input

2013-01-31
Monthly

Output

2013-01-31
2013-03-31
2013-05-31
2013-07-31
2013-08-31

Also, if my start date is the last day of its month, I would expect all monthly frequencies to also be on the last day of each subsequent month.

Input

2013-02-28
Monthly

Output

2013-03-28 - (and doesn't include the first date, like the first example did)
2013-04-28
2013-05-28
2013-06-28
2013-07-28

BYDAY=20MO causes error

Results in "Undefined offset: 2" in RecurrenceRule::getByDayTransformedToWeekdays line 762.

rule.toText()

Is this functionality available in this library? Please let me know if it is supported. Thanks in advance.

Doctrine class not found

Hi,

I installed vendor classes using composer. The vendor folder is downloaded where the src folder located like below

src
tests
vendor

I copied 'Doctrine' folder from lib and placed inside the src\Recurr\ folder but the below error occurs when I get recurrence collections.

Fatal error: Class 'Doctrine\Common\Collections\ArrayCollection' not found in APP_PATH\app\plugins\recurr\src\Recurr\RecurrenceCollection.php on line 19

getString issue with DTSTART

The string being returned by Recurr isn't playing nice with rrule.js library, a Z is missing at the end of DTSTART. The javascript error I get is:

Uncaught Error: Invalid UNTIL value: 20140911T020000

However if I modify the getString method and add a Z at the end of the DTSTART being generated it works fine.

BYMONTHDAY ignoring first reccurence

Setting a simple RRULE:FREQ=MONTHLY;BYMONTHDAY=1,8,15,22,29 ignores the first reccurence as shown in the image bellow.
preview
Not sure what causes the problem, it seems to ocurr only for certain event_start, event_end, rrule settings. Note, that I'm also using BetweenConstraint with first and the last day visible in my calendar view.
Here's my function for generating recurring events:

  $data = array(
    'start' => '2015-04-02 08:00:00',
    'end' => '2015-04-03 09:00:00',
    'rrule' => 'RRULE:FREQ=Monthly;BYMONTHDAY=1,8,15,22,29' 
  )

  $start = '2015-03-30'; //first day visible
  $end = '2015-05-03'; //last day visible

  function kalendar_generate_reccuring_events($data, $start, $end) {
    $startDate    = $data['start'];
    $rrule        = str_replace('RRULE:', '', $data['rrule']);
    $rule         = new \Recurr\Rule($rrule, $startDate);
    $transformer  = new \Recurr\Transformer\ArrayTransformer();
    $constraint   = new \Recurr\Transformer\Constraint\BetweenConstraint(new \DateTime($start), new  \DateTime($end), true);
    $limit        = null;

    $result = $transformer->transform($rule, $limit, $constraint);

    $events = array();
    foreach($result as $row) {
      $ev_start = new DateTime($data['start']);
      $ev_end   = new DateTime($data['end']);
      $duration = $ev_start->diff($ev_end);

      $r_start = $row->getStart();

      $events[] = array(
        'title'   => $data['title'],
        'start'   => $r_start->format('Y-m-d H:i:s'),
        'end'     => $r_start->add($duration)->format('Y-m-d H:i:s'), 
      );
    }
    return $events;
  }

Also thanks a lot for this AWESOME PACKAGE! This is exactly what I was looking for.

BYHOUR returns one less event than expected if startDate has a time after the BYHOUR

I'm seeing this issue when I have an RRULE that occurs at 1pm every day and I set virtualLimit to 2. If the startDate is on a day before 1pm, 2 results are returned, as expected. However, if the startDate is after 1pm, only 1 result is returned.

This test case reproduces the issue:

$rule = new Rule(
    'FREQ=DAILY;BYHOUR=13',
    new \DateTime('2014-06-12 15:00:00')
);

$computed = $this->transformer->transform($rule, 2);
// fails because only 1 date is returned
$this->assertCount(2, $computed);

$this->assertEquals(new \DateTime('2014-06-13 13:00:00'), $computed[0]->getStart());
$this->assertEquals(new \DateTime('2014-06-14 13:00:00'), $computed[1]->getStart());

EXDATE and EXRULE implementation

According to the RFC 2445 there are EXDATE and EXRULE recurrence component properties which can be used in conjunction with RRULE to generate a recurrence set.

This will allow to create recurring events and then delete single instances from a series during generation.

If implementation of both is time-consuming I prefer to have at least EXDATE.
What are your thoughts on it?

endDate without COUNT

Why is this

        $timezone    = 'Europe/Warsaw';
        $startDate   = new \DateTime('2015-06-12 20:00:00', new \DateTimeZone($timezone));
        $endDate     = new \DateTime('2016-06-14 20:00:00', new \DateTimeZone($timezone)); // Optional
        $rule        = new \Recurr\Rule('FREQ=WEEKLY;BYDAY=MO,SA', $startDate, $endDate, $timezone);
        $transformer = new \Recurr\Transformer\ArrayTransformer();

        $computed = $transformer->transform($rule);

        foreach($computed as $c) {
            echo $c->getStart()->format('D jS M Y').'<br>';
        }

Producing results far and beyond the specified end date of 2016-06-14 20:00:00 ?

Sat 13th Jun 2015
Mon 15th Jun 2015
Sat 20th Jun 2015
Mon 22nd Jun 2015
Sat 27th Jun 2015
Mon 29th Jun 2015
Sat 4th Jul 2015
Mon 6th Jul 2015
Sat 11th Jul 2015

.....

Sat 14th May 2022
Mon 16th May 2022
Sat 21st May 2022
Mon 23rd May 2022
Sat 28th May 2022
Mon 30th May 2022
Sat 4th Jun 2022
Mon 6th Jun 2022
Sat 11th Jun 2022
Mon 13th Jun 2022

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.