default services conflit ?

This commit is contained in:
armansansd
2022-04-27 11:30:43 +02:00
parent 28190a5749
commit 8bb1064a3b
8132 changed files with 900138 additions and 426 deletions

View File

@@ -0,0 +1,3 @@
/tests export-ignore
/.travis.yml export-ignore
/phpunit.xml.dist export-ignore

3
old.vendor/simshaun/recurr/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/vendor/
/.idea/
/composer.lock

View File

@@ -0,0 +1,50 @@
Copyright (c) 2015 Shaun Simmons
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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.
----------------------------------------------
Recurr is heavily based on rrule.js:
Copyright 2010, Jakub Roztocil <jakub@roztocil.name> and Lars Schöning
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of The author nor the names of its contributors may
be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,156 @@
# Recurr [![Build Status](https://travis-ci.org/simshaun/recurr.png)](https://travis-ci.org/simshaun/recurr.png) [![Latest Stable Version](https://poser.pugx.org/simshaun/recurr/v/stable.svg)](https://packagist.org/packages/simshaun/recurr) [![Total Downloads](https://poser.pugx.org/simshaun/recurr/downloads.svg)](https://packagist.org/packages/simshaun/recurr) [![Latest Unstable Version](https://poser.pugx.org/simshaun/recurr/v/unstable.svg)](https://packagist.org/packages/simshaun/recurr) [![License](https://poser.pugx.org/simshaun/recurr/license.svg)](https://packagist.org/packages/simshaun/recurr)
Recurr is a PHP library for working with recurrence rules ([RRULE](https://tools.ietf.org/html/rfc5545)) 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](https://github.com/jkbr/rrule).
Installing Recurr
------------
The recommended way to install Recurr is through [Composer](http://getcomposer.org).
`composer require simshaun/recurr`
Using Recurr
-----------
### Creating RRULE rule objects ###
You can create a new Rule object by passing the ([RRULE](https://tools.ietf.org/html/rfc5545)) string or an array with the rule parts, the start date, end date (optional) and timezone.
```php
$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.
```php
$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 ###
```php
$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,
```php
$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](https://github.com/doctrine/collections/blob/master/lib/Doctrine/Common/Collections/ArrayCollection.php) 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.
```php
$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)*.
```php
$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:
```php
$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.

View File

@@ -0,0 +1,37 @@
{
"name": "simshaun/recurr",
"description": "PHP library for working with recurrence rules",
"keywords": ["rrule", "recurrence", "recurring", "events", "dates"],
"homepage": "https://github.com/simshaun/recurr",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Shaun Simmons",
"email": "shaun@shaun.pub",
"homepage": "https://shaun.pub"
}
],
"require": {
"php": ">=5.5.0",
"doctrine/collections": "~1.3"
},
"require-dev": {
"phpunit/phpunit": "~5.7"
},
"autoload": {
"psr-4": {
"Recurr\\": "src/Recurr/"
}
},
"autoload-dev": {
"psr-4": {
"Recurr\\Test\\": "tests/Recurr/Test"
}
},
"extra": {
"branch-alias": {
"dev-master": "0.x-dev"
}
}
}

View File

@@ -0,0 +1,48 @@
<?php
/*
* Copyright 2014 Shaun Simmons
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Recurr;
/**
* Class DateExclusion is a container for a single \DateTimeInterface.
*
* The purpose of this class is to hold a flag that specifies whether
* or not the \DateTimeInterface was created from a DATE only, or with a
* DATETIME.
*
* It also tracks whether or not the exclusion is explicitly set to UTC.
*
* @package Recurr
* @author Shaun Simmons <shaun@envysphere.com>
*/
class DateExclusion
{
/** @var \DateTimeInterface */
public $date;
/** @var bool Day of year */
public $hasTime;
/** @var bool */
public $isUtcExplicit;
/**
* Constructor
*
* @param \DateTimeInterface $date
* @param bool $hasTime
* @param bool $isUtcExplicit
*/
public function __construct(\DateTimeInterface $date, $hasTime = true, $isUtcExplicit = false)
{
$this->date = $date;
$this->hasTime = $hasTime;
$this->isUtcExplicit = $isUtcExplicit;
}
}

View File

@@ -0,0 +1,48 @@
<?php
/*
* Copyright 2015 Shaun Simmons
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Recurr;
/**
* Class DateInclusion is a container for a single \DateTimeInterface.
*
* The purpose of this class is to hold a flag that specifies whether
* or not the \DateTimeInterface was created from a DATE only, or with a
* DATETIME.
*
* It also tracks whether or not the inclusion is explicitly set to UTC.
*
* @package Recurr
* @author Shaun Simmons <shaun@envysphere.com>
*/
class DateInclusion
{
/** @var \DateTimeInterface */
public $date;
/** @var bool Day of year */
public $hasTime;
/** @var bool */
public $isUtcExplicit;
/**
* Constructor
*
* @param \DateTimeInterface $date
* @param bool $hasTime
* @param bool $isUtcExplicit
*/
public function __construct(\DateTimeInterface $date, $hasTime = true, $isUtcExplicit = false)
{
$this->date = $date;
$this->hasTime = $hasTime;
$this->isUtcExplicit = $isUtcExplicit;
}
}

View File

@@ -0,0 +1,73 @@
<?php
/*
* Copyright 2013 Shaun Simmons
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* Based on rrule.js
* Copyright 2010, Jakub Roztocil and Lars Schoning
* https://github.com/jkbr/rrule/blob/master/LICENCE
*/
namespace Recurr;
/**
* Class DateInfo is responsible for holding information based on a particular
* date that is applicable to a Rule.
*
* @package Recurr
* @author Shaun Simmons <shaun@envysphere.com>
*/
class DateInfo
{
/** @var \DateTime */
public $dt;
/**
* @var int Number of days in the month.
*/
public $monthLength;
/**
* @var int Number of days in the year (365 normally, 366 on leap years)
*/
public $yearLength;
/**
* @var int Number of days in the next year (365 normally, 366 on leap years)
*/
public $nextYearLength;
/**
* @var array Day of year of last day of each month.
*/
public $mRanges;
/** @var int Day of week */
public $dayOfWeek;
/** @var int Day of week of the year's first day */
public $dayOfWeekYearDay1;
/**
* @var array Month number for each day of the year.
*/
public $mMask;
/**
* @var array Month-daynumber for each day of the year.
*/
public $mDayMask;
/**
* @var array Month-daynumber for each day of the year (in reverse).
*/
public $mDayMaskNeg;
/**
* @var array Day of week (0-6) for each day of the year, 0 being Monday
*/
public $wDayMask;
}

View File

@@ -0,0 +1,571 @@
<?php
/*
* Copyright 2013 Shaun Simmons
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* Based on rrule.js
* Copyright 2010, Jakub Roztocil and Lars Schoning
* https://github.com/jkbr/rrule/blob/master/LICENCE
*
* Based on python-dateutil - Extensions to the standard Python datetime module.
* Copyright (c) 2003-2011 - Gustavo Niemeyer <gustavo@niemeyer.net>
* Copyright (c) 2012 - Tomi Pieviläinen <tomi.pievilainen@iki.fi>
*/
namespace Recurr;
/**
* Class DateUtil is responsible for providing utilities applicable to Rules.
*
* @package Recurr
* @author Shaun Simmons <shaun@envysphere.com>
*/
class DateUtil
{
public static $leapBug = null;
public static $monthEndDoY366 = array(
0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366
);
public static $monthEndDoY365 = array(
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
);
public static $wDayMask = array(
0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6,
0, 1, 2, 3, 4, 5, 6,
);
/**
* Get an object containing info for a particular date
*
* @param \DateTimeInterface $dt
*
* @return DateInfo
*/
public static function getDateInfo(\DateTimeInterface $dt)
{
$i = new DateInfo();
$i->dt = $dt;
$i->dayOfWeek = self::getDayOfWeek($dt);
$i->monthLength = $dt->format('t');
$i->yearLength = self::getYearLength($dt);
$i->mMask = self::getMonthMask($dt);
$i->mDayMask = self::getMonthDaysMask($dt);
$i->mDayMaskNeg = self::getMonthDaysMask($dt, true);
if ($i->yearLength == 365) {
$i->mRanges = self::$monthEndDoY365;
} else {
$i->mRanges = self::$monthEndDoY366;
}
$tmpDt = clone $dt;
$tmpDt = $tmpDt->setDate($dt->format('Y') + 1, 1, 1);
$i->nextYearLength = self::getYearLength($tmpDt);
$tmpDt = clone $dt;
$tmpDt = $tmpDt->setDate($dt->format('Y'), 1, 1);
$i->dayOfWeekYearDay1 = self::getDayOfWeek($tmpDt);
$i->wDayMask = array_slice(
self::$wDayMask,
$i->dayOfWeekYearDay1
);
return $i;
}
/**
* Get an array of DOY (Day of Year) for each day in a particular week.
*
* @param \DateTimeInterface $dt
* @param \DateTimeInterface $start
* @param null|Rule $rule
* @param null|DateInfo $dtInfo
*
* @return DaySet
*/
public static function getDaySetOfWeek(
\DateTimeInterface $dt,
\DateTimeInterface $start,
Rule $rule = null,
DateInfo $dtInfo = null
)
{
$start = clone $dt;
$start = $start->setDate($start->format('Y'), 1, 1);
$diff = $dt->diff($start);
$start = $diff->days;
$set = array();
for ($i = $start, $k = 0; $k < 7; $k++) {
$set[] = $i;
++$i;
if (null !== $dtInfo && null !== $rule && $dtInfo->wDayMask[$i] == $rule->getWeekStartAsNum()) {
break;
}
}
$obj = new DaySet($set, $start, $i);
return $obj;
}
/**
* @param Rule $rule
* @param \DateTimeInterface $dt
* @param DateInfo $dtInfo
* @param \DateTimeInterface $start
*
* @return DaySet
*/
public static function getDaySet(Rule $rule, \DateTimeInterface $dt, DateInfo $dtInfo, $start)
{
switch ($rule->getFreq()) {
case Frequency::SECONDLY:
return self::getDaySetOfDay($dt, $start, $rule, $dtInfo);
break;
case Frequency::MINUTELY:
return self::getDaySetOfDay($dt, $start, $rule, $dtInfo);
break;
case Frequency::HOURLY:
return self::getDaySetOfDay($dt, $start, $rule, $dtInfo);
break;
case Frequency::DAILY:
return self::getDaySetOfDay($dt, $start, $rule, $dtInfo);
break;
case Frequency::WEEKLY:
return self::getDaySetOfWeek($dt, $start, $rule, $dtInfo);
case Frequency::MONTHLY:
return self::getDaySetOfMonth($dt, $start, $rule, $dtInfo);
case Frequency::YEARLY:
return self::getDaySetOfYear($dt, $start, $rule, $dtInfo);
}
throw new \RuntimeException('Invalid freq.');
}
/**
* Get an array of DOY (Day of Year) for each day in a particular year.
*
* @param \DateTimeInterface $dt The datetime
*
* @return DaySet
*/
public static function getDaySetOfYear(\DateTimeInterface $dt)
{
$yearLen = self::getYearLength($dt);
$set = range(0, $yearLen - 1);
return new DaySet($set, 0, $yearLen);
}
/**
* Get an array of DOY (Day of Year) for each day in a particular month.
*
* @param \DateTimeInterface $dt The datetime
*
* @return DaySet
*/
public static function getDaySetOfMonth(\DateTimeInterface $dt)
{
$dateInfo = self::getDateInfo($dt);
$monthNum = $dt->format('n');
$start = $dateInfo->mRanges[$monthNum - 1];
$end = $dateInfo->mRanges[$monthNum];
$days = range(0, $dt->format('t') - 1);
$set = range($start, $end - 1);
$set = array_combine($days, $set);
$obj = new DaySet($set, $start, $end - 1);
return $obj;
}
/**
* Get an array of DOY (Day of Year) for each day in a particular month.
*
* @param \DateTimeInterface $dt The datetime
*
* @return DaySet
*/
public static function getDaySetOfDay(\DateTimeInterface $dt)
{
$dayOfYear = $dt->format('z');
if (self::isLeapYearDate($dt) && self::hasLeapYearBug() && $dt->format('nj') > 229) {
$dayOfYear -= 1;
}
$start = $dayOfYear;
$end = $dayOfYear;
$set = range($start, $end);
$obj = new DaySet($set, $start, $end + 1);
return $obj;
}
/**
* @param Rule $rule
* @param \DateTimeInterface $dt
*
* @return array
*/
public static function getTimeSetOfHour(Rule $rule, \DateTimeInterface $dt)
{
$set = array();
$hour = $dt->format('G');
$byMinute = $rule->getByMinute();
$bySecond = $rule->getBySecond();
if (empty($byMinute)) {
$byMinute = array($dt->format('i'));
}
if (empty($bySecond)) {
$bySecond = array($dt->format('s'));
}
foreach ($byMinute as $minute) {
foreach ($bySecond as $second) {
$set[] = new Time($hour, $minute, $second);
}
}
return $set;
}
/**
* @param Rule $rule
* @param \DateTimeInterface $dt
*
* @return array
*/
public static function getTimeSetOfMinute(Rule $rule, \DateTimeInterface $dt)
{
$set = array();
$hour = $dt->format('G');
$minute = $dt->format('i');
$bySecond = $rule->getBySecond();
if (empty($bySecond)) {
$bySecond = array($dt->format('s'));
}
foreach ($bySecond as $second) {
$set[] = new Time($hour, $minute, $second);
}
return $set;
}
/**
* @param \DateTimeInterface $dt
*
* @return array
*/
public static function getTimeSetOfSecond(\DateTimeInterface $dt)
{
return array(new Time($dt->format('G'), $dt->format('i'), $dt->format('s')));
}
/**
* @param Rule $rule
* @param \DateTimeInterface $dt
*
* @return array
*/
public static function getTimeSet(Rule $rule, \DateTimeInterface $dt)
{
$set = array();
if (null === $rule || $rule->getFreq() >= Frequency::HOURLY) {
return $set;
}
$byHour = $rule->getByHour();
$byMinute = $rule->getByMinute();
$bySecond = $rule->getBySecond();
if (empty($byHour)) {
$byHour = array($dt->format('G'));
}
if (empty($byMinute)) {
$byMinute = array($dt->format('i'));
}
if (empty($bySecond)) {
$bySecond = array($dt->format('s'));
}
foreach ($byHour as $hour) {
foreach ($byMinute as $minute) {
foreach ($bySecond as $second) {
$set[] = new Time($hour, $minute, $second);
}
}
}
return $set;
}
/**
* Get a reference array with the day number for each day of each month.
*
* @param \DateTimeInterface $dt The datetime
* @param bool $negative
*
* @return array
*/
public static function getMonthDaysMask(\DateTimeInterface $dt, $negative = false)
{
if ($negative) {
$m29 = range(-29, -1);
$m30 = range(-30, -1);
$m31 = range(-31, -1);
} else {
$m29 = range(1, 29);
$m30 = range(1, 30);
$m31 = range(1, 31);
}
$mask = array_merge(
$m31, // Jan (31)
$m29, // Feb (28)
$m31, // Mar (31)
$m30, // Apr (30)
$m31, // May (31)
$m30, // Jun (30)
$m31, // Jul (31)
$m31, // Aug (31)
$m30, // Sep (30)
$m31, // Oct (31)
$m30, // Nov (30)
$m31, // Dec (31)
array_slice(
$m31,
0,
7
)
);
if (self::isLeapYearDate($dt)) {
return $mask;
} else {
if ($negative) {
$mask = array_merge(array_slice($mask, 0, 31), array_slice($mask, 32));
} else {
$mask = array_merge(array_slice($mask, 0, 59), array_slice($mask, 60));
}
return $mask;
}
}
public static function getMonthMask(\DateTimeInterface $dt)
{
if (self::isLeapYearDate($dt)) {
return array_merge(
array_fill(0, 31, 1), // Jan (31)
array_fill(0, 29, 2), // Feb (29)
array_fill(0, 31, 3), // Mar (31)
array_fill(0, 30, 4), // Apr (30)
array_fill(0, 31, 5), // May (31)
array_fill(0, 30, 6), // Jun (30)
array_fill(0, 31, 7), // Jul (31)
array_fill(0, 31, 8), // Aug (31)
array_fill(0, 30, 9), // Sep (30)
array_fill(0, 31, 10), // Oct (31)
array_fill(0, 30, 11), // Nov (30)
array_fill(0, 31, 12), // Dec (31)
array_fill(0, 7, 1)
);
} else {
return array_merge(
array_fill(0, 31, 1), // Jan (31)
array_fill(0, 28, 2), // Feb (28)
array_fill(0, 31, 3), // Mar (31)
array_fill(0, 30, 4), // Apr (30)
array_fill(0, 31, 5), // May (31)
array_fill(0, 30, 6), // Jun (30)
array_fill(0, 31, 7), // Jul (31)
array_fill(0, 31, 8), // Aug (31)
array_fill(0, 30, 9), // Sep (30)
array_fill(0, 31, 10), // Oct (31)
array_fill(0, 30, 11), // Nov (30)
array_fill(0, 31, 12), // Dec (31)
array_fill(0, 7, 1)
);
}
}
public static function getDateTimeByDayOfYear($dayOfYear, $year, \DateTimeZone $timezone)
{
$dtTmp = new \DateTime('now', $timezone);
$dtTmp = $dtTmp->setDate($year, 1, 1);
$dtTmp = $dtTmp->modify("+$dayOfYear day");
return $dtTmp;
}
public static function hasLeapYearBug()
{
$leapBugTest = \DateTime::createFromFormat('Y-m-d', '2016-03-21');
return $leapBugTest->format('z') != '80';
}
/**
* closure/goog/math/math.js:modulo
* Copyright 2006 The Closure Library Authors.
*
* The % operator in PHP returns the remainder of a / b, but differs from
* some other languages in that the result will have the same sign as the
* dividend. For example, -1 % 8 == -1, whereas in some other languages
* (such as Python) the result would be 7. This function emulates the more
* correct modulo behavior, which is useful for certain applications such as
* calculating an offset index in a circular list.
*
* @param int $a The dividend.
* @param int $b The divisor.
*
* @return int $a % $b where the result is between 0 and $b
* (either 0 <= x < $b
* or $b < x <= 0, depending on the sign of $b).
*/
public static function pymod($a, $b)
{
$x = $a % $b;
// If $x and $b differ in sign, add $b to wrap the result to the correct sign.
return ($x * $b < 0) ? $x + $b : $x;
}
/**
* Alias method to determine if a date falls within a leap year.
*
* @param \DateTimeInterface $dt
*
* @return bool
*/
public static function isLeapYearDate(\DateTimeInterface $dt)
{
return $dt->format('L') ? true : false;
}
/**
* Alias method to determine if a year is a leap year.
*
* @param int $year
*
* @return bool
*/
public static function isLeapYear($year)
{
$isDivisBy4 = $year % 4 == 0 ? true : false;
$isDivisBy100 = $year % 100 == 0? true : false;
$isDivisBy400 = $year % 400 == 0 ? true : false;
// http://en.wikipedia.org/wiki/February_29
if ($isDivisBy100 && !$isDivisBy400) {
return false;
}
return $isDivisBy4;
}
/**
* Method to determine the day of the week from MO-SU.
*
* MO = Monday
* TU = Tuesday
* WE = Wednesday
* TH = Thursday
* FR = Friday
* SA = Saturday
* SU = Sunday
*
* @param \DateTimeInterface $dt
*
* @return string
*/
public static function getDayOfWeekAsText(\DateTimeInterface $dt)
{
$dayOfWeek = $dt->format('w') - 1;
if ($dayOfWeek < 0) {
$dayOfWeek = 6;
}
$map = array('MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU');
return $map[$dayOfWeek];
}
/**
* Alias method to determine the day of the week from 0-6.
*
* 0 = Monday
* 1 = Tuesday
* 2 = Wednesday
* 3 = Thursday
* 4 = Friday
* 5 = Saturday
* 6 = Sunday
*
* @param \DateTimeInterface $dt
*
* @return int
*/
public static function getDayOfWeek(\DateTimeInterface $dt)
{
$dayOfWeek = $dt->format('w') - 1;
if ($dayOfWeek < 0) {
$dayOfWeek = 6;
}
return $dayOfWeek;
}
/**
* Get the number of days in a year.
*
* @param \DateTimeInterface $dt
*
* @return int
*/
public static function getYearLength(\DateTimeInterface $dt)
{
return self::isLeapYearDate($dt) ? 366 : 365;
}
}

View File

@@ -0,0 +1,46 @@
<?php
/*
* Copyright 2013 Shaun Simmons
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* Based on rrule.js
* Copyright 2010, Jakub Roztocil and Lars Schoning
* https://github.com/jkbr/rrule/blob/master/LICENCE
*/
namespace Recurr;
/**
* Class DaySet is a container for a set and its meta.
*
* @package Recurr
* @author Shaun Simmons <shaun@envysphere.com>
*/
class DaySet
{
/** @var array */
public $set;
/** @var int Day of year */
public $start;
/** @var int Day of year */
public $end;
/**
* Constructor
*
* @param array $set Set of days
* @param int $start Day of year of start day
* @param int $end Day of year of end day
*/
public function __construct($set, $start, $end)
{
$this->set = $set;
$this->start = $start;
$this->end = $end;
}
}

View File

@@ -0,0 +1,17 @@
<?php
/*
* Copyright 2013 Shaun Simmons
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Recurr;
/**
* The base Recurr exception class
*/
class Exception extends \Exception
{
}

View File

@@ -0,0 +1,20 @@
<?php
/*
* Copyright 2013 Shaun Simmons
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Recurr\Exception;
use Recurr\Exception;
/**
* @package Recurr\Exception
* @author Shaun Simmons <shaun@envysphere.com>
*/
class InvalidArgument extends Exception
{
}

View File

@@ -0,0 +1,20 @@
<?php
/*
* Copyright 2013 Shaun Simmons
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Recurr\Exception;
use Recurr\Exception;
/**
* @package Recurr\Exception
* @author Shaun Simmons <shaun@envysphere.com>
*/
class InvalidRRule extends Exception
{
}

View File

@@ -0,0 +1,20 @@
<?php
/*
* Copyright 2013 Shaun Simmons
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Recurr\Exception;
use Recurr\Exception;
/**
* @package Recurr\Exception
* @author Shaun Simmons <shaun@envysphere.com>
*/
class InvalidWeekday extends Exception
{
}

View File

@@ -0,0 +1,25 @@
<?php
/*
* Copyright 2014 Shaun Simmons
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* Based on:
* rrule.js - Library for working with recurrence rules for calendar dates.
* Copyright 2010, Jakub Roztocil and Lars Schoning
* https://github.com/jkbr/rrule/blob/master/LICENCE
*/
namespace Recurr;
class Frequency {
const YEARLY = 0;
const MONTHLY = 1;
const WEEKLY = 2;
const DAILY = 3;
const HOURLY = 4;
const MINUTELY = 5;
const SECONDLY = 6;
}

View File

@@ -0,0 +1,90 @@
<?php
/*
* Copyright 2014 Shaun Simmons
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Recurr;
/**
* Class Recurrence is responsible for storing the start and end \DateTime of
* a specific recurrence in a RRULE.
*
* @package Recurr
* @author Shaun Simmons <shaun@envysphere.com>
*/
class Recurrence
{
/** @var \DateTimeInterface */
protected $start;
/** @var \DateTimeInterface */
protected $end;
/** @var int */
protected $index;
public function __construct(\DateTimeInterface $start = null, \DateTimeInterface $end = null, $index = 0)
{
if ($start instanceof \DateTimeInterface) {
$this->setStart($start);
}
if ($end instanceof \DateTimeInterface) {
$this->setEnd($end);
}
$this->index = $index;
}
/**
* @return \DateTimeInterface
*/
public function getStart()
{
return $this->start;
}
/**
* @param \DateTime $start
*/
public function setStart($start)
{
$this->start = $start;
}
/**
* @return \DateTime
*/
public function getEnd()
{
return $this->end;
}
/**
* @param \DateTime $end
*/
public function setEnd($end)
{
$this->end = $end;
}
/**
* @return int
*/
public function getIndex()
{
return $this->index;
}
/**
* @param int $index
*/
public function setIndex($index)
{
$this->index = $index;
}
}

View File

@@ -0,0 +1,153 @@
<?php
/*
* Copyright 2014 Shaun Simmons
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Recurr;
use \Doctrine\Common\Collections\ArrayCollection as BaseCollection;
/**
* @package Recurr
* @author Shaun Simmons <shaun@envysphere.com>
*/
class RecurrenceCollection extends BaseCollection
{
/**
* @param \DateTimeInterface $after
* @param \DateTimeInterface $before
* @param bool $inc Include $after or $before if they happen to be a recurrence.
*
* @return RecurrenceCollection
*/
public function startsBetween(\DateTimeInterface $after, \DateTimeInterface $before, $inc = false)
{
return $this->filter(
function ($recurrence) use ($after, $before, $inc) {
/** @var $recurrence Recurrence */
$start = $recurrence->getStart();
if ($inc) {
return $start >= $after && $start <= $before;
}
return $start > $after && $start < $before;
}
);
}
/**
* @param \DateTimeInterface $before
* @param bool $inc Include $before if it is a recurrence.
*
* @return RecurrenceCollection
*/
public function startsBefore(\DateTimeInterface $before, $inc = false)
{
return $this->filter(
function ($recurrence) use ($before, $inc) {
/** @var $recurrence Recurrence */
$start = $recurrence->getStart();
if ($inc) {
return $start <= $before;
}
return $start < $before;
}
);
}
/**
* @param \DateTimeInterface $after
* @param bool $inc Include $after if it a recurrence.
*
* @return RecurrenceCollection
*/
public function startsAfter(\DateTimeInterface $after, $inc = false)
{
return $this->filter(
function ($recurrence) use ($after, $inc) {
/** @var $recurrence Recurrence */
$start = $recurrence->getStart();
if ($inc) {
return $start >= $after;
}
return $start > $after;
}
);
}
/**
* @param \DateTimeInterface $after
* @param \DateTimeInterface $before
* @param bool $inc Include $after or $before if they happen to be a recurrence.
*
* @return RecurrenceCollection
*/
public function endsBetween(\DateTimeInterface $after, \DateTimeInterface $before, $inc = false)
{
return $this->filter(
function ($recurrence) use ($after, $before, $inc) {
/** @var $recurrence Recurrence */
$end = $recurrence->getEnd();
if ($inc) {
return $end >= $after && $end <= $before;
}
return $end > $after && $end < $before;
}
);
}
/**
* @param \DateTimeInterface $before
* @param bool $inc Include $before if it is a recurrence.
*
* @return RecurrenceCollection
*/
public function endsBefore(\DateTimeInterface $before, $inc = false)
{
return $this->filter(
function ($recurrence) use ($before, $inc) {
/** @var $recurrence Recurrence */
$end = $recurrence->getEnd();
if ($inc) {
return $end <= $before;
}
return $end < $before;
}
);
}
/**
* @param \DateTimeInterface $after
* @param bool $inc Include $after if it a recurrence.
*
* @return RecurrenceCollection
*/
public function endsAfter(\DateTimeInterface $after, $inc = false)
{
return $this->filter(
function ($recurrence) use ($after, $inc) {
/** @var $recurrence Recurrence */
$end = $recurrence->getEnd();
if ($inc) {
return $end >= $after;
}
return $end > $after;
}
);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,39 @@
<?php
/*
* Copyright 2013 Shaun Simmons
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* Based on rrule.js
* Copyright 2010, Jakub Roztocil and Lars Schoning
* https://github.com/jkbr/rrule/blob/master/LICENCE
*/
namespace Recurr;
/**
* Class Time is a storage container for a time of day.
*
* @package Recurr
* @author Shaun Simmons <shaun@envysphere.com>
*/
class Time
{
/** @var int */
public $hour;
/** @var int */
public $minute;
/** @var int */
public $second;
public function __construct($hour, $minute, $second)
{
$this->hour = $hour;
$this->minute = $minute;
$this->second = $second;
}
}

View File

@@ -0,0 +1,736 @@
<?php
/*
* Copyright 2013 Shaun Simmons
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* Based on:
* rrule.js - Library for working with recurrence rules for calendar dates.
* Copyright 2010, Jakub Roztocil and Lars Schoning
* https://github.com/jkbr/rrule/blob/master/LICENCE
*/
namespace Recurr\Transformer;
use Recurr\DateExclusion;
use Recurr\DateInclusion;
use Recurr\Exception\InvalidWeekday;
use Recurr\Frequency;
use Recurr\Recurrence;
use Recurr\RecurrenceCollection;
use Recurr\Rule;
use Recurr\Time;
use Recurr\Weekday;
use Recurr\DateUtil;
/**
* This class is responsible for transforming a Rule in to an array
* of \DateTimeInterface objects.
*
* If a recurrence rule is infinitely recurring, a virtual limit is imposed.
*
* @package Recurr
* @author Shaun Simmons <shaun@envysphere.com>
*/
class ArrayTransformer
{
/** @var ArrayTransformerConfig */
protected $config;
/**
* Some versions of PHP are affected by a bug where
* \DateTimeInterface::createFromFormat('z Y', ...) does not account for leap years.
*
* @var bool
*/
protected $leapBug = false;
/**
* Construct a new ArrayTransformer
*
* @param ArrayTransformerConfig $config
*/
public function __construct(ArrayTransformerConfig $config = null)
{
if (!$config instanceof ArrayTransformerConfig) {
$config = new ArrayTransformerConfig();
}
$this->config = $config;
$this->leapBug = DateUtil::hasLeapYearBug();
}
/**
* @param ArrayTransformerConfig $config
*/
public function setConfig($config)
{
$this->config = $config;
}
/**
* Transform a Rule in to an array of \DateTimeInterface objects
*
* @param Rule $rule the Rule object
* @param ConstraintInterface|null $constraint Potential recurrences must pass the constraint, else
* they will not be included in the returned collection.
* @param bool $countConstraintFailures Whether recurrences that fail the constraint's test
* should count towards a rule's COUNT limit.
*
* @return RecurrenceCollection|Recurrence[]
* @throws InvalidWeekday
*/
public function transform(Rule $rule, ConstraintInterface $constraint = null, $countConstraintFailures = true)
{
$start = $rule->getStartDate();
$end = $rule->getEndDate();
$until = $rule->getUntil();
if (null === $start) {
$start = new \DateTime(
'now', $until instanceof \DateTimeInterface ? $until->getTimezone() : null
);
}
if (null === $end) {
$end = $start;
}
$durationInterval = $start->diff($end);
$startDay = $start->format('j');
$startMonthLength = $start->format('t');
$fixLastDayOfMonth = false;
$dt = clone $start;
$maxCount = $rule->getCount();
$vLimit = $this->config->getVirtualLimit();
$freq = $rule->getFreq();
$weekStart = $rule->getWeekStartAsNum();
$bySecond = $rule->getBySecond();
$byMinute = $rule->getByMinute();
$byHour = $rule->getByHour();
$byMonth = $rule->getByMonth();
$byWeekNum = $rule->getByWeekNumber();
$byYearDay = $rule->getByYearDay();
$byMonthDay = $rule->getByMonthDay();
$byMonthDayNeg = array();
$byWeekDay = $rule->getByDayTransformedToWeekdays();
$byWeekDayRel = array();
$bySetPos = $rule->getBySetPosition();
$implicitByMonthDay = false;
if (!(!empty($byWeekNum) || !empty($byYearDay) || !empty($byMonthDay) || !empty($byWeekDay))) {
switch ($freq) {
case Frequency::YEARLY:
if (empty($byMonth)) {
$byMonth = array($start->format('n'));
}
if ($startDay > 28) {
$fixLastDayOfMonth = true;
}
$implicitByMonthDay = true;
$byMonthDay = array($startDay);
break;
case Frequency::MONTHLY:
if ($startDay > 28) {
$fixLastDayOfMonth = true;
}
$implicitByMonthDay = true;
$byMonthDay = array($startDay);
break;
case Frequency::WEEKLY:
$byWeekDay = array(
new Weekday(
DateUtil::getDayOfWeek($start), null
)
);
break;
}
}
if (!$this->config->isLastDayOfMonthFixEnabled()) {
$fixLastDayOfMonth = false;
}
if (is_array($byMonthDay) && count($byMonthDay)) {
foreach ($byMonthDay as $idx => $day) {
if ($day < 0) {
unset($byMonthDay[$idx]);
$byMonthDayNeg[] = $day;
}
}
}
if (!empty($byWeekDay)) {
foreach ($byWeekDay as $idx => $day) {
/** @var $day Weekday */
if (!empty($day->num)) {
$byWeekDayRel[] = $day;
unset($byWeekDay[$idx]);
} else {
$byWeekDay[$idx] = $day->weekday;
}
}
}
if (empty($byYearDay)) {
$byYearDay = null;
}
if (empty($byMonthDay)) {
$byMonthDay = null;
}
if (empty($byMonthDayNeg)) {
$byMonthDayNeg = null;
}
if (empty($byWeekDay)) {
$byWeekDay = null;
}
if (!count($byWeekDayRel)) {
$byWeekDayRel = null;
}
$year = $dt->format('Y');
$month = $dt->format('n');
$hour = $dt->format('G');
$minute = $dt->format('i');
$second = $dt->format('s');
$dates = array();
$total = 1;
$count = $maxCount;
$continue = true;
$iterations = 0;
while ($continue) {
$dtInfo = DateUtil::getDateInfo($dt);
$tmp = DateUtil::getDaySet($rule, $dt, $dtInfo, $start);
$daySet = $tmp->set;
$daySetStart = $tmp->start;
$daySetEnd = $tmp->end;
$wNoMask = array();
$wDayMaskRel = array();
$timeSet = DateUtil::getTimeSet($rule, $dt);
if ($freq >= Frequency::HOURLY) {
if (
($freq >= Frequency::HOURLY && !empty($byHour) && !in_array($hour, $byHour))
|| ($freq >= Frequency::MINUTELY && !empty($byMinute) && !in_array($minute, $byMinute))
|| ($freq >= Frequency::SECONDLY && !empty($bySecond) && !in_array($second, $bySecond))
) {
$timeSet = array();
} else {
switch ($freq) {
case Frequency::HOURLY:
$timeSet = DateUtil::getTimeSetOfHour($rule, $dt);
break;
case Frequency::MINUTELY:
$timeSet = DateUtil::getTimeSetOfMinute($rule, $dt);
break;
case Frequency::SECONDLY:
$timeSet = DateUtil::getTimeSetOfSecond($dt);
break;
}
}
}
// Handle byWeekNum
if (!empty($byWeekNum)) {
$no1WeekStart = $firstWeekStart = DateUtil::pymod(7 - $dtInfo->dayOfWeekYearDay1 + $weekStart, 7);
if ($no1WeekStart >= 4) {
$no1WeekStart = 0;
$wYearLength = $dtInfo->yearLength + DateUtil::pymod(
$dtInfo->dayOfWeekYearDay1 - $weekStart,
7
);
} else {
$wYearLength = $dtInfo->yearLength - $no1WeekStart;
}
$div = floor($wYearLength / 7);
$mod = DateUtil::pymod($wYearLength, 7);
$numWeeks = floor($div + ($mod / 4));
foreach ($byWeekNum as $weekNum) {
if ($weekNum < 0) {
$weekNum += $numWeeks + 1;
}
if (!(0 < $weekNum && $weekNum <= $numWeeks)) {
continue;
}
if ($weekNum > 1) {
$offset = $no1WeekStart + ($weekNum - 1) * 7;
if ($no1WeekStart != $firstWeekStart) {
$offset -= 7 - $firstWeekStart;
}
} else {
$offset = $no1WeekStart;
}
for ($i = 0; $i < 7; $i++) {
$wNoMask[] = $offset;
$offset++;
if ($dtInfo->wDayMask[$offset] == $weekStart) {
break;
}
}
}
// Check week number 1 of next year as well
if (in_array(1, $byWeekNum)) {
$offset = $no1WeekStart + $numWeeks * 7;
if ($no1WeekStart != $firstWeekStart) {
$offset -= 7 - $firstWeekStart;
}
// If week starts in next year, we don't care about it.
if ($offset < $dtInfo->yearLength) {
for ($k = 0; $k < 7; $k++) {
$wNoMask[] = $offset;
$offset += 1;
if ($dtInfo->wDayMask[$offset] == $weekStart) {
break;
}
}
}
}
if ($no1WeekStart) {
// Check last week number of last year as well.
// If $no1WeekStart is 0, either the year started on week start,
// or week number 1 got days from last year, so there are no
// days from last year's last week number in this year.
if (!in_array(-1, $byWeekNum)) {
$dtTmp = new \DateTime();
$dtTmp = $dtTmp->setDate($year - 1, 1, 1);
$lastYearWeekDay = DateUtil::getDayOfWeek($dtTmp);
$lastYearNo1WeekStart = DateUtil::pymod(7 - $lastYearWeekDay + $weekStart, 7);
$lastYearLength = DateUtil::getYearLength($dtTmp);
if ($lastYearNo1WeekStart >= 4) {
$lastYearNo1WeekStart = 0;
$lastYearNumWeeks = floor(
52 + DateUtil::pymod(
$lastYearLength + DateUtil::pymod(
$lastYearWeekDay - $weekStart,
7
),
7
) / 4
);
} else {
$lastYearNumWeeks = floor(
52 + DateUtil::pymod(
$dtInfo->yearLength - $no1WeekStart,
7
) / 4
);
}
} else {
$lastYearNumWeeks = -1;
}
if (in_array($lastYearNumWeeks, $byWeekNum)) {
for ($i = 0; $i < $no1WeekStart; $i++) {
$wNoMask[] = $i;
}
}
}
}
// Handle relative weekdays (e.g. 3rd Friday of month)
if (!empty($byWeekDayRel)) {
$ranges = array();
if (Frequency::YEARLY == $freq) {
if (!empty($byMonth)) {
foreach ($byMonth as $mo) {
$ranges[] = array_slice($dtInfo->mRanges, $mo - 1, 2);
}
} else {
$ranges[] = array(0, $dtInfo->yearLength);
}
} elseif (Frequency::MONTHLY == $freq) {
$ranges[] = array_slice($dtInfo->mRanges, $month - 1, 2);
}
if (!empty($ranges)) {
foreach ($ranges as $range) {
$rangeStart = $range[0];
$rangeEnd = $range[1];
--$rangeEnd;
reset($byWeekDayRel);
foreach ($byWeekDayRel as $weekday) {
/** @var Weekday $weekday */
if ($weekday->num < 0) {
$i = $rangeEnd + ($weekday->num + 1) * 7;
$i -= DateUtil::pymod(
$dtInfo->wDayMask[$i] - $weekday->weekday,
7
);
} else {
$i = $rangeStart + ($weekday->num - 1) * 7;
$i += DateUtil::pymod(
7 - $dtInfo->wDayMask[$i] + $weekday->weekday,
7
);
}
if ($rangeStart <= $i && $i <= $rangeEnd) {
$wDayMaskRel[] = $i;
}
}
}
}
}
$numMatched = 0;
foreach ($daySet as $i => $dayOfYear) {
$dayOfMonth = $dtInfo->mDayMask[$dayOfYear];
$ifByMonth = $byMonth !== null && !in_array($dtInfo->mMask[$dayOfYear], $byMonth);
$ifByWeekNum = $byWeekNum !== null && !in_array($i, $wNoMask);
$ifByYearDay = $byYearDay !== null && (
(
$i < $dtInfo->yearLength &&
!in_array($i + 1, $byYearDay) &&
!in_array(-$dtInfo->yearLength + $i, $byYearDay)
) ||
(
$i >= $dtInfo->yearLength &&
!in_array($i + 1 - $dtInfo->yearLength, $byYearDay) &&
!in_array(-$dtInfo->nextYearLength + $i - $dtInfo->yearLength, $byYearDay)
)
);
$ifByMonthDay = $byMonthDay !== null && !in_array($dtInfo->mDayMask[$dayOfYear], $byMonthDay);
// Handle "last day of next month" problem.
if ($fixLastDayOfMonth
&& $ifByMonthDay
&& $implicitByMonthDay
&& $startMonthLength > $dtInfo->monthLength
&& $dayOfMonth == $dtInfo->monthLength
&& $dayOfMonth < $startMonthLength
&& !$numMatched
) {
$ifByMonthDay = false;
}
$ifByMonthDayNeg = $byMonthDayNeg !== null
&& !in_array($dtInfo->mDayMaskNeg[$dayOfYear], $byMonthDayNeg);
$ifByDay = $byWeekDay !== null && count($byWeekDay)
&& !in_array($dtInfo->wDayMask[$dayOfYear], $byWeekDay);
$ifWDayMaskRel = $byWeekDayRel !== null && !in_array($dayOfYear, $wDayMaskRel);
if ($byMonthDay !== null && $byMonthDayNeg !== null) {
if ($ifByMonthDay && $ifByMonthDayNeg) {
unset($daySet[$i]);
}
} elseif ($ifByMonth || $ifByWeekNum || $ifByYearDay || $ifByMonthDay || $ifByMonthDayNeg || $ifByDay || $ifWDayMaskRel) {
unset($daySet[$i]);
} else {
++$numMatched;
}
}
if (!empty($bySetPos) && !empty($daySet)) {
$datesAdj = array();
$tmpDaySet = array_combine($daySet, $daySet);
foreach ($bySetPos as $setPos) {
if ($setPos < 0) {
$dayPos = floor($setPos / count($timeSet));
$timePos = DateUtil::pymod($setPos, count($timeSet));
} else {
$dayPos = floor(($setPos - 1) / count($timeSet));
$timePos = DateUtil::pymod(($setPos - 1), count($timeSet));
}
$tmp = array();
for ($k = $daySetStart; $k <= $daySetEnd; $k++) {
if (!array_key_exists($k, $tmpDaySet)) {
continue;
}
$tmp[] = $tmpDaySet[$k];
}
if ($dayPos < 0) {
$nextInSet = array_slice($tmp, $dayPos, 1);
if (count($nextInSet) === 0) {
continue;
}
$nextInSet = $nextInSet[0];
} else {
$nextInSet = isset($tmp[$dayPos]) ? $tmp[$dayPos] : null;
}
if (null !== $nextInSet) {
/** @var Time $time */
$time = $timeSet[$timePos];
$dtTmp = DateUtil::getDateTimeByDayOfYear($nextInSet, $dt->format('Y'), $start->getTimezone());
$dtTmp = $dtTmp->setTime(
$time->hour,
$time->minute,
$time->second
);
$datesAdj[] = $dtTmp;
}
}
foreach ($datesAdj as $dtTmp) {
if (null !== $until && $dtTmp > $until) {
$continue = false;
break;
}
if ($dtTmp < $start) {
continue;
}
if ($constraint instanceof ConstraintInterface && !$constraint->test($dtTmp)) {
if (!$countConstraintFailures) {
if ($constraint->stopsTransformer()) {
$continue = false;
break;
} else {
continue;
}
}
} else {
$dates[$total] = $dtTmp;
}
if (null !== $count) {
--$count;
if ($count <= 0) {
$continue = false;
break;
}
}
++$total;
if ($total > $vLimit) {
$continue = false;
break;
}
}
} else {
foreach ($daySet as $dayOfYear) {
$dtTmp = DateUtil::getDateTimeByDayOfYear($dayOfYear, $dt->format('Y'), $start->getTimezone());
foreach ($timeSet as $time) {
/** @var Time $time */
$dtTmp = $dtTmp->setTime(
$time->hour,
$time->minute,
$time->second
);
if (null !== $until && $dtTmp > $until) {
$continue = false;
break;
}
if ($dtTmp < $start) {
continue;
}
if ($constraint instanceof ConstraintInterface && !$constraint->test($dtTmp)) {
if (!$countConstraintFailures) {
if ($constraint->stopsTransformer()) {
$continue = false;
break;
} else {
continue;
}
}
} else {
$dates[$total] = clone $dtTmp;
}
if (null !== $count) {
--$count;
if ($count <= 0) {
$continue = false;
break;
}
}
++$total;
if ($total > $vLimit) {
$continue = false;
break;
}
}
if (!$continue) {
break;
}
}
if ($total > $vLimit) {
$continue = false;
break;
}
}
switch ($freq) {
case Frequency::YEARLY:
$year += $rule->getInterval();
$month = $dt->format('n');
$dt = $dt->setDate($year, $month, 1);
// Stop an infinite loop w/ a sane limit
++$iterations;
if ($iterations > 300 && !count($dates)) {
break 2;
}
break;
case Frequency::MONTHLY:
$month += $rule->getInterval();
if ($month > 12) {
$delta = floor($month / 12);
$mod = DateUtil::pymod($month, 12);
$month = $mod;
$year += $delta;
if ($month == 0) {
$month = 12;
--$year;
}
}
$dt = $dt->setDate($year, $month, 1);
break;
case Frequency::WEEKLY:
if ($weekStart > $dtInfo->dayOfWeek) {
$delta = ($dtInfo->dayOfWeek + 1 + (6 - $weekStart)) * -1 + $rule->getInterval() * 7;
} else {
$delta = ($dtInfo->dayOfWeek - $weekStart) * -1 + $rule->getInterval() * 7;
}
$dt = $dt->modify("+$delta day");
$year = $dt->format('Y');
$month = $dt->format('n');
break;
case Frequency::DAILY:
$dt = $dt->modify('+'.$rule->getInterval().' day');
$year = $dt->format('Y');
$month = $dt->format('n');
break;
case Frequency::HOURLY:
$dt = $dt->modify('+'.$rule->getInterval().' hours');
$year = $dt->format('Y');
$month = $dt->format('n');
$hour = $dt->format('G');
break;
case Frequency::MINUTELY:
$dt = $dt->modify('+'.$rule->getInterval().' minutes');
$year = $dt->format('Y');
$month = $dt->format('n');
$hour = $dt->format('G');
$minute = $dt->format('i');
break;
case Frequency::SECONDLY:
$dt = $dt->modify('+'.$rule->getInterval().' seconds');
$year = $dt->format('Y');
$month = $dt->format('n');
$hour = $dt->format('G');
$minute = $dt->format('i');
$second = $dt->format('s');
break;
}
}
/** @var Recurrence[] $recurrences */
$recurrences = array();
foreach ($dates as $key => $start) {
/** @var \DateTimeInterface $end */
$end = clone $start;
$recurrences[] = new Recurrence($start, $end->add($durationInterval), $key);
}
$recurrences = $this->handleInclusions($rule->getRDates(), $recurrences);
$recurrences = $this->handleExclusions($rule->getExDates(), $recurrences);
return new RecurrenceCollection($recurrences);
}
/**
* @param DateExclusion[] $exclusions
* @param Recurrence[] $recurrences
*
* @return Recurrence[]
*/
protected function handleExclusions(array $exclusions, array $recurrences)
{
foreach ($exclusions as $exclusion) {
$exclusionDate = $exclusion->date->format('Ymd');
$exclusionTime = $exclusion->date->format('Ymd\THis');
$exclusionTimezone = $exclusion->date->getTimezone();
foreach ($recurrences as $key => $recurrence) {
$recurrenceDate = $recurrence->getStart();
if ($recurrenceDate->getTimezone()->getName() !== $exclusionTimezone->getName()) {
$recurrenceDate = clone $recurrenceDate;
$recurrenceDate = $recurrenceDate->setTimezone($exclusionTimezone);
}
if (!$exclusion->hasTime && $recurrenceDate->format('Ymd') == $exclusionDate) {
unset($recurrences[$key]);
continue;
}
if ($exclusion->hasTime && $recurrenceDate->format('Ymd\THis') == $exclusionTime) {
unset($recurrences[$key]);
}
}
}
return array_values($recurrences);
}
/**
* @param DateInclusion[] $inclusions
* @param Recurrence[] $recurrences
*
* @return Recurrence[]
*/
protected function handleInclusions(array $inclusions, array $recurrences)
{
foreach ($inclusions as $inclusion) {
$recurrence = new Recurrence(clone $inclusion->date, clone $inclusion->date);
$recurrences[] = $recurrence;
}
return array_values($recurrences);
}
}

View File

@@ -0,0 +1,65 @@
<?php
/*
* Copyright 2014 Shaun Simmons
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Recurr\Transformer;
class ArrayTransformerConfig
{
/** @var int */
protected $virtualLimit = 732;
protected $lastDayOfMonthFix = false;
/**
* Set the virtual limit imposed upon infinitely recurring events.
*
* @param int $virtualLimit The limit
*
* @return $this
*/
public function setVirtualLimit($virtualLimit)
{
$this->virtualLimit = (int) $virtualLimit;
return $this;
}
/**
* Get the virtual limit imposed upon infinitely recurring events.
*
* @return int
*/
public function getVirtualLimit()
{
return $this->virtualLimit;
}
/**
* 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;
}
public function disableLastDayOfMonthFix()
{
$this->lastDayOfMonthFix = false;
}
/**
* @return boolean
*/
public function isLastDayOfMonthFixEnabled()
{
return $this->lastDayOfMonthFix;
}
}

View File

@@ -0,0 +1,21 @@
<?php
/*
* Copyright 2014 Shaun Simmons
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Recurr\Transformer;
abstract class Constraint implements ConstraintInterface
{
protected $stopsTransformer = true;
public function stopsTransformer()
{
return $this->stopsTransformer;
}
}

View File

@@ -0,0 +1,64 @@
<?php
/*
* Copyright 2014 Shaun Simmons
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Recurr\Transformer\Constraint;
use Recurr\Transformer\Constraint;
class AfterConstraint extends Constraint
{
protected $stopsTransformer = false;
/** @var \DateTimeInterface */
protected $after;
/** @var bool */
protected $inc;
/**
* @param \DateTimeInterface $after
* @param bool $inc Include date if it equals $after.
*/
public function __construct(\DateTimeInterface $after, $inc = false)
{
$this->after = $after;
$this->inc = $inc;
}
/**
* Passes if $date is after $after
*
* {@inheritdoc}
*/
public function test(\DateTimeInterface $date)
{
if ($this->inc) {
return $date >= $this->after;
}
return $date > $this->after;
}
/**
* @return \DateTimeInterface
*/
public function getAfter()
{
return $this->after;
}
/**
* @return bool
*/
public function isInc()
{
return $this->inc;
}
}

View File

@@ -0,0 +1,64 @@
<?php
/*
* Copyright 2014 Shaun Simmons
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Recurr\Transformer\Constraint;
use Recurr\Transformer\Constraint;
class BeforeConstraint extends Constraint
{
protected $stopsTransformer = true;
/** @var \DateTimeInterface */
protected $before;
/** @var bool */
protected $inc;
/**
* @param \DateTimeInterface $before
* @param bool $inc Include date if it equals $before.
*/
public function __construct(\DateTimeInterface $before, $inc = false)
{
$this->before = $before;
$this->inc = $inc;
}
/**
* Passes if $date is before $before
*
* {@inheritdoc}
*/
public function test(\DateTimeInterface $date)
{
if ($this->inc) {
return $date <= $this->before;
}
return $date < $this->before;
}
/**
* @return \DateTimeInterface
*/
public function getBefore()
{
return $this->before;
}
/**
* @return bool
*/
public function isInc()
{
return $this->inc;
}
}

View File

@@ -0,0 +1,81 @@
<?php
/*
* Copyright 2014 Shaun Simmons
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Recurr\Transformer\Constraint;
use Recurr\Transformer\Constraint;
class BetweenConstraint extends Constraint
{
protected $stopsTransformer = false;
/** @var \DateTimeInterface */
protected $before;
/** @var \DateTimeInterface */
protected $after;
/** @var bool */
protected $inc;
/**
* @param \DateTimeInterface $after
* @param \DateTimeInterface $before
* @param bool $inc Include date if it equals $after or $before.
*/
public function __construct(\DateTimeInterface $after, \DateTimeInterface $before, $inc = false)
{
$this->after = $after;
$this->before = $before;
$this->inc = $inc;
}
/**
* Passes if $date is between $after and $before
*
* {@inheritdoc}
*/
public function test(\DateTimeInterface $date)
{
if ($date > $this->before) {
$this->stopsTransformer = true;
}
if ($this->inc) {
return $date >= $this->after && $date <= $this->before;
}
return $date > $this->after && $date < $this->before;
}
/**
* @return \DateTimeInterface
*/
public function getBefore()
{
return $this->before;
}
/**
* @return \DateTimeInterface
*/
public function getAfter()
{
return $this->after;
}
/**
* @return bool
*/
public function isInc()
{
return $this->inc;
}
}

View File

@@ -0,0 +1,25 @@
<?php
/*
* Copyright 2014 Shaun Simmons
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Recurr\Transformer;
interface ConstraintInterface
{
/**
* @return bool
*/
public function stopsTransformer();
/**
* @param \DateTimeInterface $date
*
* @return bool
*/
public function test(\DateTimeInterface $date);
}

View File

@@ -0,0 +1,502 @@
<?php
namespace Recurr\Transformer;
use Recurr\Rule;
class TextTransformer
{
protected $fragments = array();
protected $translator;
public function __construct(TranslatorInterface $translator = null)
{
$this->translator = $translator ?: new Translator('en');
}
public function transform(Rule $rule)
{
$this->fragments = array();
switch ($rule->getFreq()) {
case 0:
$this->addYearly($rule);
break;
case 1:
$this->addMonthly($rule);
break;
case 2:
$this->addWeekly($rule);
break;
case 3:
$this->addDaily($rule);
break;
case 4:
$this->addHourly($rule);
break;
case 5:
case 6:
return $this->translator->trans('Unable to fully convert this rrule to text.');
}
$until = $rule->getUntil();
$count = $rule->getCount();
if ($until instanceof \DateTimeInterface) {
$dateFormatted = $this->translator->trans('day_date', array('date' => $until->format('U')));
$this->addFragment($this->translator->trans('until %date%', array('date' => $dateFormatted)));
} else if (!empty($count)) {
if ($this->isPlural($count)) {
$this->addFragment($this->translator->trans('for %count% times', array('count' => $count)));
} else {
$this->addFragment($this->translator->trans('for one time'));
}
}
if (!$this->isFullyConvertible($rule)) {
$this->addFragment($this->translator->trans('(~ approximate)'));
}
return implode(' ', $this->fragments);
}
protected function isFullyConvertible(Rule $rule)
{
if ($rule->getFreq() >= 5) {
return false;
}
$until = $rule->getUntil();
$count = $rule->getCount();
if (!empty($until) && !empty($count)) {
return false;
}
$bySecond = $rule->getBySecond();
$byMinute = $rule->getByMinute();
$byHour = $rule->getByHour();
if (!empty($bySecond) || !empty($byMinute) || !empty($byHour)) {
return false;
}
$byWeekNum = $rule->getByWeekNumber();
$byYearDay = $rule->getByYearDay();
if ($rule->getFreq() != 0 && (!empty($byWeekNum) || !empty($byYearDay))) {
return false;
}
return true;
}
protected function addYearly(Rule $rule)
{
$interval = $rule->getInterval();
$byMonth = $rule->getByMonth();
$byMonthDay = $rule->getByMonthDay();
$byDay = $rule->getByDay();
$byYearDay = $rule->getByYearDay();
$byWeekNum = $rule->getByWeekNumber();
if (!empty($byMonth) && count($byMonth) > 1 && $interval == 1) {
$this->addFragment($this->translator->trans('every_month_list'));
} else {
$this->addFragment($this->translator->trans($this->isPlural($interval) ? 'every %count% years' : 'every year', array('count' => $interval)));
}
$hasNoOrOneByMonth = is_null($byMonth) || count($byMonth) <= 1;
if ($hasNoOrOneByMonth && empty($byMonthDay) && empty($byDay) && empty($byYearDay) && empty($byWeekNum)) {
$this->addFragment($this->translator->trans('on'));
$monthNum = (is_array($byMonth) && count($byMonth)) ? $byMonth[0] : $rule->getStartDate()->format('n');
$this->addFragment(
$this->translator->trans('day_month', array('month' => $monthNum, 'day' => $rule->getStartDate()->format('d')))
);
} elseif (!empty($byMonth)) {
if ($interval != 1) {
$this->addFragment($this->translator->trans('in_month'));
}
$this->addByMonth($rule);
}
if (!empty($byMonthDay)) {
$this->addByMonthDay($rule);
$this->addFragment($this->translator->trans('of_the_month'));
} else if (!empty($byDay)) {
$this->addByDay($rule);
}
if (!empty($byYearDay)) {
$this->addFragment($this->translator->trans('on the'));
$this->addFragment($this->getByYearDayAsText($byYearDay));
$this->addFragment($this->translator->trans('day'));
}
if (!empty($byWeekNum)) {
$this->addFragment($this->translator->trans('in_week'));
$this->addFragment($this->translator->trans($this->isPlural(count($byWeekNum)) ? 'weeks' : 'week'));
$this->addFragment($this->getByWeekNumberAsText($byWeekNum));
}
if (empty($byMonthDay) && empty($byYearDay) && empty($byDay) && !empty($byWeekNum)) {
$this->addDayOfWeek($rule);
}
}
protected function addMonthly(Rule $rule)
{
$interval = $rule->getInterval();
$byMonth = $rule->getByMonth();
if (!empty($byMonth) && $interval == 1) {
$this->addFragment($this->translator->trans('every_month_list'));
} else {
$this->addFragment($this->translator->trans($this->isPlural($interval) ? 'every %count% months' : 'every month', array('count' => $interval)));
}
if (!empty($byMonth)) {
if ($interval != 1) {
$this->addFragment($this->translator->trans('in_month'));
}
$this->addByMonth($rule);
}
$byMonthDay = $rule->getByMonthDay();
$byDay = $rule->getByDay();
if (!empty($byMonthDay)) {
$this->addByMonthDay($rule);
} else if (!empty($byDay)) {
$this->addByDay($rule);
}
}
protected function addWeekly(Rule $rule)
{
$interval = $rule->getInterval();
$byMonth = $rule->getByMonth();
$byMonthDay = $rule->getByMonthDay();
$byDay = $rule->getByDay();
$this->addFragment($this->translator->trans($this->isPlural($interval) ? 'every %count% weeks' : 'every week', array('count' => $interval)));
if (empty($byMonthDay) && empty($byDay)) {
$this->addDayOfWeek($rule);
}
if (!empty($byMonth)) {
$this->addFragment($this->translator->trans('in_month'));
$this->addByMonth($rule);
}
if (!empty($byMonthDay)) {
$this->addByMonthDay($rule);
$this->addFragment($this->translator->trans('of_the_month'));
} else if (!empty($byDay)) {
$this->addByDay($rule);
}
}
protected function addDaily(Rule $rule)
{
$interval = $rule->getInterval();
$byMonth = $rule->getByMonth();
$this->addFragment($this->translator->trans($this->isPlural($interval) ? 'every %count% days' : 'every day', array('count' => $interval)));
if (!empty($byMonth)) {
$this->addFragment($this->translator->trans('in_month'));
$this->addByMonth($rule);
}
$byMonthDay = $rule->getByMonthDay();
$byDay = $rule->getByDay();
if (!empty($byMonthDay)) {
$this->addByMonthDay($rule);
$this->addFragment($this->translator->trans('of_the_month'));
} else if (!empty($byDay)) {
$this->addByDay($rule);
}
}
protected function addHourly(Rule $rule)
{
$interval = $rule->getInterval();
$byMonth = $rule->getByMonth();
$this->addFragment($this->translator->trans($this->isPlural($interval) ? 'every %count% hours' : 'every hour', array('count' => $interval)));
if (!empty($byMonth)) {
$this->addFragment($this->translator->trans('in_month'));
$this->addByMonth($rule);
}
$byMonthDay = $rule->getByMonthDay();
$byDay = $rule->getByDay();
if (!empty($byMonthDay)) {
$this->addByMonthDay($rule);
$this->addFragment($this->translator->trans('of_the_month'));
} else if (!empty($byDay)) {
$this->addByDay($rule);
}
}
protected function addByMonth(Rule $rule)
{
$byMonth = $rule->getByMonth();
if (empty($byMonth)) {
return;
}
$this->addFragment($this->getByMonthAsText($byMonth));
}
protected function addByMonthDay(Rule $rule)
{
$byMonthDay = $rule->getByMonthDay();
$byDay = $rule->getByDay();
if (!empty($byDay)) {
$this->addFragment($this->translator->trans('on'));
$this->addFragment($this->getByDayAsText($byDay, 'or'));
$this->addFragment($this->translator->trans('the_for_monthday'));
$this->addFragment($this->getByMonthDayAsText($byMonthDay, 'or'));
} else {
$this->addFragment($this->translator->trans('on the'));
$this->addFragment($this->getByMonthDayAsText($byMonthDay, 'and'));
}
}
protected function addByDay(Rule $rule)
{
$byDay = $rule->getByDay();
$this->addFragment($this->translator->trans('on'));
$this->addFragment($this->getByDayAsText($byDay));
}
protected function addDayOfWeek(Rule $rule)
{
$this->addFragment($this->translator->trans('on'));
$dayNames = $this->translator->trans('day_names');
$this->addFragment($dayNames[$rule->getStartDate()->format('w')]);
}
public function getByMonthAsText($byMonth)
{
if (empty($byMonth)) {
return '';
}
if (count($byMonth) > 1) {
sort($byMonth);
}
$monthNames = $this->translator->trans('month_names');
$byMonth = array_map(
function ($monthInt) use ($monthNames) {
return $monthNames[$monthInt - 1];
},
$byMonth
);
return $this->getListStringFromArray($byMonth);
}
public function getByDayAsText($byDay, $listSeparator = 'and')
{
if (empty($byDay)) {
return '';
}
$map = array(
'SU' => null,
'MO' => null,
'TU' => null,
'WE' => null,
'TH' => null,
'FR' => null,
'SA' => null
);
$dayNames = $this->translator->trans('day_names');
$timestamp = mktime(1, 1, 1, 1, 12, 2014); // A Sunday
foreach (array_keys($map) as $short) {
$long = $dayNames[date('w', $timestamp)];
$map[$short] = $long;
$timestamp += 86400;
}
$numOrdinals = 0;
foreach ($byDay as $key => $short) {
$day = strtoupper($short);
$string = '';
if (preg_match('/([+-]?)([0-9]*)([A-Z]+)/', $short, $parts)) {
$symbol = $parts[1];
$nth = $parts[2];
$day = $parts[3];
if (!empty($nth)) {
++$numOrdinals;
$string .= $this->getOrdinalNumber($symbol == '-' ? -$nth : $nth);
}
}
if (!isset($map[$day])) {
throw new \RuntimeException("byDay $short could not be transformed");
}
if (!empty($string)) {
$string .= ' ';
}
$byDay[$key] = ltrim($string.$map[$day]);
}
$output = $numOrdinals ? $this->translator->trans('the_for_weekday') . ' ' : '';
if ($output == ' ') {
$output = '';
}
$output .= $this->getListStringFromArray($byDay, $listSeparator);
return $output;
}
public function getByMonthDayAsText($byMonthDay, $listSeparator = 'and')
{
if (empty($byMonthDay)) {
return '';
}
// sort negative indices in reverse order so we get e.g. 1st, 2nd, 4th, 3rd last, last day
usort($byMonthDay, function ($a, $b) {
if (($a < 0 && $b < 0) || ($a >= 0 && $b >= 0)) {
return $a - $b;
}
return $b - $a;
});
// generate ordinal numbers and insert a "on the" for clarity in the middle if we have both
// positive and negative ordinals. This is to avoid confusing situations like:
//
// monthly on the 1st and 2nd to the last day
//
// which gets clarified to:
//
// monthly on the 1st day and on the 2nd to the last day
$hadPositives = false;
$hadNegatives = false;
foreach ($byMonthDay as $index => $day) {
$prefix = '';
if ($day >= 0) {
$hadPositives = true;
}
if ($day < 0) {
if ($hadPositives && !$hadNegatives && $listSeparator === 'and') {
$prefix = $this->translator->trans('on the') . ' ';
}
$hadNegatives = true;
}
$byMonthDay[$index] = $prefix . $this->getOrdinalNumber($day, end($byMonthDay) < 0, true);
}
return $this->getListStringFromArray($byMonthDay, $listSeparator);
}
public function getByYearDayAsText($byYearDay)
{
if (empty($byYearDay)) {
return '';
}
// sort negative indices in reverse order so we get e.g. 1st, 2nd, 4th, 3rd last, last day
usort($byYearDay, function ($a, $b) {
if (($a < 0 && $b < 0) || ($a >= 0 && $b >= 0)) {
return $a - $b;
}
return $b - $a;
});
$byYearDay = array_map(
array($this, 'getOrdinalNumber'),
$byYearDay,
array_fill(0, count($byYearDay), end($byYearDay) < 0)
);
return $this->getListStringFromArray($byYearDay);
}
public function getByWeekNumberAsText($byWeekNum)
{
if (empty($byWeekNum)) {
return '';
}
if (count($byWeekNum) > 1) {
sort($byWeekNum);
}
return $this->getListStringFromArray($byWeekNum);
}
protected function addFragment($fragment)
{
if ($fragment && $fragment !== ' ') {
$this->fragments[] = $fragment;
}
}
public function resetFragments()
{
$this->fragments = array();
}
protected function isPlural($number)
{
return $number % 100 != 1;
}
protected function getOrdinalNumber($number, $hasNegatives = false, $dayInMonth = false)
{
if (!preg_match('{^-?\d+$}D', $number)) {
throw new \RuntimeException('$number must be a whole number');
}
return $this->translator->trans('ordinal_number', array('number' => $number, 'has_negatives' => $hasNegatives, 'day_in_month' => $dayInMonth));
}
protected function getListStringFromArray($values, $separator = 'and')
{
$separator = $this->translator->trans($separator);
if (!is_array($values)) {
throw new \RuntimeException('$values must be an array.');
}
$numValues = count($values);
if (!$numValues) {
return '';
}
if ($numValues == 1) {
reset($values);
return current($values);
}
if ($numValues == 2) {
return implode(" $separator ", $values);
}
$lastValue = array_pop($values);
$output = implode(', ', $values);
$output .= " $separator ".$lastValue;
return $output;
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace Recurr\Transformer;
class Translator implements TranslatorInterface
{
protected $data = array();
public function __construct($locale = 'en', $fallbackLocale = 'en')
{
$this->loadLocale($fallbackLocale);
if ($locale !== $fallbackLocale) {
$this->loadLocale($locale);
}
}
public function loadLocale($locale, $path = null)
{
if (!$path) {
$path = __DIR__ . '/../../../translations/' . $locale . '.php';
}
if (!file_exists($path)) {
throw new \InvalidArgumentException('Locale '.$locale.' could not be found in '.$path);
}
$this->data = array_merge($this->data, include $path);
}
public function trans($string, array $params = array())
{
$res = $this->data[$string];
if (is_object($res) && is_callable($res)) {
$res = $res($string, $params);
}
foreach ($params as $key => $val) {
$res = str_replace('%' . $key . '%', $val, $res);
}
return $res;
}
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Recurr\Transformer;
interface TranslatorInterface
{
public function trans($string);
}

View File

@@ -0,0 +1,72 @@
<?php
/*
* Copyright 2013 Shaun Simmons
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* Based on rrule.js
* Copyright 2010, Jakub Roztocil and Lars Schoning
* https://github.com/jkbr/rrule/blob/master/LICENCE
*/
namespace Recurr;
use Recurr\Exception\InvalidWeekday;
/**
* Class Weekday is a storage container for a day of the week.
*
* @package Recurr
* @author Shaun Simmons <shaun@envysphere.com>
*/
class Weekday
{
/**
* Weekday number.
*
* 0 = Sunday
* 1 = Monday
* 2 = Tuesday
* 3 = Wednesday
* 4 = Thursday
* 5 = Friday
* 6 = Saturday
*
* @var string
*/
public $weekday;
/** @var int nth occurrence of the weekday */
public $num;
protected $days = array('MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU');
/**
* @param int|string $weekday 0-6 or MO..SU
* @param null|int $num
*
* @throws InvalidWeekday
*/
public function __construct($weekday, $num)
{
if (is_numeric($weekday) && $weekday > 6 || $weekday < 0) {
throw new InvalidWeekday('Day is not a valid weekday (0-6)');
} elseif (!is_numeric($weekday) && !in_array($weekday, $this->days)) {
throw new InvalidWeekday('Day is not a valid weekday (SU, MO, ...)');
}
if (!is_numeric($weekday)) {
$weekday = array_search($weekday, $this->days);
}
$this->weekday = $weekday;
$this->num = $num;
}
public function __toString()
{
return $this->num . $this->days[$this->weekday];
}
}

View File

@@ -0,0 +1,100 @@
<?php
// sunday first as date('w') is zero-based on sunday
$days = array(
'søndag',
'mandag',
'tirsdag',
'onsdag',
'torsdag',
'fredag',
'lørdag',
);
$months = array(
'januar',
'februar',
'marts',
'april',
'maj',
'juni',
'juli',
'august',
'september',
'oktober',
'november',
'december',
);
return array(
'Unable to fully convert this rrule to text.' => 'Kunne ikke konvertere denne regel til tekst.',
'for %count% times' => '%count% gange',
'for one time' => 'en gang',
'(~ approximate)' => '(~ cirka)',
'until %date%' => 't.o.m. %date%', // e.g. every year until July 4, 2014
'day_date' => function ($str, $params) use ($days, $months) { // outputs a day date, e.g. July 4, 2014
return date('j', $params['date']) . '. '. $months[date('n', $params['date']) - 1].date(', Y', $params['date']);
},
'day_month' => function ($str, $params) use ($days, $months) { // outputs a day month, e.g. July 4
return $params['day'].'. '.$months[$params['month'] - 1];
},
'day_names' => $days,
'month_names' => $months,
'and' => 'og',
'or' => 'eller',
'in_month' => 'i', // e.g. weekly in January, May and August
'in_week' => 'i', // e.g. yearly in week 3
'on' => 'hver', // e.g. every day on Tuesday, Wednesday and Friday
'the_for_monthday' => 'den', // e.g. monthly on Tuesday the 1st
'the_for_weekday' => 'den', // e.g. monthly on the 4th Monday
'on the' => 'på den', // e.g. every year on the 1st and 200th day
'of_the_month' => 'i måneden', // e.g. every year on the 2nd or 3rd of the month
'every %count% years' => 'hvert %count% år',
'every year' => 'årligt',
'every_month_list' => 'hver', // e.g. every January, May and August
'every %count% months' => 'hver %count% måned',
'every month' => 'månedsvis',
'every %count% weeks' => 'hver %count% uge',
'every week' => 'ugenligt',
'every %count% days' => 'hver %count% dag',
'every day' => 'dagligt',
'last' => 'sidste', // e.g. 2nd last Friday
'days' => 'dage',
'day' => 'dag',
'weeks' => 'uger',
'week' => 'uge',
// formats a number with a prefix e.g. every year on the 1st and 200th day
// negative numbers should be handled as in '5th to the last' or 'last'
//
// if has_negatives is true in the params, it is good form to add 'day' after
// each number, as in: 'every month on the 5th day or 2nd to the last day' or
// it may be confusing like 'every month on the 5th or 2nd to the last day'
'ordinal_number' => function ($str, $params) {
$number = $params['number'];
$ends = array(':e', ':a', ':a', ':e', ':e', ':e', ':e', ':e', ':e', ':e');
$suffix = '';
$isNegative = $number < 0;
if ($number == -1) {
$abbreviation = 'last';
} else {
if ($isNegative) {
$number = abs($number);
$suffix = ' to the last';
}
if (($number % 100) >= 11 && ($number % 100) <= 13) {
$abbreviation = $number.'.';
} else {
$abbreviation = $number.$ends[$number % 10];
}
}
if (!empty($params['has_negatives'])) {
$suffix .= ' dag';
}
return $abbreviation . $suffix;
},
);

View File

@@ -0,0 +1,116 @@
<?php
// sunday first as date('w') is zero-based on sunday
$days = array(
'Sonntag',
'Montag',
'Dienstag',
'Mittwoch',
'Donnerstag',
'Freitag',
'Samstag',
);
$months = array(
'Januar',
'Februar',
'März',
'April',
'Mai',
'Juni',
'Juli',
'August',
'September',
'Oktober',
'November',
'Dezember',
);
return array(
'Unable to fully convert this rrule to text.' => 'RRule kann nicht vollständig zu Text konvertiert werden.',
'for %count% times' => '%count% Mal',
'for one time' => 'einmal',
'(~ approximate)' => '(~ ungefähr)',
'until %date%' => 'bis %date%', // e.g. every year until July 4, 2014
'day_date' => function ($str, $params) use ($days, $months) { // outputs a day date, e.g. 4. Juli, 2014
return date('j. ', $params['date']) . $months[date('n', $params['date']) - 1] . date(', Y', $params['date']);
},
'day_month' => function ($str, $params) use ($days, $months) { // outputs a day month, e.g. July 4
return $params['day'].'. '.$months[$params['month'] - 1];
},
'day_names' => $days,
'month_names' => $months,
'and' => 'und',
'or' => 'oder',
'in_month' => 'im', // e.g. weekly in January, May and August
'in_week' => 'in', // e.g. yearly in week 3
'on' => 'am', // e.g. every day on Tuesday, Wednesday and Friday
'the_for_monthday' => 'dem', // e.g. monthly on Tuesday the 1st
'the_for_weekday' => '', // e.g. monthly on the 4th Monday
'on the' => 'am', // e.g. every year on the 1st and 200th day
'of_the_month' => 'des Monats', // e.g. every year on the 2nd or 3rd of the month
'every %count% years' => 'alle %count% Jahre',
'every year' => 'jährlich',
'every_month_list' => 'jeden', // e.g. every January, May and August
'every %count% months' => 'alle %count% Monate',
'every month' => 'monatlich',
'every %count% weeks' => 'alle %count% Wochen',
'every week' => 'wöchentlich',
'every %count% days' => 'alle %count% Tage',
'every day' => 'täglich',
'every %count% hours' => 'alle %count% Stunden',
'every hour' => 'stündlich',
'last' => 'letzte', // e.g. 2nd last Friday
'days' => 'Tage',
'day' => 'Tag',
'weeks' => 'Wochen',
'week' => 'Woche',
'hours' => 'Stunden',
'hour' => 'stündlich',
// formats a number with a prefix e.g. every year on the 1st and 200th day
// negative numbers should be handled as in '5th to the last' or 'last'
//
// if has_negatives is true in the params, it is good form to add 'day' after
// each number, as in: 'every month on the 5th day or 2nd to the last day' or
// it may be confusing like 'every month on the 5th or 2nd to the last day'
'ordinal_number' => function ($str, $params) {
$number = $params['number'];
$suffix = '';
$isNegative = $number < 0;
if ($number == -1) {
$abbreviation = 'letzten';
} elseif ($number == -2) {
$abbreviation = 'vorletzten';
} elseif ($number == -3) {
$abbreviation = 'drittletzten';
} elseif ($number == -4) {
$abbreviation = 'viertletzten';
} elseif ($number == -5) {
$abbreviation = 'fünftletzten';
} elseif ($number == -6) {
$abbreviation = 'sechstletzten';
} elseif ($number == -7) {
$abbreviation = 'siebtletzten';
} elseif ($number == -8) {
$abbreviation = 'achtletzten';
} elseif ($number == -9) {
$abbreviation = 'neuntletzten';
} elseif ($number == -10) {
$abbreviation = 'zehntletzten';
} elseif ($number == -11) {
$abbreviation = 'elftletzten';
} elseif ($isNegative) {
$number = abs($number);
$abbreviation = $number . 't letzten';
} else {
$abbreviation = $number . '.';
}
if (!empty($params['has_negatives']) && $isNegative) {
$suffix .= ' Tag';
}
return $abbreviation . $suffix;
},
);

View File

@@ -0,0 +1,110 @@
<?php
// sunday first as date('w') is zero-based on sunday
$days = array(
'Κυριακή',
'Δευτέρα',
'Τρίτη',
'Τετάρτη',
'Πέμπτη',
'Παρασκευή',
'Σάββατο',
);
$months = array(
'Ιανουάριος',
'Φεβρουάριος',
'Μάρτιος',
'Απρίλιος',
'Μάιος',
'Ιούνιος',
'Ιούλιος',
'Αύγουστος',
'Σεπτέμβριος',
'Οκτώβριος',
'Νοέμβριος',
'Δεκέμβριος',
);
$months_genitive = array(
'Ιανουαρίου',
'Φεβρουαρίου',
'Μαρτίου',
'Απριλίου',
'Μαΐου',
'Ιουνίου',
'Ιουλίου',
'Αυγούστου',
'Σεπτεμβρίου',
'Οκτωβρίου',
'Νοεμβρίου',
'Δεκεμβρίου',
);
return array(
'Unable to fully convert this rrule to text.' => 'Αδυναμία πλήρους μετατροπής αυτού του κανόνα rrule σε κείμενο.',
'for %count% times' => 'για %count% φορές',
'for one time' => 'για μία φορά',
'(~ approximate)' => '(~ κατά προσέγγιση)',
'until %date%' => 'μέχρι %date%', // e.g. every year until July 4, 2014
'day_date' => function ($str, $params) use ($days, $months_genitive) { // outputs a day date, e.g. 4 Ιουλίου 2014
return date('j', $params['date']) . ' ' . $months_genitive[date('n', $params['date']) - 1] . ' '. date('Y', $params['date']);
},
'day_month' => function ($str, $params) use ($days, $months_genitive) { // outputs a day month, e.g. 4 Ιουλίου
return $params['day'] . ' ' . $months_genitive[$params['month'] - 1];
},
'day_names' => $days,
'month_names' => $months,
'and' => 'και',
'or' => 'ή',
'in_month' => 'τον', // e.g. weekly in January, May and August
'in_week' => 'την', // e.g. yearly in week 3
'on' => 'την', // e.g. every day on Tuesday, Wednesday and Friday
'the_for_monthday' => 'την', // e.g. monthly on Tuesday the 1st
'the_for_weekday' => 'την', // e.g. monthly on the 4th Monday
'on the' => 'την', // e.g. every year on the 1st and 200th day
'of_the_month' => 'του μήνα', // e.g. every year on the 2nd or 3rd of the month
'every %count% years' => 'κάθε %count% χρόνια',
'every year' => 'ετήσια',
'every_month_list' => 'κάθε', // e.g. every January, May and August
'every %count% months' => 'κάθε %count% μήνες',
'every month' => 'μηνιαία',
'every %count% weeks' => 'κάθε %count% εβδομάδες',
'every week' => 'εβδομαδιαία',
'every %count% days' => 'κάθε %count% ημέρες',
'every day' => 'καθημερινά',
'last' => 'τελευταία', // e.g. 2nd last Friday
'days' => 'ημέρες',
'day' => 'ημέρα',
'weeks' => 'εβδομάδες',
'week' => 'εβδομάδα',
// formats a number with a prefix e.g. every year on the 1st and 200th day
// negative numbers should be handled as in '5th to the last' or 'last'
//
// if has_negatives is true in the params, it is good form to add 'day' after
// each number, as in: 'every month on the 5th day or 2nd to the last day' or
// it may be confusing like 'every month on the 5th or 2nd to the last day'
'ordinal_number' => function ($str, $params) {
$number = $params['number'];
$ends = 'η';
$suffix = '';
$isNegative = $number < 0;
if ($number == -1) {
$abbreviation = 'τελευταία';
} else {
if ($isNegative) {
$number = abs($number);
$suffix = ' μέχρι την τελευταία';
}
$abbreviation = $number . $ends;
}
if (!empty($params['has_negatives'])) {
$suffix .= ' ημέρα';
}
return $abbreviation . $suffix;
},
);

View File

@@ -0,0 +1,104 @@
<?php
// sunday first as date('w') is zero-based on sunday
$days = array(
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
);
$months = array(
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
);
return array(
'Unable to fully convert this rrule to text.' => 'Unable to fully convert this rrule to text.',
'for %count% times' => 'for %count% times',
'for one time' => 'once',
'(~ approximate)' => '(~ approximate)',
'until %date%' => 'until %date%', // e.g. every year until July 4, 2014
'day_date' => function ($str, $params) use ($days, $months) { // outputs a day date, e.g. July 4, 2014
return $months[date('n', $params['date']) - 1] . ' '. date('j, Y', $params['date']);
},
'day_month' => function ($str, $params) use ($days, $months) { // outputs a day month, e.g. July 4
return $months[$params['month'] - 1] . ' '. $params['day'];
},
'day_names' => $days,
'month_names' => $months,
'and' => 'and',
'or' => 'or',
'in_month' => 'in', // e.g. weekly in January, May and August
'in_week' => 'in', // e.g. yearly in week 3
'on' => 'on', // e.g. every day on Tuesday, Wednesday and Friday
'the_for_monthday' => 'the', // e.g. monthly on Tuesday the 1st
'the_for_weekday' => 'the', // e.g. monthly on the 4th Monday
'on the' => 'on the', // e.g. every year on the 1st and 200th day
'of_the_month' => 'of the month', // e.g. every year on the 2nd or 3rd of the month
'every %count% years' => 'every %count% years',
'every year' => 'yearly',
'every_month_list' => 'every', // e.g. every January, May and August
'every %count% months' => 'every %count% months',
'every month' => 'monthly',
'every %count% weeks' => 'every %count% weeks',
'every week' => 'weekly',
'every %count% days' => 'every %count% days',
'every day' => 'daily',
'every %count% hours' => 'every %count% hours',
'every hour' => 'hourly',
'last' => 'last', // e.g. 2nd last Friday
'days' => 'days',
'day' => 'day',
'weeks' => 'weeks',
'week' => 'week',
'hours' => 'hours',
'hour' => 'hour',
// formats a number with a prefix e.g. every year on the 1st and 200th day
// negative numbers should be handled as in '5th to the last' or 'last'
//
// if has_negatives is true in the params, it is good form to add 'day' after
// each number, as in: 'every month on the 5th day or 2nd to the last day' or
// it may be confusing like 'every month on the 5th or 2nd to the last day'
'ordinal_number' => function ($str, $params) {
$number = $params['number'];
$ends = array('th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th');
$suffix = '';
$isNegative = $number < 0;
if ($number == -1) {
$abbreviation = 'last';
} else {
if ($isNegative) {
$number = abs($number);
$suffix = ' to the last';
}
if (($number % 100) >= 11 && ($number % 100) <= 13) {
$abbreviation = $number.'th';
} else {
$abbreviation = $number.$ends[$number % 10];
}
}
if (!empty($params['has_negatives'])) {
$suffix .= ' day';
}
return $abbreviation . $suffix;
},
);

View File

@@ -0,0 +1,100 @@
<?php
// sunday first as date('w') is zero-based on sunday
$days = array(
'domingo',
'lunes',
'martes',
'miércoles',
'jueves',
'viernes',
'sábado',
);
$months = array(
'enero',
'febrero',
'marzo',
'abril',
'mayo',
'junio',
'julio',
'agosto',
'septiembre',
'octubre',
'noviembre',
'diciembre',
);
return array(
'Unable to fully convert this rrule to text.' => 'No se puede convertir completamente este RRULE al texto.',
'for %count% times' => 'para %count% veces',
'for one time' => 'por una vez',
'(~ approximate)' => '(~ aproximado)',
'until %date%' => 'hasta %date%', // e.g. every year until July 4, 2014
'day_date' => function ($str, $params) use ($days, $months) { // outputs a day date, e.g. July 4, 2014
return $months[date('n', $params['date']) - 1] . ' '. date('j, Y', $params['date']);
},
'day_month' => function ($str, $params) use ($days, $months) { // outputs a day month, e.g. July 4
return $months[$params['month'] - 1] . ' '. $params['day'];
},
'day_names' => $days,
'month_names' => $months,
'and' => 'y',
'or' => 'o',
'in_month' => 'en', // e.g. weekly in January, May and August
'in_week' => 'en', // e.g. yearly in week 3
'on' => 'en', // e.g. every day on Tuesday, Wednesday and Friday
'the_for_monthday' => 'el', // e.g. monthly on Tuesday the 1st
'the_for_weekday' => 'en el', // e.g. monthly on the 4th Monday
'on the' => 'en el', // e.g. every year on the 1st and 200th day
'of_the_month' => 'del mes', // e.g. every year on the 2nd or 3rd of the month
'every %count% years' => 'cada %count% años',
'every year' => 'anual',
'every_month_list' => 'cada', // e.g. every January, May and August
'every %count% months' => 'cada %count% meses',
'every month' => 'mensual',
'every %count% weeks' => 'cada %count% semanas',
'every week' => 'cada semana',
'every %count% days' => 'cada %count% días',
'every day' => 'diariamente',
'last' => 'pasado', // e.g. 2nd last Friday
'days' => 'día',
'day' => 'el día',
'weeks' => 'semanas',
'week' => 'semana',
// formats a number with a prefix e.g. every year on the 1st and 200th day
// negative numbers should be handled as in '5th to the last' or 'last'
//
// if has_negatives is true in the params, it is good form to add 'day' after
// each number, as in: 'every month on the 5th day or 2nd to the last day' or
// it may be confusing like 'every month on the 5th or 2nd to the last day'
'ordinal_number' => function ($str, $params) {
$number = $params['number'];
$ends = array('a', 'a', 'nd', 'a', 'a', 'a', 'a', 'a', 'a', 'a');
$suffix = '';
$isNegative = $number < 0;
if ($number == -1) {
$abbreviation = 'último';
} else {
if ($isNegative) {
$number = abs($number);
$suffix = ' a la última';
}
if (($number % 100) >= 11 && ($number % 100) <= 13) {
$abbreviation = $number.'a';
} else {
$abbreviation = $number.$ends[$number % 10];
}
}
if (!empty($params['has_negatives'])) {
$suffix .= ' día';
}
return $abbreviation . $suffix;
},
);

View File

@@ -0,0 +1,43 @@
<?php
return array(
'Unable to fully convert this rrule to text.' => 'Ezin izan da rrule testura osoki bihurtu.',
'for %count% times' => '%count% aldiz',
'for %count% time' => '%count% aldia',
'(~ approximate)' => '(~ inguru)',
'until %date%' => '%date% arte', // e.g. every year until July 4, 2014
'day_date' => defined('PHP_WINDOWS_VERSION_BUILD') ? '%B %#d, %Y' : '%B %e, %Y',
'and' => 'eta',
'or' => 'edo',
'in' => 'hilabete hauetan:', // e.g. every week in January, May and August
'on' => 'egun hauetan:', // e.g. every day on Tuesday, Wednesday and Friday
'the' => '',
'on the' => '', // e.g. every year on the 1st and 200th day
'every %count% years' => '%count% urtero',
'every year' => 'urtero',
'every_month_list' => 'hilabete hauetan', // e.g. every January, May and August
'every %count% months' => '%count% hilabetero',
'every month' => 'hilabetero',
'every %count% weeks' => '%count% astero',
'every week' => 'astero',
'every %count% days' => '%count% egunero',
'every day' => 'egunero',
'last' => 'azken', // e.g. 2nd last Friday
'days' => 'egun',
'day' => 'egun',
'weeks' => 'aste',
'week' => 'aste',
'ordinal_number' => function ($str, $params) { // formats a number with a prefix e.g. every year on the 1st and 200th day
$number = $params['number'];
$ends = array('garren', 'go', 'garren', 'garren', 'garren', 'garren', 'garren', 'garren', 'garren', 'garren');
if (($number % 100) >= 11 && ($number % 100) <= 13) {
$abbreviation = $number.'garren';
} else {
$abbreviation = $number.$ends[$number % 10];
}
return $abbreviation;
},
);

View File

@@ -0,0 +1,103 @@
<?php
// sunday first as date('w') is zero-based on sunday
$days = array(
'dimanche',
'lundi',
'mardi',
'mercredi',
'jeudi',
'vendredi',
'samedi',
);
$months = array(
'janvier',
'février',
'mars',
'avril',
'mai',
'juin',
'juillet',
'août',
'septembre',
'octobre',
'novembre',
'décembre',
);
return array(
'Unable to fully convert this rrule to text.' => 'Cette règle de récurrence n\'a pas pu être convertie en texte.',
'for %count% times' => '%count% fois',
'for one time' => 'une fois',
'(~ approximate)' => '(~ approximation)',
'until %date%' => 'jusqu\'au %date%', // e.g. every year until July 4, 2014
'day_date' => function ($str, $params) use ($days, $months) { // outputs a day date, e.g. 4 juillet, 2014
return date('j ', $params['date']) . $months[date('n', $params['date']) - 1] . date(', Y', $params['date']);
},
'day_month' => function ($str, $params) use ($days, $months) { // outputs a day month, e.g. July 4
return $params['day'].' '.$months[$params['month'] - 1];
},
'day_names' => $days,
'month_names' => $months,
'and' => 'et',
'or' => 'ou',
'in_month' => 'en', // e.g. weekly in January, May and August
'in_week' => 'en', // e.g. yearly in week 3
'on' => 'le', // e.g. every day on Tuesday, Wednesday and Friday
'the_for_monthday' => 'le', // e.g. monthly on Tuesday the 1st
'the_for_weekday' => '', // e.g. monthly on the 4th Monday
'on the' => 'le', // e.g. every year on the 1st and 200th day
'of_the_month' => 'du mois', // e.g. every year on the 2nd or 3rd of the month
'every %count% years' => 'tous les %count% ans',
'every year' => 'chaque année',
'every_month_list' => 'chaque', // e.g. every January, May and August
'every %count% months' => 'tous les %count% mois',
'every month' => 'chaque mois',
'every %count% weeks' => 'toutes les %count% semaines',
'every week' => 'chaque semaine',
'every %count% days' => 'tous les %count% jours',
'every day' => 'chaque jour',
'every %count% hours' => 'toutes les %count% heures',
'every hour' => 'chaque heure',
'last' => 'dernier', // e.g. 2nd last Friday
'days' => 'jours',
'day' => 'jour',
'weeks' => 'semaines',
'week' => 'semaine',
'hours' => 'heures',
'hour' => 'heure',
// formats a number with a prefix e.g. every year on the 1st and 200th day
// negative numbers should be handled as in '5th to the last' or 'last'
//
// if has_negatives is true in the params, it is good form to add 'day' after
// each number, as in: 'every month on the 5th day or 2nd to the last day' or
// it may be confusing like 'every month on the 5th or 2nd to the last day'
'ordinal_number' => function ($str, $params) {
$number = $params['number'];
$suffix = '';
$isNegative = $number < 0;
if ($number == -1) {
$abbreviation = 'dernier';
} elseif ($number == -2) {
$abbreviation = 'avant dernier';
} elseif ($isNegative) {
$number = abs($number);
$abbreviation = $number . 'ème au dernier';
} elseif ($number == 1 && (!$params['day_in_month'])) {
$abbreviation = $number . 'er';
} else if (!$params['day_in_month']) {
$abbreviation = $number . 'ème';
}
else {
$abbreviation = $number;
}
if (!empty($params['has_negatives'])) {
$suffix .= ' jour';
}
return $abbreviation . $suffix;
},
);

View File

@@ -0,0 +1,116 @@
<?php
// sunday first as date('w') is zero-based on sunday
$days = array(
'domenica',
'lunedì',
'martedì',
'mercoledì',
'giovedì',
'venerdì',
'sabato',
);
$months = array(
'gennaio',
'febbraio',
'marzo',
'aprile',
'maggio',
'giugno',
'luglio',
'agosto',
'settembre',
'ottobre',
'novembre',
'dicembre',
);
return array(
'Unable to fully convert this rrule to text.' => 'Non è possibile convertire questo rrule in testo.',
'for %count% times' => 'per %count% volte',
'for one time' => 'per una volta',
'(~ approximate)' => '(~ approssimato)',
'until %date%' => 'fino al %date%', // e.g. every year until July 4, 2014
'day_date' => function ($str, $params) use ($days, $months) { // outputs a day date, e.g. 4 luglio, 2014
return date('j ', $params['date']) . $months[date('n', $params['date']) - 1] . date(', Y', $params['date']);
},
'day_month' => function ($str, $params) use ($days, $months) { // outputs a day month, e.g. July 4
return $params['day'].' '.$months[$params['month'] - 1];
},
'day_names' => $days,
'month_names' => $months,
'and' => 'e',
'or' => 'o',
'in_month' => 'in', // e.g. weekly in January, May and August
'in_week' => 'in', // e.g. yearly in week 3
'on' => 'il', // e.g. every day on Tuesday, Wednesday and Friday
'the_for_monthday' => 'il', // e.g. monthly on Tuesday the 1st
'the_for_weekday' => 'il', // e.g. monthly on the 4th Monday
'on the' => 'il', // e.g. every year on the 1st and 200th day
'of_the_month' => 'del mese', // e.g. every year on the 2nd or 3rd of the month
'every %count% years' => 'ogni %count% anni',
'every year' => 'ogni anno',
'every_month_list' => 'ogni', // e.g. every January, May and August
'every %count% months' => 'ogni %count% mesi',
'every month' => 'ogni mese',
'every %count% weeks' => 'ogni %count% settimane',
'every week' => 'ogni settimana',
'every %count% days' => 'ogni %count% giorni',
'every day' => 'ogni giorno',
'every %count% hours' => 'ogni %count% ore',
'every hour' => 'ogni ora',
'last' => 'scorso', // e.g. 2nd last Friday
'days' => 'giorni',
'day' => 'giorno',
'weeks' => 'settimane',
'week' => 'settimana',
'hours' => 'ore',
'hour' => 'ora',
// formats a number with a prefix e.g. every year on the 1st and 200th day
// negative numbers should be handled as in '5th to the last' or 'last'
//
// if has_negatives is true in the params, it is good form to add 'day' after
// each number, as in: 'every month on the 5th day or 2nd to the last day' or
// it may be confusing like 'every month on the 5th or 2nd to the last day'
'ordinal_number' => function ($str, $params) {
$number = $params['number'];
$suffix = '';
$isNegative = $number < 0;
if ($number == -1) {
$abbreviation = 'ultimo';
} elseif ($number == -2) {
$abbreviation = 'penultimo';
} elseif ($number == -3) {
$abbreviation = 'terzultimo';
} elseif ($number == -4) {
$abbreviation = 'quarto ultimo';
} elseif ($number == -5) {
$abbreviation = 'quinta ultimo';
} elseif ($number == -6) {
$abbreviation = 'sesto ultimo';
} elseif ($number == -7) {
$abbreviation = 'settimo ultimo';
} elseif ($number == -8) {
$abbreviation = 'otto ultimo';
} elseif ($number == -9) {
$abbreviation = 'nono ultimo';
} elseif ($number == -10) {
$abbreviation = 'decimo ultimo';
} elseif ($number == -11) {
$abbreviation = 'undici ultimo';
} elseif ($isNegative) {
$number = abs($number);
$abbreviation = $number . ' ultimo';
} else {
$abbreviation = $number;
}
if (!empty($params['has_negatives'])) {
$suffix .= ' giorno';
}
return $abbreviation . $suffix;
},
);

View File

@@ -0,0 +1,100 @@
<?php
// sunday first as date('w') is zero-based on sunday
$days = array(
'zondag',
'maandag',
'dinsdag',
'woensdag',
'donderdag',
'vrijdag',
'zaterdag',
);
$months = array(
'januari',
'februari',
'maart',
'april',
'mei',
'juni',
'juli',
'augustus',
'september',
'oktober',
'november',
'december',
);
return array(
'Unable to fully convert this rrule to text.' => 'Unable to fully convert this rrule to text.',
'for %count% times' => 'voor %count% keer',
'for one time' => 'eenmalig',
'(~ approximate)' => '(~ ongeveer)',
'until %date%' => 'tot en met %date%', // e.g. every year until July 4, 2014
'day_date' => function ($str, $params) use ($days, $months) { // outputs a day date, e.g. July 4, 2014
return date('j', $params['date']).' '.$months[date('n', $params['date']) - 1] . ' '. date('Y', $params['date']);
},
'day_month' => function ($str, $params) use ($days, $months) { // outputs a day month, e.g. July 4
return $params['day'].' '.$months[$params['month'] - 1];
},
'day_names' => $days,
'month_names' => $months,
'and' => 'en',
'or' => 'of',
'in_month' => 'op', // e.g. weekly in January, May and August
'in_week' => 'op', // e.g. yearly in week 3
'on' => 'op', // e.g. every day on Tuesday, Wednesday and Friday
'the_for_monthday' => 'de', // e.g. monthly on Tuesday the 1st
'the_for_weekday' => 'de', // e.g. monthly on the 4th Monday
'on the' => 'op de', // e.g. every year on the 1st and 200th day
'of_the_month' => 'van de maand', // e.g. every year on the 2nd or 3rd of the month
'every %count% years' => 'elke %count% jaar',
'every year' => 'jaarlijks',
'every_month_list' => 'elke', // e.g. every January, May and August
'every %count% months' => 'elke %count% maanden',
'every month' => 'maandelijks',
'every %count% weeks' => 'elke %count% weken',
'every week' => 'wekelijks',
'every %count% days' => 'elke %count% dagen',
'every day' => 'dagelijks',
'last' => 'laatste', // e.g. 2nd last Friday
'days' => 'dagen',
'day' => 'dag',
'weeks' => 'weken',
'week' => 'week',
// formats a number with a prefix e.g. every year on the 1st and 200th day
// negative numbers should be handled as in '5th to the last' or 'last'
//
// if has_negatives is true in the params, it is good form to add 'day' after
// each number, as in: 'every month on the 5th day or 2nd to the last day' or
// it may be confusing like 'every month on the 5th or 2nd to the last day'
'ordinal_number' => function ($str, $params) {
$number = $params['number'];
$ends = array('ste', 'de', 'de', 'de', 'de', 'de', 'de', 'de', 'de', 'de');
$suffix = '';
$isNegative = $number < 0;
if ($number == -1) {
$abbreviation = 'laatste';
} else {
if ($isNegative) {
$number = abs($number);
$suffix = ' na laatste';
}
if (($number % 100) >= 11 && ($number % 100) <= 13) {
$abbreviation = $number.'ste';
} else {
$abbreviation = $number.$ends[$number % 10];
}
}
if (!empty($params['has_negatives'])) {
$suffix .= ' dag';
}
return $abbreviation . $suffix;
},
);

View File

@@ -0,0 +1,100 @@
<?php
// sunday first as date('w') is zero-based on sunday
$days = array(
'Søndag',
'Mandag',
'Tirsdag',
'Onsdag',
'Torsdag',
'Fredag',
'Lørdag',
);
$months = array(
'Januar',
'Februar',
'Mars',
'April',
'Mai',
'Juni',
'Juli',
'August',
'September',
'Oktober',
'November',
'Desember',
);
return array(
'Unable to fully convert this rrule to text.' => 'Kunne ikke konvertere rrule til tekst.',
'for %count% times' => '%count% ganger',
'for one time' => 'en gang',
'(~ approximate)' => '(~ omtrent)',
'until %date%' => 'frem til %date%', // e.g. every year until July 4, 2014
'day_date' => function ($str, $params) use ($days, $months) { // outputs a day date, e.g. July 4, 2014
return $months[date('n', $params['date']) - 1] . ' '. date('j, Y', $params['date']);
},
'day_month' => function ($str, $params) use ($days, $months) { // outputs a day month, e.g. July 4
return $months[$params['month'] - 1] . ' '. $params['day'];
},
'day_names' => $days,
'month_names' => $months,
'and' => 'og',
'or' => 'eller',
'in_month' => 'i', // e.g. weekly in January, May and August
'in_week' => 'i', // e.g. yearly in week 3
'on' => 'på', // e.g. every day on Tuesday, Wednesday and Friday
'the_for_monthday' => 'den', // e.g. monthly on Tuesday the 1st
'the_for_weekday' => 'den', // e.g. monthly on the 4th Monday
'on the' => 'på den', // e.g. every year on the 1st and 200th day
'of_the_month' => 'i måneden', // e.g. every year on the 2nd or 3rd of the month
'every %count% years' => 'hvert %count% år',
'every year' => 'årlig',
'every_month_list' => 'hver', // e.g. every January, May and August
'every %count% months' => 'hver %count% måned',
'every month' => 'månedlig',
'every %count% weeks' => 'hver %count% uke',
'every week' => 'ukentlig',
'every %count% days' => 'hver %count% dag',
'every day' => 'daglig',
'last' => 'siste', // e.g. 2nd last Friday
'days' => 'dager',
'day' => 'dag',
'weeks' => 'uker',
'week' => 'uke',
// formats a number with a prefix e.g. every year on the 1st and 200th day
// negative numbers should be handled as in '5th to the last' or 'last'
//
// if has_negatives is true in the params, it is good form to add 'day' after
// each number, as in: 'every month on the 5th day or 2nd to the last day' or
// it may be confusing like 'every month on the 5th or 2nd to the last day'
'ordinal_number' => function ($str, $params) {
$number = $params['number'];
$ends = array('th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th');
$suffix = '';
$isNegative = $number < 0;
if ($number == -1) {
$abbreviation = 'sist';
} else {
if ($isNegative) {
$number = abs($number);
$suffix = ' til den siste';
}
if (($number % 100) >= 11 && ($number % 100) <= 13) {
$abbreviation = $number.'th';
} else {
$abbreviation = $number.$ends[$number % 10];
}
}
if (!empty($params['has_negatives'])) {
$suffix .= ' dag';
}
return $abbreviation . $suffix;
},
);

View File

@@ -0,0 +1,87 @@
<?php
// sunday first as date('w') is zero-based on sunday
$days = array(
'domingo',
'segunda-feira',
'terça-feira',
'quarta-feira',
'quinta-feira',
'sexta-feira',
'sábado',
);
$months = array(
'Janeiro',
'Fevereiro',
'Março',
'Abril',
'Maio',
'Junho',
'Julho',
'Agosto',
'Setembro',
'Outubro',
'Novembro',
'Dezembro',
);
return array(
'Unable to fully convert this rrule to text.' => 'Não foi possível converter esta regra para texto.',
'for %count% times' => 'por %count% vezes',
'for one time' => 'uma vez',
'(~ approximate)' => '(~ approximado)',
'until %date%' => 'até %date%', // e.g. every year until July 4, 2014
'day_date' => function ($str, $params) use ($days, $months) { // outputs a day date, e.g. July 4, 2014
return date('j', $params['date']) . ' de ' . $months[date('n', $params['date']) - 1] . ' de ' . date('Y', $params['date']);
},
'day_month' => function ($str, $params) use ($days, $months) { // outputs a day month, e.g. July 4
return $params['day'].' de '.$months[$params['month'] - 1];
},
'day_names' => $days,
'month_names' => $months,
'and' => 'e',
'or' => 'ou',
'in_month' => 'em', // e.g. weekly in January, May and August
'in_week' => 'na', // e.g. yearly in week 3
'on' => 'à', // e.g. every day on Tuesday, Wednesday and Friday
'the_for_monthday' => 'o', // e.g. monthly on Tuesday the 1st
'the_for_weekday' => 'o', // e.g. monthly on the 4th Monday
'on the' => 'no', // e.g. every year on the 1st and 200th day
'of_the_month' => 'do mês', // e.g. every year on the 2nd or 3rd of the month
'every %count% years' => 'a cada %count% anos',
'every year' => 'anualmente',
'every_month_list' => 'sempre em', // e.g. every January, May and August
'every %count% months' => 'a cada %count% meses',
'every month' => 'mensalmente',
'every %count% weeks' => 'a cada %count% semanas',
'every week' => 'semanalmente',
'every %count% days' => 'a cada %count% dias',
'every day' => 'diariamente',
'last' => 'último', // e.g. 2nd last Friday
'days' => 'dias',
'day' => 'dia',
'weeks' => 'semanas',
'week' => 'semana',
// formats a number with a prefix e.g. every year on the 1st and 200th day
// negative numbers should be handled as in '5th to the last' or 'last'
//
// if has_negatives is true in the params, it is good form to add 'day' after
// each number, as in: 'every month on the 5th day or 2nd to the last day' or
// it may be confusing like 'every month on the 5th or 2nd to the last day'
'ordinal_number' => function ($str, $params) {
$number = $params['number'];
$abbreviation = $number.'°';
$isNegative = $number < 0;
if ($isNegative) {
$abbreviation = $abbreviation.' último';
}
$suffix = '';
if (!empty($params['has_negatives'])) {
$suffix .= ' dia';
}
return $abbreviation . $suffix;
},
);

View File

@@ -0,0 +1,100 @@
<?php
// sunday first as date('w') is zero-based on sunday
$days = array(
'Söndag',
'Måndag',
'Tisdag',
'Onsdag',
'Torsdag',
'Fredag',
'Lördag',
);
$months = array(
'Januari',
'Februari',
'Mars',
'April',
'Maj',
'Juni',
'Juli',
'Augusti',
'September',
'Oktober',
'November',
'December',
);
return array(
'Unable to fully convert this rrule to text.' => 'Kunde inte konvertera denna rrule till text.',
'for %count% times' => '%count% gånger',
'for one time' => 'en gång',
'(~ approximate)' => '(~ ungefärlig)',
'until %date%' => 't.o.m. %date%', // e.g. every year until July 4, 2014
'day_date' => function ($str, $params) use ($days, $months) { // outputs a day date, e.g. July 4, 2014
return $months[date('n', $params['date']) - 1] . ' '. date('j, Y', $params['date']);
},
'day_month' => function ($str, $params) use ($days, $months) { // outputs a day month, e.g. July 4
return $months[$params['month'] - 1].' '.$params['day'];
},
'day_names' => $days,
'month_names' => $months,
'and' => 'och',
'or' => 'eller',
'in_month' => 'i', // e.g. weekly in January, May and August
'in_week' => 'i', // e.g. yearly in week 3
'on' => 'på', // e.g. every day on Tuesday, Wednesday and Friday
'the_for_monthday' => 'den', // e.g. monthly on Tuesday the 1st
'the_for_weekday' => 'den', // e.g. monthly on the 4th Monday
'on the' => 'på den', // e.g. every year on the 1st and 200th day
'of_the_month' => 'i månaden', // e.g. every year on the 2nd or 3rd of the month
'every %count% years' => 'varje %count% år',
'every year' => 'årligen',
'every_month_list' => 'varje', // e.g. every January, May and August
'every %count% months' => 'varje %count% månad',
'every month' => 'månadsvis',
'every %count% weeks' => 'varje %count% vecka',
'every week' => 'veckovis',
'every %count% days' => 'varje %count% dag',
'every day' => 'dagligen',
'last' => 'sista', // e.g. 2nd last Friday
'days' => 'dagar',
'day' => 'dag',
'weeks' => 'veckor',
'week' => 'vecka',
// formats a number with a prefix e.g. every year on the 1st and 200th day
// negative numbers should be handled as in '5th to the last' or 'last'
//
// if has_negatives is true in the params, it is good form to add 'day' after
// each number, as in: 'every month on the 5th day or 2nd to the last day' or
// it may be confusing like 'every month on the 5th or 2nd to the last day'
'ordinal_number' => function ($str, $params) {
$number = $params['number'];
$ends = array(':e', ':a', ':a', ':e', ':e', ':e', ':e', ':e', ':e', ':e');
$suffix = '';
$isNegative = $number < 0;
if ($number == -1) {
$abbreviation = 'last';
} else {
if ($isNegative) {
$number = abs($number);
$suffix = ' to the last';
}
if (($number % 100) >= 11 && ($number % 100) <= 13) {
$abbreviation = $number.'th';
} else {
$abbreviation = $number.$ends[$number % 10];
}
}
if (!empty($params['has_negatives'])) {
$suffix .= ' dag';
}
return $abbreviation . $suffix;
},
);

View File

@@ -0,0 +1,100 @@
<?php
// sunday first as date('w') is zero-based on sunday
$days = array(
'Pazar',
'Pazartesi',
'Salı',
'Çarşamba',
'Perşembe',
'Cuma',
'Cumartesi',
);
$months = array(
'Ocak',
'Şubat',
'Mart',
'Nisan',
'Mayıs',
'Haziran',
'Temmuz',
'Ağustos',
'Eylül',
'Ekim',
'Kasım',
'Aralık',
);
return array(
'Unable to fully convert this rrule to text.' => 'Bu rrule tam metne dönüştürülemiyor.',
'for %count% times' => '%count% kez',
'for one time' => 'bir kere',
'(~ approximate)' => '(~ yaklaşık)',
'until %date%' => 'kadar %date%', // e.g. 4 Temmuz 2014 e kadar her yıl
'day_date' => function ($str, $params) use ($days, $months) { // tarih çıktıları, e.g. Temmuz 4, 2014
return $months[date('n', $params['date']) - 1] . ' '. date('j, Y', $params['date']);
},
'day_month' => function ($str, $params) use ($days, $months) { // outputs a day month, e.g. July 4
return $months[$params['month'] - 1].' '.$params['day'];
},
'day_names' => $days,
'month_names' => $months,
'and' => 've',
'or' => 'veya',
'in_month' => 'içinde', // e.g. Ocak, Mayıs ve Ağustos'ta haftalık
'in_week' => 'içinde', // e.g. yıllık haftada 3
'on' => 'on', // e.g. her Salı, Çarşamba ve Cuma günü
'the_for_monthday' => 'the', // e.g. monthly on Tuesday the 1st
'the_for_weekday' => 'the', // e.g. monthly on the 4th Monday
'on the' => 'üzerinde', // e.g. her yıl 1. ve 200. günde
'of_the_month' => 'ayın', // e.g. her yıl 2. ve 3. ayın
'every %count% years' => 'every %count% years',
'every year' => 'yıllık',
'every_month_list' => 'her', // e.g. her Ocak, Mayıs ve Ağustos
'every %count% months' => 'her %count% ay',
'every month' => 'aylık',
'every %count% weeks' => 'her %count% hafta',
'every week' => 'haftalık',
'every %count% days' => 'her %count% gün',
'every day' => 'günlük',
'last' => 'son', // e.g. 2nd last Friday
'days' => 'günler',
'day' => 'gün',
'weeks' => 'haftalar',
'week' => 'hafta',
// formats a number with a prefix e.g. every year on the 1st and 200th day
// negative numbers should be handled as in '5th to the last' or 'last'
//
// if has_negatives is true in the params, it is good form to add 'day' after
// each number, as in: 'every month on the 5th day or 2nd to the last day' or
// it may be confusing like 'every month on the 5th or 2nd to the last day'
'ordinal_number' => function ($str, $params) {
$number = $params['number'];
$ends = array('th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th');
$suffix = '';
$isNegative = $number < 0;
if ($number == -1) {
$abbreviation = 'son';
} else {
if ($isNegative) {
$number = abs($number);
$suffix = ' sonuna kadar';
}
if (($number % 100) >= 11 && ($number % 100) <= 13) {
$abbreviation = $number.'th';
} else {
$abbreviation = $number.$ends[$number % 10];
}
}
if (!empty($params['has_negatives'])) {
$suffix .= ' gün';
}
return $abbreviation . $suffix;
},
);