You are here

public static function SmartDateTrait::formatSmartDate in Smart Date 8

Same name and namespace in other branches
  1. 8.2 src/SmartDateTrait.php \Drupal\smart_date\SmartDateTrait::formatSmartDate()
  2. 3.x src/SmartDateTrait.php \Drupal\smart_date\SmartDateTrait::formatSmartDate()
  3. 3.0.x src/SmartDateTrait.php \Drupal\smart_date\SmartDateTrait::formatSmartDate()
  4. 3.1.x src/SmartDateTrait.php \Drupal\smart_date\SmartDateTrait::formatSmartDate()
  5. 3.2.x src/SmartDateTrait.php \Drupal\smart_date\SmartDateTrait::formatSmartDate()
  6. 3.3.x src/SmartDateTrait.php \Drupal\smart_date\SmartDateTrait::formatSmartDate()
  7. 3.4.x src/SmartDateTrait.php \Drupal\smart_date\SmartDateTrait::formatSmartDate()

Creates a formatted date value as a string.

Parameters

object $start_ts: A timestamp.

object $end_ts: A timestamp.

array $settings: The formatter settings.

array $timezone: An optional timezone override.

Return value

string A formatted date string using the chosen format.

4 calls to SmartDateTrait::formatSmartDate()
SmartDateDefaultFormatter::formatDate in src/Plugin/Field/FieldFormatter/SmartDateDefaultFormatter.php
Creates a formatted date value as a string.
SmartDateDefaultFormatter::getAvailableSmartDateFormatOptions in src/Plugin/Field/FieldFormatter/SmartDateDefaultFormatter.php
Get an array of available Smart Date format options.
SmartDateTrait::viewElements in src/SmartDateTrait.php
smart_date_tokens in ./smart_date.tokens.inc
Implements hook_tokens().

File

src/SmartDateTrait.php, line 71

Class

SmartDateTrait
Provides friendly methods for smart date range.

Namespace

Drupal\smart_date

Code

public static function formatSmartDate($start_ts, $end_ts, $settings, $timezone = NULL, $return_type = '') {

  // Don't need to reduce dates unless conditions are met.
  $date_reduce = FALSE;

  // Apply date format from the display config.
  if ($settings['date_format']) {
    $range['start']['date'] = \Drupal::service('date.formatter')
      ->format($start_ts, '', $settings['date_format'], $timezone);
    $range['end']['date'] = \Drupal::service('date.formatter')
      ->format($end_ts, '', $settings['date_format'], $timezone);
    if ($range['start']['date'] == $range['end']['date']) {
      if ($settings['date_first']) {
        unset($range['end']['date']);
      }
      else {
        unset($range['start']['date']);
      }
    }
    else {

      // If a date range and reduce is set, reduce duplication in the dates.
      $date_reduce = $settings['ampm_reduce'];

      // Don't reduce am/pm if spanning more than one day.
      $settings['ampm_reduce'] = FALSE;
    }
  }

  // If not rendering times, we can stop here.
  if (!$settings['time_format']) {
    return static::rangeFormat($range, $settings, $return_type);
  }
  $temp_start = date('H:i', $start_ts);
  $temp_end = date('H:i', $end_ts);

  // If one of the dates are missing, they must have been the same.
  if (!isset($range['start']['date']) || !isset($range['end']['date'])) {

    // check for zero duration
    if ($temp_start == $temp_end) {
      if ($settings['date_first']) {
        $range['start']['time'] = static::timeFormat($end_ts, $settings, $timezone);
      }
      else {
        $range['end']['time'] = static::timeFormat($end_ts, $settings, $timezone);
      }
      return static::rangeFormat($range, $settings, $return_type);
    }

    // If the conditions that make this necessary aren't met, set to skip.
    if (!$settings['ampm_reduce'] || date('a', $start_ts) != date('a', $end_ts)) {
      $settings['ampm_reduce'] = FALSE;
    }
  }

  // Check for an all-day range.
  if ($temp_start == '00:00' && $temp_end == '23:59') {
    if ($settings['allday_label']) {
      if ($settings['date_first'] && isset($range['end']['date']) || empty($range['start']['date'])) {
        $range['end']['time'] = $settings['allday_label'];
      }
      else {
        $range['start']['time'] = $settings['allday_label'];
      }
    }
    if ($date_reduce) {

      // Reduce duplication in date only range
      // First attempt has the following limitations, to reduce complexity:
      // * Day ranges only work either d or j, and no other day tokens
      // * Not able to handle S token unless adjacent to day
      // * Month, day ranges only work if year at start or end
      $start = getdate($start_ts);
      $end = getdate($end_ts);

      // If the years are different, no deduplication necessary.
      if ($start['year'] == $end['year']) {
        $valid_days = [];
        $invalid_days = [];

        // Check for workable day tokens.
        preg_match_all('/[dj]/', $settings['date_format'], $valid_days, PREG_OFFSET_CAPTURE);

        // Check for challenging day tokens.
        preg_match_all('/[DNlwz]/', $settings['date_format'], $invalid_days, PREG_OFFSET_CAPTURE);

        // TODO: add handling for S token
        // If specific conditions are met format as a range within the month.
        if ($start['month'] == $end['month'] && count($valid_days[0]) == 1 && count($invalid_days[0]) == 0) {

          // Split the date string at the valid day token.
          $day_loc = $valid_days[0][0][1];

          // Don't remove the S token from the start if present.
          if ($s_loc = strpos($settings['date_format'], 'S', $day_loc)) {
            $offset = 1 + $s_loc - $day_loc;
          }
          else {
            $offset = 1;
          }
          $start_format = substr($settings['date_format'], 0, $day_loc + $offset);
          $end_format = substr($settings['date_format'], $day_loc);
          $range['start']['date'] = \Drupal::service('date.formatter')
            ->format($start_ts, '', $start_format, $timezone);
          $range['end']['date'] = \Drupal::service('date.formatter')
            ->format($end_ts, '', $end_format, $timezone);
        }
        else {
          if (strpos($settings['date_format'], 'Y') === 0) {
            $year_pos = 0;
          }
          elseif (strpos($settings['date_format'], 'Y') == strlen($settings['date_format']) - 1) {
            $year_pos = -1;
          }
          else {

            // Too complicated if year is in the middle.
            $year_pos = FALSE;
          }
          if ($year_pos !== FALSE) {
            $valid_tokens = [];

            // Check for workable day or month tokens.
            preg_match_all('/[djDNlwzSFmMn]/', $settings['date_format'], $valid_tokens, PREG_OFFSET_CAPTURE);
            if ($valid_tokens) {
              if ($year_pos == 0) {

                // Year is at the beginning, so change the end to start at the
                // first valid token after it.
                $first_token = $valid_tokens[0][0];
                $end_format = substr($settings['date_format'], $first_token[1]);
                $range['end']['date'] = \Drupal::service('date.formatter')
                  ->format($end_ts, '', $end_format, $timezone);
              }
              else {
                $last_token = array_pop($valid_tokens[0]);
                $start_format = substr($settings['date_format'], 0, $last_token[1] + 1);
                $range['start']['date'] = \Drupal::service('date.formatter')
                  ->format($start_ts, '', $start_format, $timezone);
              }
            }
          }
        }
      }
    }
    return static::rangeFormat($range, $settings, $return_type);
  }
  $range['start']['time'] = static::timeFormat($start_ts, $settings, $timezone, TRUE);
  $range['end']['time'] = static::timeFormat($end_ts, $settings, $timezone);
  return static::rangeFormat($range, $settings, $return_type);
}