Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support ability to parse a negative BYDAY $day_number value such as -2MO, etc. #14

Closed
u01jmg3 opened this issue Apr 13, 2015 · 0 comments
Assignees

Comments

@u01jmg3
Copy link
Owner

u01jmg3 commented Apr 13, 2015

  • -1 is already supported as by using relative date formats we can use 'last day of ...'; however anything less than -1 won't work because penultimate, etc. is not offered with relative date formats

  • For example:
    • FREQ=MONTHLY;BYDAY=-2MO;COUNT=7
      • Every month on the 2nd last Monday for 7 times
    • FREQ=YEARLY;BYDAY=-3SU;BYMONTH=10
      • Every October on the 3rd last Sunday

  • The code below will convert a negative BYDAY value such as -2MO to its appropriate positive day ordinal such as the 'third'.
    • Will leave the implementation to someone else but this snippet should provide a start.
<?php
    /**
     * Get the number of days between a
     * start and end date
     *
     * @param  $days
     * @param  $start
     * @param  $end
     * @return integer
     */
    function numberOfDays($days, $start, $end){
        $w       = array(date('w', $start), date('w', $end));
        $oneWeek = 604800; // 7 * 24 * 60 * 60
        $x       = floor(($end - $start) / $oneWeek);
        $sum     = 0;

        for ($day = 0; $day < 7; ++$day) {
            if ($days & pow(2, $day)) {
                $sum += $x + ($w[0] > $w[1] ? $w[0] <= $day || $day <= $w[1] : $w[0] <= $day && $day <= $w[1]);
            }
        }

        return $sum;
    }

    /**
     * Convert a negative day ordinal to
     * its equivalent positive form
     *
     * @param  $dayNumber
     * @param  $weekday
     * @param  $timestamp
     * @return string
     */
    function convertDayOrdinalToPositive($dayNumber, $weekday, $timestamp){
        $dayNumber = empty($dayNumber) ? 1 : $dayNumber; // Returns 0 when no number defined in BYDAY

        $dayOrdinals = array(1 => 'first', 2 => 'second', 3 => 'third', 4 => 'fourth', 5 => 'fifth');

        // We only care about negative BYDAY values
        if ($dayNumber >= 1) {
            return $dayOrdinals[$dayNumber];
        }

        $timestamp = (is_object($timestamp)) ? $timestamp : \DateTime::createFromFormat('U', $timestamp);
        $start = strtotime('first day of ' . $timestamp->format('F Y H:i:s'));
        $end   = strtotime('last day of ' . $timestamp->format('F Y H:i:s'));

        // Used with pow(2, X) so pow(2, 4) is THURSDAY
        $weekdays = array('SU' => 0, 'MO' => 1, 'TU' => 2, 'WE' => 3, 'TH' => 4, 'FR' => 5, 'SA' => 6);

        $numberOfDays = numberOfDays(pow(2, $weekdays[$weekday]), $start, $end);

        // Create subset
        $dayOrdinals = array_slice($dayOrdinals, 0, $numberOfDays, true);

        //Reverse only the values
        $dayOrdinals = array_combine(array_keys($dayOrdinals), array_reverse(array_values($dayOrdinals)));

        return $dayOrdinals[$dayNumber * -1];
    }

    echo convertDayOrdinalToPositive(-2, 'MO', date_create('now'));
@u01jmg3 u01jmg3 changed the title Ability to parse a negative BYDAY $day_number value such as -2MO Support ability to parse a negative BYDAY $day_number value such as -2MO, etc. Apr 13, 2015
@u01jmg3 u01jmg3 self-assigned this Jan 10, 2017
@u01jmg3 u01jmg3 modified the milestone: v2.x.x Jan 10, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant