Projet

Général

Profil

Révision 599a39cd

Ajouté par Assos Assos il y a environ 3 ans

Weekly update of contrib modules

Voir les différences:

drupal7/sites/all/modules/date/date_repeat/date_repeat_calc.inc
1 1
<?php
2

  
2 3
/**
3 4
 * @file
4 5
 * Code to compute the dates that match an iCal RRULE.
......
53 54
  // Create a date object for the start and end dates.
54 55
  $start_date = new DateObject($start, $timezone);
55 56

  
56
  // Versions of PHP greater than PHP 5.3.5 require
57
  // that we set an explicit time when using date_modify()
58
  // or the time may not match the original value.
59
  // Adding this modifier gives us the same results in both older
60
  // and newer versions of PHP.
57
  // Versions of PHP greater than PHP 5.3.5 require that we set an explicit
58
  // time when using date_modify() or the time may not match the original value.
59
  // Adding this modifier gives us the same results in both older and newer
60
  // versions of PHP.
61 61
  $modify_time = ' ' . $start_date->format('g:ia');
62 62

  
63 63
  // If the rule has an UNTIL, see if that is earlier than the end date.
......
122 122
  }
123 123
  $rrule = date_repeat_adjust_rrule($rrule, $start_date);
124 124

  
125
  // The start date always goes into the results, whether or not it meets
126
  // the rules. RFC 2445 includes examples where the start date DOES NOT
127
  // meet the rules, but the expected results always include the start date.
125
  // The start date always goes into the results, whether or not it meets the
126
  // rules. RFC 2445 includes examples where the start date DOES NOT meet the
127
  // rules, but the expected results always include the start date.
128 128
  $days = array(date_format($start_date, DATE_FORMAT_DATETIME));
129 129

  
130 130
  // BYMONTHDAY will look for specific days of the month in one or more months.
131 131
  // This process is only valid when frequency is monthly or yearly.
132

  
133 132
  if (!empty($rrule['BYMONTHDAY'])) {
134 133
    $finished = FALSE;
135
    $current_day = clone($start_date);
134
    $current_day = clone $start_date;
136 135
    $direction_days = array();
137 136
    // Deconstruct the day in case it has a negative modifier.
138 137
    foreach ($rrule['BYMONTHDAY'] as $day) {
......
187 186
    }
188 187
  }
189 188

  
190
  // This is the simple fallback case, not looking for any BYDAY,
191
  // just repeating the start date. Because of imputed BYDAY above, this
192
  // will only test TRUE for a DAILY or less frequency (like HOURLY).
193

  
189
  // This is the simple fallback case, not looking for any BYDAY, just
190
  // repeating the start date. Because of imputed BYDAY above, this will only
191
  // test TRUE for a DAILY or less frequency (like HOURLY).
194 192
  elseif (empty($rrule['BYDAY'])) {
195 193
    // $current_day will keep track of where we are in the calculation.
196
    $current_day = clone($start_date);
194
    $current_day = clone $start_date;
197 195
    $finished = FALSE;
198 196
    $months = !empty($rrule['BYMONTH']) ? $rrule['BYMONTH'] : array();
199 197
    while (!$finished) {
......
204 202
  }
205 203

  
206 204
  else {
207

  
208
    // More complex searches for day names and criteria
209
    // like '-1SU' or '2TU,2TH', require that we interate through
210
    // the whole time period checking each BYDAY.
211

  
212
    // Create helper array to pull day names out of iCal day strings.
205
    // More complex searches for day names and criteria like '-1SU' or
206
    // '2TU,2TH', require that we interate through the whole time period
207
    // checking each BYDAY. Create helper array to pull day names out of iCal
208
    // day strings.
213 209
    $day_names = date_repeat_dow_day_options(FALSE);
214 210
    $days_of_week = array_keys($day_names);
215 211

  
216
    // Parse out information about the BYDAYs and separate them
217
    // depending on whether they have directional parameters like -1SU or 2TH.
212
    // Parse out information about the BYDAYs and separate them depending on
213
    // whether they have directional parameters like -1SU or 2TH.
218 214
    $month_days = array();
219 215
    $week_days = array();
220 216

  
......
223 219
    $week_start_rule = !empty($rrule['WKST']) ? trim($rrule['WKST']) : 'MO';
224 220
    $week_start_day = $day_names[$week_start_rule];
225 221

  
226
    // Make sure the week days array is sorted into week order,
227
    // we use the $ordered_keys to get the right values into the key
228
    // and force the array to that order. Needed later when we
229
    // iterate through each week looking for days so we don't
230
    // jump to the next week when we hit a day out of order.
222
    // Make sure the week days array is sorted into week order, we use the
223
    // $ordered_keys to get the right values into the key and force the array
224
    // to that order. Needed later when we iterate through each week looking
225
    // for days so we don't jump to the next week when we hit a day out of
226
    // order.
231 227
    $ordered = date_repeat_days_ordered($week_start_rule);
232 228
    $ordered_keys = array_flip($ordered);
233 229

  
......
236 232
      foreach ($rrule['BYMONTH'] as $month) {
237 233
        foreach ($rrule['BYDAY'] as $day) {
238 234
          preg_match("@(-)?([0-9]+)?([SU|MO|TU|WE|TH|FR|SA]{2})@", trim($day), $regs);
239
          // Convert parameters into full day name, count, and direction.
240
          // Add leading zero to first 9 months.
235
          // Convert parameters into full day name, count, and direction. Add
236
          // leading zero to first 9 months.
241 237
          if (!empty($regs[2])) {
242 238
            $direction_days[] = array(
243 239
              'day' => $day_names[$regs[3]],
......
271 267
    }
272 268
    ksort($week_days);
273 269

  
274
    // BYDAYs with parameters like -1SU (last Sun) or 2TH (second Thur)
275
    // need to be processed one month or year at a time.
270
    // BYDAYs with parameters like -1SU (last Sun) or 2TH (second Thur) need to
271
    // be processed one month or year at a time.
276 272
    if (!empty($direction_days) && in_array($rrule['FREQ'], array('MONTHLY', 'YEARLY'))) {
277 273
      $finished = FALSE;
278
      $current_day = clone($start_date);
274
      $current_day = clone $start_date;
279 275
      while (!$finished) {
280 276
        foreach ($direction_days as $day) {
281 277
          // Find the BYDAY date in the current month.
......
288 284
          date_repeat_add_dates($days, $current_day, $start_date, $end_date, $exceptions, $rrule);
289 285
        }
290 286
        $finished = date_repeat_is_finished($current_day, $days, $count, $end_date);
291
        // Reset to beginning of period before jumping to next period.
292
        // Needed especially when working with values like 'last Saturday'
293
        // to be sure we don't skip months like February.
287
        // Reset to beginning of period before jumping to next period. Needed
288
        // especially when working with values like 'last Saturday' to be sure
289
        // we don't skip months like February.
294 290
        $year = date_format($current_day, 'Y');
295 291
        $month = date_format($current_day, 'n');
296 292
        if ($rrule['FREQ'] == 'MONTHLY') {
......
304 300
      }
305 301
    }
306 302

  
307
    // For BYDAYs without parameters,like TU,TH (every Tues and Thur),
308
    // we look for every one of those days during the frequency period.
309
    // Iterate through periods of a WEEK, MONTH, or YEAR, checking for
310
    // the days of the week that match our criteria for each week in the
311
    // period, then jumping ahead to the next week, month, or year,
312
    // an INTERVAL at a time.
313

  
303
    // For BYDAYs without parameters,like TU,TH (every Tues and Thur), we look
304
    // for every one of those days during the frequency period. Iterate through
305
    // periods of a WEEK, MONTH, or YEAR, checking for the days of the week
306
    // that match our criteria for each week in the period, then jumping ahead
307
    // to the next week, month, or year, an INTERVAL at a time.
314 308
    if (!empty($week_days) &&
315 309
      in_array($rrule['FREQ'], array('MONTHLY', 'WEEKLY', 'YEARLY'))) {
316 310
      $finished = FALSE;
317
      $current_day = clone($start_date);
311
      $current_day = clone $start_date;
318 312
      $format = $rrule['FREQ'] == 'YEARLY' ? 'Y' : 'n';
319 313
      $current_period = date_format($current_day, $format);
320 314

  
321 315
      // Back up to the beginning of the week in case we are somewhere in the
322
      // middle of the possible week days, needed so we don't prematurely
323
      // jump to the next week. The date_repeat_add_dates() function will
324
      // keep dates outside the range from getting added.
316
      // middle of the possible week days, needed so we don't prematurely jump
317
      // to the next week. The date_repeat_add_dates() function will keep dates
318
      // outside the range from getting added.
325 319
      if (date_format($current_day, 'l') != $day_names[$day]) {
326 320
        date_modify($current_day, '-1 ' . $week_start_day . $modify_time);
327 321
      }
......
330 324
        while (!$period_finished) {
331 325
          $moved = FALSE;
332 326
          foreach ($week_days as $delta => $day) {
333
            // Find the next occurence of each day in this week, only add it
334
            // if we are still in the current month or year.
335
            // The date_repeat_add_dates function is insufficient
336
            // to test whether to include this date
337
            // if we are using a rule like 'every other month', so we must
338
            // explicitly test it here.
339

  
340
            // If we're already on the right day, don't jump or we
341
            // will prematurely move into the next week.
327
            // Find the next occurence of each day in this week, only add it if
328
            // we are still in the current month or year. The
329
            // date_repeat_add_dates() function is insufficient to test whether
330
            // to include this date if we are using a rule like 'every other
331
            // month', so we must explicitly test it here. If we're already on
332
            // the right day, don't jump or we will prematurely move into the
333
            // next week.
342 334
            if (date_format($current_day, 'l') != $day) {
343 335
              date_modify($current_day, '+1 ' . $day . $modify_time);
344 336
              $moved = TRUE;
......
349 341
          }
350 342
          $finished = date_repeat_is_finished($current_day, $days, $count, $end_date);
351 343

  
352
          // Make sure we don't get stuck in endless loop if the current
353
          // day never got changed above.
344
          // Make sure we don't get stuck in endless loop if the current day
345
          // never got changed above.
354 346
          if (!$moved) {
355 347
            date_modify($current_day, '+1 day' . $modify_time);
356 348
          }
357 349

  
358
          // If this is a WEEKLY frequency, stop after each week,
359
          // otherwise, stop when we've moved outside the current period.
360
          // Jump to the end of the week, then test the period.
350
          // If this is a WEEKLY frequency, stop after each week, otherwise,
351
          // stop when we've moved outside the current period. Jump to the end
352
          // of the week, then test the period.
361 353
          if ($finished || $rrule['FREQ'] == 'WEEKLY') {
362 354
            $period_finished = TRUE;
363 355
          }
......
370 362
          continue;
371 363
        }
372 364

  
373
        // We'll be at the end of a week, month, or year when
374
        // we get to this point in the code.
375

  
376
        // Go back to the beginning of this period before we jump, to
377
        // ensure we jump to the first day of the next period.
365
        // We'll be at the end of a week, month, or year when we get to this
366
        // point in the code. Go back to the beginning of this period before we
367
        // jump, to ensure we jump to the first day of the next period.
378 368
        switch ($rrule['FREQ']) {
379 369
          case 'WEEKLY':
380 370
            date_modify($current_day, '+1 ' . $week_start_day . $modify_time);
......
420 410

  
421 411
  // RFC 2445 says if no day or monthday is specified when creating repeats for
422 412
  // weeks, months, or years, impute the value from the start date.
423

  
424 413
  if (empty($rrule['BYDAY']) && $rrule['FREQ'] == 'WEEKLY') {
425 414
    $rrule['BYDAY'] = array(date_repeat_dow2day(date_format($start_date, 'w')));
426 415
  }
......
433 422
      $rrule['BYMONTH'] = array(date_format($start_date, 'n'));
434 423
    }
435 424
  }
436
  // If we are processing rules for period other than YEARLY or MONTHLY
437
  // and have BYDAYS like 2SU or -1SA, simplify them to SU or SA since the
438
  // position rules make no sense in other periods and just add complexity.
439

  
425
  // If we are processing rules for period other than YEARLY or MONTHLY and have
426
  // BYDAYS like 2SU or -1SA, simplify them to SU or SA since the position
427
  // rules make no sense in other periods and just add complexity.
440 428
  elseif (!empty($rrule['BYDAY']) && !in_array($rrule['FREQ'], array('MONTHLY', 'YEARLY'))) {
441 429
    foreach ($rrule['BYDAY'] as $delta => $by_day) {
442 430
      $rrule['BYDAY'][$delta] = substr($by_day, -2);
......
449 437
/**
450 438
 * Helper function to add found date to the $dates array.
451 439
 *
452
 * Check that the date to be added is between the start and end date
453
 * and that it is not in the $exceptions, nor already in the $days array,
454
 * and that it meets other criteria in the RRULE.
440
 * Check that the date to be added is between the start and end date and that it
441
 * is not in the $exceptions, nor already in the $days array, and that it meets
442
 * other criteria in the RRULE.
455 443
 */
