diff --git a/core/modules/datetime/config/schema/datetime.schema.yml b/core/modules/datetime/config/schema/datetime.schema.yml
index 406a2fd..58c690f 100644
--- a/core/modules/datetime/config/schema/datetime.schema.yml
+++ b/core/modules/datetime/config/schema/datetime.schema.yml
@@ -7,6 +7,12 @@ field.storage_settings.datetime:
     datetime_type:
       type: string
       label: 'Date type'
+    enddate_get:
+      type: string
+      label: 'Collect end date'
+    enddate_require:
+      type: string
+      label: 'Require end date'
 
 field.field_settings.datetime:
   type: mapping
diff --git a/core/modules/datetime/datetime.install b/core/modules/datetime/datetime.install
new file mode 100644
index 0000000..9ee7343
--- /dev/null
+++ b/core/modules/datetime/datetime.install
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the datetime module.
+ */
+
+use Drupal\Core\Database\Database;
+
+/**
+ * Add 'enddate_get' field to 'field.storage_settings.datetime'.
+ *
+ * Add 'value2' field.
+ */
+function datetime_update_8001() {
+
+  // Update field storage for existing datetime fields.
+  $entity_manager = \Drupal::entityManager();
+  $entity_manager->useCaches(FALSE);
+  $change_list = array();
+
+  foreach ($entity_manager->getDefinitions() as $entity_type_id => $entity_type) {
+
+    if ($entity_manager->getStorage($entity_type_id) instanceof \Drupal\Core\Entity\Schema\DynamicallyFieldableEntityStorageSchemaInterface) {
+      $field_changes = array();
+
+      $storage_definitions = $entity_manager->getFieldStorageDefinitions($entity_type_id);
+      $original_storage_definitions = $entity_manager->getLastInstalledFieldStorageDefinitions($entity_type_id);
+
+      // Detect updated field storage definitions.
+      foreach (array_intersect_key($storage_definitions, $original_storage_definitions) as $field_name => $storage_definition) {
+
+        if ($storage_definition->getType() == 'datetime') {
+          if ($entity_manager->getStorage($entity_type_id)->requiresFieldStorageSchemaChanges($storage_definition, $original_storage_definitions[$field_name])) {
+            $field_changes[$field_name] = TRUE;
+          }
+        }
+      }
+
+      if ($field_changes) {
+        $change_list[$entity_type_id] = array(
+          'field_storage_definitions' => $field_changes,
+          'base_table' => $entity_type->getBaseTable(),
+          'revision_table' => $entity_type->getRevisionTable(),
+        );
+      }
+    }
+  }
+
+  $field_spec = array(
+    'description' => 'The end date value.',
+    'type' => 'varchar',
+    'length' => 20,
+  );
+
+  $schema = Database::getConnection()->schema();
+
+  foreach ($change_list as $entity_type_id => $changes) {
+    foreach (array_keys($changes['field_storage_definitions']) as $field_name) {
+      $value_field_name = $field_name . '_value2';
+
+      $field_schema = array(
+        'fields' => array(
+          $value_field_name => array(
+            'description' => 'The end date value.',
+            'type' => 'varchar',
+            'length' => 20,
+          ),
+        ),
+        'indexes' => array(
+          $value_field_name => array($value_field_name),
+        ),
+      );
+
+      $index_spec = array($value_field_name);
+      $base_table = $changes['base_table'] . '__' . $field_name;
+      $schema->addField($base_table, $value_field_name, $field_spec);
+      $schema->addIndex($base_table, $value_field_name, $index_spec, $field_schema);
+
+      if ($changes['revision_table']) {
+        $revision_table = $changes['revision_table'] . '__' . $field_name;
+        $schema->addField($revision_table, $value_field_name, $field_spec);
+        $schema->addIndex($revision_table, $value_field_name, $index_spec, $field_schema);
+      }
+    }
+  }
+
+  // Update the storage configs.
+  if (!$field_storage_configs = \Drupal::entityManager()->getStorage('field_storage_config')->loadByProperties(array('type' => 'datetime'))) {
+    return;
+  }
+
+  foreach ($field_storage_configs as $field_storage) {
+    $field_storage->setSetting('enddate_get', FALSE);
+    $field_storage->setSetting('enddate_require', FALSE);
+    $field_storage->save();
+  }
+
+}
diff --git a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeCustomFormatter.php b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeCustomFormatter.php
index 5b53a8f..69e6612 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeCustomFormatter.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeCustomFormatter.php
@@ -53,6 +53,21 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
 
         $output = $this->formatDate($date);
       }
