0

I have two fields field_start_date and field_end_date and under manage
display section
I have set the field format for
field_start_date as F d
field_end_date as - d Y
I need to combine the two fields and display it as follows
suppose field_start_date value is >>> 10th Feb 2019 &
field_end_date value is >>> 20th Feb 2019
So the output should be
February 03 - 20, 2019

But I have two other different scenario,
1) Month is different but year would be same, in that case I need to
display it as February 03 - March 20, 2019 2) Month and Year both is different , in that case I would need to display it as
February 03,2019 - March 20,2020
The suitable module which I found was
Date Range Formatter :-
https://www.drupal.org/project/date_range_formatter
which includes single field which has both start date and end date and it
has provided defaultsettings as shown in the code below along with
formatter logic altered inside viewElements

namespace Drupal\date_range_formatter\Plugin\Field\FieldFormatter;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\datetime\Plugin\Field\FieldFormatter\DateTimeCustomFormatter;
use Drupal\datetime_range\DateTimeRangeTrait;

/**
 * Plugin implementation of the 'Custom' formatter for 'daterange' fields.
 *
 * This formatter renders the data range as plain text, with a fully
 * configurable date format using the PHP date syntax and separator.
 *
 * @FieldFormatter(
 *   id = "date_range_without_time",
 *   label = @Translation("Date range (without time)"),
 *   field_types = {
 *     "daterange"
 *   }
 * )
 */
class DateRangeFormatterRangeFormatter extends DateTimeCustomFormatter {

  use DateTimeRangeTrait;

  /**
   * {@inheritdoc}
   */
  public static function defaultSettings() {
    return [
      'separator' => '-',
      'single' => 'd F Y',
      'single_all_day' => 'd F Y',
      'one_day' => 'd F Y',
      'one_month' => 'd - {d} F Y',
      'several_months' => 'd F - {d} {F} Y',
      'several_years' => 'd F Y - {d} {F} {Y}',
    ] + parent::defaultSettings();
  }

  /**
   * {@inheritdoc}
   */
  public function viewElements(FieldItemListInterface $items, $langcode) {
    $elements = [];

    foreach ($items as $delta => $item) {
      if (!empty($item->start_date) && !empty($item->end_date)) {
        /** @var \Drupal\Core\Datetime\DrupalDateTime $start_date */
        $start_date = $item->start_date->getTimestamp();
        /** @var \Drupal\Core\Datetime\DrupalDateTime $end_date */
        $end_date = $item->end_date->getTimestamp();
        if ($start_date !== $end_date) {
          $format = $this->getSetting('several_years');
          if (date('Y', $start_date) === date('Y', $end_date)) {
            $format = $this->getSetting('several_months');
          }
          if (date('m.Y', $start_date) === date('m.Y', $end_date)) {
            $format = $this->getSetting('one_month');
          }
          if (date('d.m.Y', $start_date) === date('d.m.Y', $end_date)) {
            $format = $this->getSetting('one_day');
          }

          $date_str = format_date($start_date, 'custom', preg_replace('/\{([a-zA-Z])\}/', '{\\\$1}', t($format)));
          $matches = array();
          if (preg_match_all('/\{([a-zA-Z])\}/', $date_str, $matches)) {
            foreach ($matches[1] as $match) {
              $date_str = preg_replace('/\{' . $match . '\}/', format_date($end_date, 'custom', $match), $date_str);
            }
          }
          $elements[$delta] = ['#markup' => '<span class="date-display-range">' . $date_str . '</span>',];

        }
        else {
          $elements[$delta] = ['#markup' => date($this->getSetting('one_day'), $start_date)];
        }
      }
    }
    return $elements;
  }

  /**
   * {@inheritdoc}
   */
  public function settingsForm(array $form, FormStateInterface $form_state) {
    $form = parent::settingsForm($form, $form_state);
    unset($form['date_format']);
    $form['single'] = [
      '#type' => 'textfield',
      '#title' => t('Date format for single date'),
      '#default_value' => $this->getSetting('single') ? : 'd F Y',
    ];
    $form['single_all_day'] = [
      '#type' => 'textfield',
      '#title' => t('Date format for the single date if the date is "all day"'),
      '#default_value' => $this->getSetting('single_all_day') ? : 'd F Y',
    ];
    $form['one_day'] = [
      '#type' => 'textfield',
      '#title' => t('Date format for the single day date range'),
      '#default_value' => $this->getSetting('one_day') ? : 'd F Y',
    ];
    $form['one_month'] = [
      '#type' => 'textfield',
      '#title' => t('Date format for the single month date range'),
      '#default_value' => $this->getSetting('one_month') ? : 'd - {d} F Y',
    ];
    $form['several_months'] = [
      '#type' => 'textfield',
      '#title' => t('Date format for the single year date range'),
      '#default_value' => $this->getSetting('several_months') ? : 'd F - {d} {F} Y',
    ];
    $form['several_years'] = [
      '#type' => 'textfield',
      '#title' => t('Date format for multiple years date range'),
      '#default_value' => $this->getSetting('several_years') ? : 'd F Y - {d} {F} {Y}',
    ];
    $form['help'] = [
      '#type' => 'markup',
      '#markup' => t('A user-defined date format. See the <a href="@url">PHP manual</a> for available options.', ['@url' => 'http://php.net/manual/function.date.php']) .
        '<br />' . t('Use letters in braces for end date elements, for example, {d} means the day of the end date.') .
        '<br />' . t('These format values are translated, for example, t("d F Y") instead of "d F Y" will be used as the actual date format.'),
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function settingsSummary() {
    $summary = parent::settingsSummary();
    $summary[] = $this->t('Display date range using formats: @single, @single_all_day, @one_day, @one_month, @several_months, @several_years',
        array(
          '@single' => $this->getSetting('single') ? : 'd F Y',
          '@single_all_day' => $this->getSetting('single_all_day') ? : 'd F Y',
          '@one_day' => $this->getSetting('one_day') ? : 'd F Y',
          '@one_month' => $this->getSetting('one_month') ? : 'd - {d} F Y',
          '@several_months' => $this->getSetting('several_months') ? : 'd F - {d} {F} Y',
          '@several_years' => $this->getSetting('several_years') ? : 'd F Y - {d} {F} {Y}',
        )
      );

    return $summary;
  }

}

What I am looking for is to alter existing 2 fields field_start_date and field_end_date before rendering and use the logic given above.
I thought of hook_preprocess_field($variables,$hook) but it only works per field and I probably don't have any option to alter field_end_date value
based on field_start_date value.
Is there any way to alter default date format of two fields field_start_date and field_end_date conditionally based on field value and set a format accordingly? I am looking into the following hook to see if that can help https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Entity!entity.api.php/function/hook_entity_display_build_alter/8.2.x

  • I'm not sure what you are asking. Of course you can keep the two existing fields and program the output in an entity view hook, but ideally you would use a date range field and a field formatter. This is a much cleaner solution. – 4k4 Feb 10 at 16:02
  • Hi , yes I found your answer here : drupal.stackexchange.com/questions/194688/… and hence i realised it may affect performance and may cause caching issues. – harshal Feb 10 at 20:03
  • 1
    There wouldn't be any caching or performance issue in your case. This is not the problem, this is more about how fields are configured, stored and displayed and the date range field is more straightforward. Think about multivalues for example or if you need to change the field names. When you have the functionality in the field type and formatter you can configure all of this in UI. – 4k4 Feb 10 at 20:57
  • yes @4k4 got it, thanks for your expert advice.! – harshal Feb 11 at 6:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.