456 444
function date_repeat_add_dates(&$days, $current_day, $start_date, $end_date, $exceptions, $rrule) {
457 445
  if (isset($rrule['COUNT']) && count($days) >= $rrule['COUNT']) {
......
525 513
 * Set a date object to a specific day of the month.
526 514
 *
527 515
 * Example,
528
 *   date_set_month_day($date, 'Sunday', 2, '-')
529
 *   will reset $date to the second to last Sunday in the month.
530
 *   If $day is empty, will set to the number of days from the
531
 *   beginning or end of the month.
516
 *   date_set_month_day($date, 'Sunday', 2, '-') will reset $date to the second
517
 *   to last Sunday in the month. If $day is empty, will set to the number of
518
 *   days from the beginning or end of the month.
532 519
 */
533 520
function date_repeat_set_month_day($date_in, $day, $count = 1, $direction = '+', $timezone = 'UTC', $modify_time = '') {
534 521
  if (is_object($date_in)) {
535 522
    $current_month = date_format($date_in, 'n');
536 523

  
537
    // Reset to the start of the month.
538
    // We should be able to do this with date_date_set(), but
539
    // for some reason the date occasionally gets confused if run
540
    // through this function multiple times. It seems to work
541
    // reliably if we create a new object each time.
524
    // Reset to the start of the month. We should be able to do this with
525
    // date_date_set(), but for some reason the date occasionally gets confused
526
    // if run through this function multiple times. It seems to work reliably
527
    // if we create a new object each time.
542 528
    $datetime = date_format($date_in, DATE_FORMAT_DATETIME);
543 529
    $datetime = substr_replace($datetime, '01', 8, 2);
544 530
    $date = new DateObject($datetime, $timezone);
......
547 533
      date_modify($date, '+1 month' . $modify_time);
548 534
    }
549 535
    else {
550
      // For positive search, back up one day to get outside the
551
      // current month, so we can catch the first of the month.
536
      // For positive search, back up one day to get outside the current month,
537
      // so we can catch the first of the month.
552 538
      date_modify($date, '-1 day' . $modify_time);
553 539
    }
554 540

  
......
556 542
      date_modify($date, $direction . $count . ' days' . $modify_time);
557 543
    }
558 544
    else {
559
      // Use the English text for order, like First Sunday
560
      // instead of +1 Sunday to overcome PHP5 bug, (see #369020).
545
      // Use the English text for order, like First Sunday instead of +1 Sunday
546
      // to overcome PHP5 bug, (see #369020).
561 547
      $order = date_order();
562 548
      $step = $count <= 5 ? $order[$direction . $count] : $count;
563 549
      date_modify($date, $step . ' ' . $day . $modify_time);
......
575 561
 * Set a date object to a specific day of the year.
576 562
 *
577 563
 * Example,
578
 *   date_set_year_day($date, 'Sunday', 2, '-')
579
 *   will reset $date to the second to last Sunday in the year.
580
 *   If $day is empty, will set to the number of days from the
581
 *   beginning or end of the year.
564
 *   date_set_year_day($date, 'Sunday', 2, '-') will reset $date to the second
565
 *   to last Sunday in the year. If $day is empty, will set to the number of
566
 *   days from the beginning or end of the year.
582 567
 */
583 568
function date_repeat_set_year_day($date_in, $month, $day, $count = 1, $direction = '+', $timezone = 'UTC', $modify_time = '') {
584 569
  if (is_object($date_in)) {
585 570
    $current_year = date_format($date_in, 'Y');
586 571

  
587
    // Reset to the start of the month.
588
    // See note above.
572
    // Reset to the start of the month. See note above.
589 573
    $datetime = date_format($date_in, DATE_FORMAT_DATETIME);
590 574
    $month_key = isset($month) ? $month : '01';
591 575
    $datetime = substr_replace($datetime, $month_key . '-01', 5, 5);
......
597 581
        $modifier = '+1 month';
598 582
      }
599 583
      else {
600
        // For positive search, back up one day to get outside the
601
        // current month, so we can catch the first of the month.
584
        // For positive search, back up one day to get outside the current
585
        // month, so we can catch the first of the month.
602 586
        $modifier = '-1 day';
603 587
      }
604 588
    }
......
608 592
        $modifier = '+1 year';
609 593
      }
610 594
      else {
611
        // For positive search, back up one day to get outside the
612
        // current year, so we can catch the first of the year.
595
        // For positive search, back up one day to get outside the current
596
        // year, so we can catch the first of the year.
613 597
        $modifier = '-1 day';
614 598
      }
615 599
    }
......
620 604
      date_modify($date, $direction . $count . ' days' . $modify_time);
621 605
    }
622 606
    else {
623
      // Use the English text for order, like First Sunday
624
      // instead of +1 Sunday to overcome PHP5 bug, (see #369020).
607
      // Use the English text for order, like First Sunday instead of +1 Sunday
608
      // to overcome PHP5 bug, (see #369020).
625 609
      $order = date_order();
626 610
      $step = $count <= 5 ? $order[$direction . $count] : $count;
627 611
      date_modify($date, $step . ' ' . $day . $modify_time);

Formats disponibles : Unified diff