+      if (!empty($item->date2)) {
+        /** @var \Drupal\Core\Datetime\DrupalDateTime $date */
+        $date2 = $item->date2;
+
+        if ($this->getFieldSetting('datetime_type') == 'date') {
+          // A date without time will pick up the current time, use the default.
+          datetime_date_default_time($date2);
+        }
+        $this->setTimeZone($date2);
+
+        $output = $this->t('@date to @date2', [
+          '@date' => $this->formatDate($date),
+          '@date2' => $this->formatDate($date2),
+        ]);
+      }
       $elements[$delta] = [
         '#markup' => $output,
         '#cache' => [
diff --git a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeDefaultFormatter.php b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeDefaultFormatter.php
index 9b2735c..3b4d1eb 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeDefaultFormatter.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeDefaultFormatter.php
@@ -42,6 +42,8 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
     foreach ($items as $delta => $item) {
       $output = '';
       $iso_date = '';
+      $output2 = '';
+      $iso_date2 = '';
 
       if ($item->date) {
         /** @var \Drupal\Core\Datetime\DrupalDateTime $date */
@@ -58,8 +60,33 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
         $output = $this->formatDate($date);
       }
 
+      if ($item->date2 && $item->date != $item->date2) {
+        /** @var \Drupal\Core\Datetime\DrupalDateTime $date */
+        $date2 = $item->date2;
+        // Create the ISO date in Universal Time.
+        $iso_date2 = $date->format("Y-m-d\TH:i:s") . 'Z';
+
+        if ($this->getFieldSetting('datetime_type') == 'date') {
+          // A date without time will pick up the current time, use the default.
+          datetime_date_default_time($date2);
+        }
+        $this->setTimeZone($date2);
+
+        $output2 = $this->formatDate($date2);
+
+        // Check if start day == end day.
+        if ($this->getFieldSetting('datetime_type') == 'datetime') {
+          // TODO better logic to split the date and time based on the format.
+          $length = strspn($output2, $output);
+          if ($length) {
+
+            $output2 = substr($output2, $length - 1);
+          }
+        }
+      }
+
       // Display the date using theme datetime.
-      $elements[$delta] = array(
+      $elements[$delta][] = [
         '#cache' => [
           'contexts' => [
             'timezone',
@@ -68,12 +95,31 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
         '#theme' => 'time',
         '#text' => $output,
         '#html' => FALSE,
-        '#attributes' => array(
-          'datetime' => $iso_date,
-        ),
-      );
+        '#attributes' => ['datetime' => $iso_date],
+      ];
+
+      // Append on the end date.
+      if ($this->getFieldSetting('enddate_get') && !empty($output2)) {
+        $elements[$delta][] = [
+          '#markup' => $this->t(' to '),
+        ];
+        $elements[$delta][] = [
+          '#cache' => [
+            'contexts' => [
+              'timezone',
+            ],
+          ],
+          '#theme' => 'time',
+          '#text' => $output2,
+          '#html' => FALSE,
+          '#attributes' => ['datetime' => $iso_date2],
+        ];
+      }
       if (!empty($item->_attributes)) {
-        $elements[$delta]['#attributes'] += $item->_attributes;
+        $elements[$delta][0]['#attributes'] += $item->_attributes;
+        if ($this->getFieldSetting('enddate_get') && !empty($output2)) {
+          $elements[$delta][2]['#attributes'] += $item->_attributes;
+        }
         // Unset field item attributes since they have been included in the
         // formatter output and should not be rendered in the field template.
         unset($item->_attributes);
diff --git a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimePlainFormatter.php b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimePlainFormatter.php
index c22445e..8ba7df7 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimePlainFormatter.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimePlainFormatter.php
@@ -30,6 +30,7 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
 
     foreach ($items as $delta => $item) {
       $output = '';
+
       if (!empty($item->date)) {
         /** @var \Drupal\Core\Datetime\DrupalDateTime $date */
         $date = $item->date;
@@ -38,12 +39,25 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
           // A date without time will pick up the current time, use the default.
           datetime_date_default_time($date);
         }
-        else {
-        }
-        $this->setTimeZone($date);
 
         $output = $this->formatDate($date);
       }
+
+      if (!empty($item->date2)) {
+        /** @var \Drupal\Core\Datetime\DrupalDateTime $date */
+        $date2 = $item->date2;
+
+        if ($this->getFieldSetting('datetime_type') == 'date') {
+          // A date without time will pick up the current time, use the default.
+          datetime_date_default_time($date2);
+        }
+
+        $output = $this->t('@date to @date2', [
+          '@date' => $this->formatDate($date),
+          '@date2' => $this->formatDate($date2),
+        ]);
+      }
+
       $elements[$delta] = [
         '#cache' => [
           'contexts' => [
diff --git a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeTimeAgoFormatter.php b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeTimeAgoFormatter.php
index 786c49b..3767ace 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeTimeAgoFormatter.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeTimeAgoFormatter.php
@@ -113,8 +113,17 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
 
     foreach ($items as $delta => $item) {
       $date = $item->date;
+      $date2 = $item->date2;
       $output = [];
-      if (!empty($item->date)) {
+      // Base the timeago calculation off of the end date, if it exists.
+      if (!empty($item->date2)) {
+        if ($this->getFieldSetting('datetime_type') == 'date') {
+          // A date without time will pick up the current time, use the default.
+          datetime_date_default_time($date2);
+        }
+        $output = $this->formatDate($date2);
+      }
+      elseif (!empty($item->date)) {
         if ($this->getFieldSetting('datetime_type') == 'date') {
           // A date without time will pick up the current time, use the default.
           datetime_date_default_time($date);
diff --git a/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeFieldItemList.php b/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeFieldItemList.php
index 3998900..776de28 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeFieldItemList.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeFieldItemList.php
@@ -29,6 +29,11 @@ class DateTimeFieldItemList extends FieldItemList {
   const DEFAULT_VALUE_CUSTOM = 'relative';
 
   /**
+   * Defines the default value as relative.
+   */
+  const DEFAULT_VALUE_SAME = 'same';
+
+  /**
    * {@inheritdoc}
    */
   public function defaultValuesForm(array &$form, FormStateInterface $form_state) {
@@ -61,6 +66,39 @@ public function defaultValuesForm(array &$form, FormStateInterface $form_state)
         )
       );
 
+      if ($this->getFieldDefinition()->getSetting('enddate_get')) {
+        $element += array(
+          'default_date_type2' => array(
+            '#type' => 'select',
+            '#title' => t('Default end date'),
+            '#description' => t('Set a default value for this end date.'),
+            '#default_value' => isset($default_value[0]['default_date_type2']) ? $default_value[0]['default_date_type2'] : '',
+            '#options' => array(
+              static::DEFAULT_VALUE_SAME => t('Same as Default date'),
+              static::DEFAULT_VALUE_NOW => t('Current date'),
+              static::DEFAULT_VALUE_CUSTOM => t('Relative date'),
+            ),
+            '#empty_value' => '',
+            '#states' => array(
+              'visible' => array(
+                ':input[id="edit-default-value-input-default-date-type"]' => array('filled' => TRUE),
+              ),
+            ),
+          ),
+          'default_date2' => array(
+            '#type' => 'textfield',
+            '#title' => t('Relative default end value'),
+            '#description' => t("Describe a time by reference to the current day, like '+90 days' (90 days from the day the field is created) or '+1 Saturday' (the next Saturday). See <a href=\"@url\">@strtotime</a> for more details.", array('@strtotime' => 'strtotime', '@url' => 'http://www.php.net/manual/en/function.strtotime.php')),
+            '#default_value' => (isset($default_value[0]['default_date_type2']) && $default_value[0]['default_date_type2'] == static::DEFAULT_VALUE_CUSTOM) ? $default_value[0]['default_date2'] : '',
+            '#states' => array(
+              'visible' => array(
+                ':input[id="edit-default-value-input-default-date-type2"]' => array('value' => static::DEFAULT_VALUE_CUSTOM),
+              ),
+            ),
+          ),
+        );
+      }
+
       return $element;
     }
   }
@@ -75,6 +113,13 @@ public function defaultValuesFormValidate(array $element, array &$form, FormStat
         $form_state->setErrorByName('default_value_input][default_date', t('The relative date value entered is invalid.'));
       }
     }
+
+    if ($form_state->getValue(['default_value_input', 'default_date_type2']) == static::DEFAULT_VALUE_CUSTOM) {
+      $is_strtotime = @strtotime($form_state->getValue(array('default_value_input', 'default_date2')));
+      if (!$is_strtotime) {
+        $form_state->setErrorByName('default_value_input][default_date2', t('The relative date value entered is invalid.'));
+      }
+    }
   }
 
   /**
@@ -82,9 +127,18 @@ public function defaultValuesFormValidate(array $element, array &$form, FormStat
    */
   public function defaultValuesFormSubmit(array $element, array &$form, FormStateInterface $form_state) {
     if ($form_state->getValue(array('default_value_input', 'default_date_type'))) {
+      // Set the start date default to now.
       if ($form_state->getValue(array('default_value_input', 'default_date_type')) == static::DEFAULT_VALUE_NOW) {
         $form_state->setValueForElement($element['default_date'], static::DEFAULT_VALUE_NOW);
       }
+      // Set the end date default to now.
+      if ($form_state->getValue(array('default_value_input', 'default_date_type2')) == static::DEFAULT_VALUE_NOW) {
+        $form_state->setValueForElement($element['default_date2'], static::DEFAULT_VALUE_NOW);
+      }
+      // Set the end date default to same default as start date.
+      if ($form_state->getValue(array('default_value_input', 'default_date_type2')) == static::DEFAULT_VALUE_SAME) {
+        $form_state->setValueForElement($element['default_date2'], $form_state->getValue(array('default_value_input', 'default_date')));
+      }
       return array($form_state->getValue('default_value_input'));
     }
     return array();
@@ -96,6 +150,8 @@ public function defaultValuesFormSubmit(array $element, array &$form, FormStateI
   public static function processDefaultValue($default_value, FieldableEntityInterface $entity, FieldDefinitionInterface $definition) {
     $default_value = parent::processDefaultValue($default_value, $entity, $definition);
 
+    $return = array();
+
     if (isset($default_value[0]['default_date_type'])) {
       // A default value should be in the format and timezone used for date
       // storage.
@@ -105,14 +161,30 @@ public static function processDefaultValue($default_value, FieldableEntityInterf
       // We only provide a default value for the first item, as do all fields.
       // Otherwise, there is no way to clear out unwanted values on multiple value
       // fields.
-      $default_value =  array(
+      $return = array(
         array(
           'value' => $value,
           'date' => $date,
         )
       );
     }
-    return $default_value;
+
+    // Repeat for end date.
+    if ($definition->getSetting('enddate_get') && !empty($default_value[0]['default_date_type2'])) {
+      // A default value should be in the format and timezone used for date
+      // storage.
+      $date = new DrupalDateTime($default_value[0]['default_date2'], DATETIME_STORAGE_TIMEZONE);
+      $storage_format = $definition->getSetting('datetime_type2') == DateTimeItem::DATETIME_TYPE_DATE ? DATETIME_DATE_STORAGE_FORMAT : DATETIME_DATETIME_STORAGE_FORMAT;
+      $value = $date->format($storage_format);
+      // We only provide a default value for the first item, as do all fields.
+      // Otherwise, there is no way to clear out unwanted values on multiple value
+      // fields.
+      $return[0] += array(
+        'value2' => $value,
+        'date2' => $date,
+      );
+    }
+    return empty($return) ? $default_value : $return;
   }
 
 }
diff --git a/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php b/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php
index a7dd1c3..482589a 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php
@@ -33,6 +33,7 @@ class DateTimeItem extends FieldItemBase {
   public static function defaultStorageSettings() {
     return array(
       'datetime_type' => 'datetime',
+      'enddate_get' => FALSE,
     ) + parent::defaultStorageSettings();
   }
 
@@ -50,17 +51,32 @@ public static function defaultStorageSettings() {
    * {@inheritdoc}
    */
   public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
+    $has_end = $field_definition->getSetting('enddate_get');
+    $require_end = $field_definition->getSetting('enddate_require');
+
     $properties['value'] = DataDefinition::create('datetime_iso8601')
-      ->setLabel(t('Date value'))
+      ->setLabel($has_end ? t('Date value (start)') : t('Date value'))
       ->setRequired(TRUE);
 
     $properties['date'] = DataDefinition::create('any')
-      ->setLabel(t('Computed date'))
-      ->setDescription(t('The computed DateTime object.'))
+      ->setLabel($has_end ? t('Computed date (start)') : t('Computed date'))
+      ->setDescription(t('The computed start DateTime object.'))
       ->setComputed(TRUE)
       ->setClass('\Drupal\datetime\DateTimeComputed')
       ->setSetting('date source', 'value');
 
+    if ($has_end) {
+      $properties['value2'] = DataDefinition::create('datetime_iso8601')
+        ->setLabel(t('Date value (end)'))
+        ->setRequired($require_end);
+      $properties['date2'] = DataDefinition::create('any')
+        ->setLabel(t('Computed date (end)'))
+        ->setDescription(t('The computed end DateTime object.'))
+        ->setComputed(TRUE)
+        ->setClass('\Drupal\datetime\DateTimeComputed')
+        ->setSetting('date source', 'value2');
+    }
+
     return $properties;
   }
 
@@ -68,10 +84,10 @@ public static function propertyDefinitions(FieldStorageDefinitionInterface $fiel
    * {@inheritdoc}
    */
   public static function schema(FieldStorageDefinitionInterface $field_definition) {
-    return array(
+    $schema = array(
       'columns' => array(
         'value' => array(
-          'description' => 'The date value.',
+          'description' => 'The start date value.',
           'type' => 'varchar',
           'length' => 20,
         ),
@@ -80,6 +96,20 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
         'value' => array('value'),
       ),
     );
+
+    if ($field_definition->getSetting('enddate_get')) {
+      $schema['columns']['value2'] = [
+        'description' => 'The end date value.',
+        'type' => 'varchar',
+        'length' => 20,
+      ];
+      $schema['indexes'] = [
+        'value' => ['value', 'value2'],
+        'value2' => ['value2'],
+      ];
+    }
+
+    return $schema;
   }
 
   /**
@@ -94,8 +124,27 @@ public function storageSettingsForm(array &$form, FormStateInterface $form_state
       '#description' => t('Choose the type of date to create.'),
       '#default_value' => $this->getSetting('datetime_type'),
       '#options' => array(
+        static::DATETIME_TYPE_DATE => t('Date (all day)'),
         static::DATETIME_TYPE_DATETIME => t('Date and time'),
-        static::DATETIME_TYPE_DATE => t('Date only'),
+      ),
+    );
+
+    $element['enddate_get'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Collect an end date'),
+      '#default_value' => $this->getSetting('enddate_get'),
+      '#disabled' => $has_data,
+    );
+
+    $element['enddate_require'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Require an end date'),
+      '#default_value' => $this->getSetting('enddate_require'),
+      '#disabled' => $has_data,
+      '#states' => array(
+        'visible' => array(
+          ':input[id="edit-settings-enddate-get"]' => array('checked' => TRUE),
+        ),
       ),
     );
 
@@ -107,15 +156,22 @@ public function storageSettingsForm(array &$form, FormStateInterface $form_state
    */
   public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
     $type = $field_definition->getSetting('datetime_type');
+    $collect_end_date = $field_definition->getSetting('enddate_get');
 
     // Just pick a date in the past year. No guidance is provided by this Field
     // type.
     $timestamp = REQUEST_TIME - mt_rand(0, 86400*365);
     if ($type == DateTimeItem::DATETIME_TYPE_DATE) {
       $values['value'] = gmdate(DATETIME_DATE_STORAGE_FORMAT, $timestamp);
+      if ($collect_end_date) {
+        $values['value2'] = gmdate(DATETIME_DATE_STORAGE_FORMAT, $timestamp + 86400);
+      }
     }
     else {
       $values['value'] = gmdate(DATETIME_DATETIME_STORAGE_FORMAT, $timestamp);
+      if ($collect_end_date) {
+        $values['value2'] = gmdate(DATETIME_DATETIME_STORAGE_FORMAT, $timestamp + 86400);
+      }
     }
     return $values;
   }
@@ -136,6 +192,9 @@ public function onChange($property_name, $notify = TRUE) {
     if ($property_name == 'value') {
       $this->date = NULL;
     }
+    if ($property_name == 'value2') {
+      $this->date2 = NULL;
+    }
     parent::onChange($property_name, $notify);
   }
 
diff --git a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php
index 3e4a2ef..ee2a301 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php
@@ -83,6 +83,14 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
       '#date_part_order'=> $date_part_order,
     ) + $element['value'];
 
+    if ($this->getFieldSetting('enddate_get')) {
+      $element['value2'] = array(
+          '#type' => 'datelist',
+          '#date_increment' => $increment,
+          '#date_part_order'=> $date_part_order,
+        ) + $element['value'];
+    }
+
     return $element;
   }
 
diff --git a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDefaultWidget.php b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDefaultWidget.php
index 8d436a0..7be4a0d 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDefaultWidget.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDefaultWidget.php
@@ -89,6 +89,17 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
       '#date_time_callbacks' => array(),
     );
 
+    if ($this->getFieldSetting('enddate_get')) {
+      $element['value2'] += array(
+        '#date_date_format'=>  $date_format,
+        '#date_date_element' => $date_type,
+        '#date_date_callbacks' => array(),
+        '#date_time_format' => $time_format,
+        '#date_time_element' => $time_type,
+        '#date_time_callbacks' => array(),
+      );
+    }
+
     return $element;
   }
 
diff --git a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeWidgetBase.php b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeWidgetBase.php
index dfe750e..f3afe5a 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeWidgetBase.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeWidgetBase.php
@@ -52,6 +52,32 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
       $element['value']['#default_value'] = $date;
     }
 
+    if ($this->getFieldSetting('enddate_get')) {
+      $element['value']['#title'] = t('Start date');
+
+      $element['value2'] = array(
+        '#title' => t('End date'),
+        '#type' => 'datetime',
+        '#default_value' => NULL,
+        '#date_increment' => 1,
+        '#date_timezone' => drupal_get_user_timezone(),
+        '#required' => $element['#required'],
+      );
+
+      if ($items[$delta]->date2) {
+        $date = $items[$delta]->date2;
+        // The date was created and verified during field_load(), so it is safe to
+        // use without further inspection.
+        if ($this->getFieldSetting('datetime_type') == DateTimeItem::DATETIME_TYPE_DATE) {
+          // A date without time will pick up the current time, use the default
+          // time.
+          datetime_date_default_time($date);
+        }
+        $date->setTimezone(new \DateTimeZone($element['value2']['#date_timezone']));
+        $element['value2']['#default_value'] = $date;
+      }
+    }
+
     return $element;
   }
 
@@ -62,9 +88,22 @@ public function massageFormValues(array $values, array $form, FormStateInterface
     // The widget form element type has transformed the value to a
     // DrupalDateTime object at this point. We need to convert it back to the
     // storage timezone and format.
+    $properties = array('value');
+    if ($this->getFieldSetting('enddate_get')) {
+      $properties[] = 'value2';
+    }
     foreach ($values as &$item) {
-      if (!empty($item['value']) && $item['value'] instanceof DrupalDateTime) {
-        $date = $item['value'];
+      foreach ($properties as $property) {
+        if (!empty($item[$property]) && $item[$property] instanceof DrupalDateTime) {
+          $this->massageDateProperty($item, $property);
+        }
+      }
+    }
+    return $values;
+  }
+
+  public function massageDateProperty(&$item, $property) {
+    $date = $item[$property];
         switch ($this->getFieldSetting('datetime_type')) {
           case DateTimeItem::DATETIME_TYPE_DATE:
             // If this is a date-only field, set it to the default time so the
@@ -79,10 +118,7 @@ public function massageFormValues(array $values, array $form, FormStateInterface
         }
         // Adjust the date for storage.
         $date->setTimezone(new \DateTimezone(DATETIME_STORAGE_TIMEZONE));
-        $item['value'] = $date->format($format);
-      }
-    }
-    return $values;
-  }
+    $item[$property] = $date->format($format);
 
+  }
 }
diff --git a/core/modules/datetime/tests/src/Kernel/DateTimeItemTest.php b/core/modules/datetime/tests/src/Kernel/DateTimeItemTest.php
index 0bf8d68..187afce 100644
--- a/core/modules/datetime/tests/src/Kernel/DateTimeItemTest.php
+++ b/core/modules/datetime/tests/src/Kernel/DateTimeItemTest.php
@@ -125,4 +125,25 @@ public function testSetValueProperty() {
     $this->assertEqual($entity->field_datetime[0]->value, $value, '"Value" property can be set directly.');
   }
 
+  /**
+   * Tests collecting an end date.
+   */
+  public function testEnddate() {
+    /** @var \Drupal\field\FieldStorageConfigInterface $field_storage */
+    $field_storage = FieldStorageConfig::load('entity_test.field_datetime');
+    $field_storage->setSetting('enddate_get', TRUE);
+    $field_storage->save();
+
+    $entity = EntityTest::create();
+    $value = '2014-01-01T20:00:00Z';
+    $value2 = '2014-02-01T20:00:00Z';
+
+    $entity->set('field_datetime', ['value' => $value, 'value2' => $value2]);
+    $entity->save();
+
+    // Load the entity.
+    $id = $entity->id();
+    $entity = EntityTest::load($id);
+    $this->assertEqual($value2, $entity->field_datetime[0]->value2, '"end date" property can be set.');
+  }
 }
diff --git a/core/modules/field/src/Entity/FieldStorageConfig.php b/core/modules/field/src/Entity/FieldStorageConfig.php
index eaf14c6..c3c01c1 100644
--- a/core/modules/field/src/Entity/FieldStorageConfig.php
+++ b/core/modules/field/src/Entity/FieldStorageConfig.php
@@ -288,6 +288,10 @@ public function preSave(EntityStorageInterface $storage) {
     $default_settings = $field_type_manager->getDefaultStorageSettings($this->type);
     $this->settings = array_intersect_key($this->settings, $default_settings) + $default_settings;
 
+    // Different settings could lead to different property definitions,
+    // invalidate the statically cached definitions.
+    $this->propertyDefinitions = NULL;
+
     if ($this->isNew()) {
       $this->preSaveNew($storage);
     }
