diff --git a/core/lib/Drupal/Core/Render/Element/YearRange.php b/core/lib/Drupal/Core/Render/Element/YearRange.php
new file mode 100644
index 0000000..fb89649
--- /dev/null
+++ b/core/lib/Drupal/Core/Render/Element/YearRange.php
@@ -0,0 +1,103 @@
+<?php
+
+namespace Drupal\Core\Render\Element;
+
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a year range configuration element.
+ *
+ * @FormElement("date_year_range")
+ */
+class YearRange extends FormElement {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getInfo() {
+    $class = get_class($this);
+    return [
+      '#input' => TRUE,
+      '#element_validate' => [
+         [$class, 'validateRange'],
+      ],
+      '#process' => [
+         [$class, 'processRange'],
+      ],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
+    // Convert the element's default value from a string to an array (to match
+    // what we will get from the two textfields when the form is submitted).
+    if ($input === FALSE && isset($element['#default_value'])) {
+      list($years_back, $years_forward) = explode(':', $element['#default_value']);
+      return [
+        'years_back' => $years_back,
+        'years_forward' => $years_forward,
+      ];
+    }
+    return parent::valueCallback($element, $input, $form_state);
+  }
+
+  /**
+   * Process callback.
+   */
+  public static function processRange(&$element, FormStateInterface $form_state, &$complete_form) {
+    // Year range is stored in the -3:+3 format, but collected as two separate
+    // textfields.
+    $element['years_back'] = [
+      '#type' => 'textfield',
+      '#title' => t('Starting year'),
+      '#default_value' => $element['#value']['years_back'],
+      '#size' => 10,
+      '#maxsize' => 10,
+       '#description' => t('Enter a relative value (-9, +9) or an absolute year such as 2015.'),
+    ];
+    $element['years_forward'] = [
+      '#type' => 'textfield',
+      '#title' => t('Ending year'),
+      '#default_value' => $element['#value']['years_forward'],
+      '#size' => 10,
+      '#maxsize' => 10,
+      '#description' => t('Enter a relative value (-9, +9) or an absolute year such as 2015.'),
+    ];
+
+    $element['#tree'] = TRUE;
+
+    return $element;
+  }
+
+  /**
+   * Validate callback.
+   */
+  public static function validateRange(&$element, FormStateInterface $form_state, &$complete_form) {
+    // Recombine the two submitted form values into the -3:+3 format we will
+    // validate and save.
+    $year_range_submitted = $form_state->getValue($element['#parents']);
+    $year_range = $year_range_submitted['years_back'] . ':' . $year_range_submitted['years_forward'];
+    $form_state->setValue($element['#parents'], $year_range);
+    if (!static::rangeIsValid($year_range)) {
+      $form_state->setError($element['years_back'], t('Starting year must be in the format -9, or an absolute year such as 1980.'));
+      $form_state->setError($element['years_forward'], t('Ending year must be in the format +9, or an absolute year such as 2030.'));
+    }
+  }
+
+  /**
+   * Check if range is valid.
+   *
+   * @param string $range
+   *   Range to validate.
+   *
+   * @return bool
+   *   TRUE if range is valid.
+   */
+  public static function rangeIsValid($range) {
+    $matches = preg_match('@^(\-[0-9]+|[0-9]{4}):([\+|\-][0-9]+|[0-9]{4})$@', $range);
+    return !($matches < 1);
+  }
+
+}
diff --git a/core/modules/datetime/config/schema/datetime.schema.yml b/core/modules/datetime/config/schema/datetime.schema.yml
index a009011..5af3edf 100644
--- a/core/modules/datetime/config/schema/datetime.schema.yml
+++ b/core/modules/datetime/config/schema/datetime.schema.yml
@@ -65,7 +65,7 @@ field.formatter.settings.datetime_time_ago:
       label: 'Granularity'
 
 field.widget.settings.datetime_datelist:
-  type: mapping
+  type: field.widget.settings.datetime_default
   label: 'Datetime select list display format settings'
   mapping:
     increment:
@@ -81,3 +81,7 @@ field.widget.settings.datetime_datelist:
 field.widget.settings.datetime_default:
   type: mapping
   label: 'Datetime default display format settings'
+  mapping:
+    year_range:
+      type: string
+      label: 'Year range'
diff --git a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php
index 276d92c..ce503ea 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeDatelistWidget.php
@@ -138,7 +138,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function settingsSummary() {
-    $summary = [];
+    $summary = parent::settingsSummary();
 
     $summary[] = t('Date part order: @order', ['@order' => $this->getSetting('date_order')]);
     if ($this->getFieldSetting('datetime_type') == 'datetime') {
diff --git a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeWidgetBase.php b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeWidgetBase.php
index ce86e04..efe302e 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeWidgetBase.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeWidgetBase.php
@@ -23,6 +23,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
       '#default_value' => NULL,
       '#date_increment' => 1,
       '#date_timezone' => drupal_get_user_timezone(),
+      '#date_year_range' => $this->getSetting('year_range'),
       '#required' => $element['#required'],
     ];
 
@@ -94,4 +95,36 @@ protected function createDefaultValue($date, $timezone) {
     return $date;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function defaultSettings() {
+    return parent::defaultSettings() + [
+      'year_range' => '1900:2050',
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsForm(array $form, FormStateInterface $form_state) {
+    $build = parent::settingsForm($form, $form_state);
+    $build['year_range'] = [
+      '#type' => 'date_year_range',
+      '#default_value' => $this->getSetting('year_range'),
+    ];
+    return $build;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsSummary() {
+    return array_merge(parent::settingsSummary(), [
+      $this->t('Year range: @range', [
+        '@range' => $this->getSetting('year_range'),
+      ])
+    ]);
+  }
+
 }
diff --git a/core/modules/datetime/tests/src/Functional/DateTimeYearRangeTest.php b/core/modules/datetime/tests/src/Functional/DateTimeYearRangeTest.php
new file mode 100644
index 0000000..9b29271
--- /dev/null
+++ b/core/modules/datetime/tests/src/Functional/DateTimeYearRangeTest.php
@@ -0,0 +1,120 @@
+<?php
+
+namespace Drupal\Tests\datetime\Functional;
+
+use Drupal\Core\Entity\Entity\EntityFormDisplay;
+use Drupal\datetime\Plugin\Field\FieldWidget\DateTimeDatelistWidget;
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests the year range settings of the date time field.
+ *
+ * @group datetime
+ */
+class DateTimeYearRangeTest extends BrowserTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'entity_test',
+    'datetime',
+    'field'
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    FieldStorageConfig::create([
+      'entity_type' => 'entity_test',
+      'field_name' => 'date',
+      'id' => 'entity_test.date',
+      'type' => 'datetime',
+      'settings' => [
+         'target_type' => 'entity_test',
+      ],
+    ])->save();
+    FieldConfig::create([
+      'field_name' => 'date',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
+      'id' => 'entity_test.entity_test.date',
+      'label' => 'Date',
+    ])->save();
+    $this->getEntityFormDisplay('entity_test', 'entity_test', 'default')
+      ->setComponent('date', [
+        'type' => 'datetime_datelist',
+        'weight' => 10,
+      ])
+      ->save();
+  }
+
+  /**
+   * Gets entity form display.
+   *
+   * @param string $entity_type
+   *   Entity type ID.
+   * @param string $bundle
+   *   Bundle.
+   * @param string $form_mode
+   *   Form mode.
+   *
+   * @return \Drupal\Core\Entity\EntityInterface
+   *   Form display.
+   */
+  protected function getEntityFormDisplay($entity_type, $bundle, $form_mode) {
+    $entity_form_display = EntityFormDisplay::load($entity_type . '.' . $bundle . '.' . $form_mode);
+
+    // If not found, create a fresh entity object. We do not preemptively create
+    // new entity form display configuration entries for each existing entity
+    // type and bundle whenever a new form mode becomes available. Instead,
+    // configuration entries are only created when an entity form display is
+    // explicitly configured and saved.
+    if (!$entity_form_display) {
+      $entity_form_display = EntityFormDisplay::create([
+        'targetEntityType' => $entity_type,
+        'bundle' => $bundle,
+        'mode' => $form_mode,
+        'status' => TRUE,
+      ]);
+    }
+
+    return $entity_form_display;
+  }
+
+  /**
+   * Test the year range widget setting.
+   */
+  public function testDateTimeYearRange() {
+    $this->drupalLogin($this->drupalCreateUser([], NULL, TRUE));
+    $this->drupalGet('/entity_test/add');
+    $assert = $this->assertSession();
+    $assert->fieldExists('date[0][value][year]');
+    // Test the default 1900:2050 range.
+    $assert->optionExists('date[0][value][year]', 1900);
+    $assert->optionExists('date[0][value][year]', 2050);
+    // Now change the settings.
+    $this->getEntityFormDisplay('entity_test', 'entity_test', 'default')
+      ->setComponent('date', [
+        'type' => 'datetime_datelist',
+        'weight' => 10,
+        'settings' => [
+            'year_range' => '1978:2017',
+          ] + DateTimeDatelistWidget::defaultSettings(),
+      ])
+      ->save();
+    $this->drupalGet('/entity_test/add');
+    $assert = $this->assertSession();
+    $assert->fieldExists('date[0][value][year]');
+    // Test the new 1978:2017 range.
+    $assert->optionNotExists('date[0][value][year]', 1900);
+    $assert->optionNotExists('date[0][value][year]', 2050);
+    $assert->optionExists('date[0][value][year]', 1978);
+    $assert->optionExists('date[0][value][year]', 2017);
+  }
+
+}
diff --git a/core/modules/datetime_range/config/schema/datetime_range.schema.yml b/core/modules/datetime_range/config/schema/datetime_range.schema.yml
index f0f9325..934f349 100644
--- a/core/modules/datetime_range/config/schema/datetime_range.schema.yml
+++ b/core/modules/datetime_range/config/schema/datetime_range.schema.yml
@@ -55,7 +55,7 @@ field.formatter.settings.daterange_custom:
       translation context: 'Date range separator'
 
 field.widget.settings.daterange_datelist:
-  type: mapping
+  type: field.widget.settings.daterange_default
   label: 'Date range select list display format settings'
   mapping:
     increment:
@@ -71,3 +71,7 @@ field.widget.settings.daterange_datelist:
 field.widget.settings.daterange_default:
   type: mapping
   label: 'Date range default display format settings'
+  mapping:
+    year_range:
+      type: string
+      label: 'Year range'
diff --git a/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeDatelistWidget.php b/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeDatelistWidget.php
index 3e0e6e4..f31c173 100644
--- a/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeDatelistWidget.php
+++ b/core/modules/datetime_range/src/Plugin/Field/FieldWidget/DateRangeDatelistWidget.php
@@ -143,7 +143,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function settingsSummary() {
-    $summary = [];
+    $summary = parent::settingsSummary();
 
     $summary[] = $this->t('Date part order: @order', ['@order' => $this->getSetting('date_order')]);
     if ($this->getFieldSetting('datetime_type') == DateRangeItem::DATETIME_TYPE_DATETIME) {
diff --git a/core/modules/datetime_range/tests/src/Functional/DateRangeYearRangeTest.php b/core/modules/datetime_range/tests/src/Functional/DateRangeYearRangeTest.php
new file mode 100644
index 0000000..c6e5612
--- /dev/null
+++ b/core/modules/datetime_range/tests/src/Functional/DateRangeYearRangeTest.php
@@ -0,0 +1,136 @@
+<?php
+
+namespace Drupal\Tests\datetime_range\Functional;
+
+use Drupal\Core\Entity\Entity\EntityFormDisplay;
+use Drupal\datetime_range\Plugin\Field\FieldWidget\DateRangeDatelistWidget;
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests the year range settings of the date range field.
+ *
+ * @group datetime_range
+ */
+class DateRangeYearRangeTest extends BrowserTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'entity_test',
+    'datetime_range',
+    'datetime',
+    'field'
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    FieldStorageConfig::create([
+      'entity_type' => 'entity_test',
+      'field_name' => 'range',
+      'id' => 'entity_test.range',
+      'type' => 'daterange',
+      'settings' => [
+         'target_type' => 'entity_test',
+      ],
+    ])->save();
+    FieldConfig::create([
+      'field_name' => 'range',
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
+      'id' => 'entity_test.entity_test.range',
+      'label' => 'Range',
+    ])->save();
+    $this->getEntityFormDisplay('entity_test', 'entity_test', 'default')
+      ->setComponent('range', [
+        'type' => 'daterange_datelist',
+        'weight' => 10,
+      ])
+      ->save();
+  }
+
+  /**
+   * Gets entity form display.
+   *
+   * @param string $entity_type
+   *   Entity type ID.
+   * @param string $bundle
+   *   Bundle.
+   * @param string $form_mode
+   *   Form mode.
+   *
+   * @return \Drupal\Core\Entity\EntityInterface
+   *   Form display.
+   */
+  protected function getEntityFormDisplay($entity_type, $bundle, $form_mode) {
+    $entity_form_display = EntityFormDisplay::load($entity_type . '.' . $bundle . '.' . $form_mode);
+
+    // If not found, create a fresh entity object. We do not preemptively create
+    // new entity form display configuration entries for each existing entity
+    // type and bundle whenever a new form mode becomes available. Instead,
+    // configuration entries are only created when an entity form display is
+    // explicitly configured and saved.
+    if (!$entity_form_display) {
+      $entity_form_display = EntityFormDisplay::create([
+        'targetEntityType' => $entity_type,
+        'bundle' => $bundle,
+        'mode' => $form_mode,
+        'status' => TRUE,
+      ]);
+    }
+
+    return $entity_form_display;
+  }
+
+  /**
+   * Test the year range widget setting.
+   *
+   * @dataProvider providerTestDateRangeYearRange
+   */
+  public function testDateRangeYearRange($from, $to, $from_year = NULL, $to_year = NULL) {
+    $from_year = $from_year ?: $from;
+    $to_year = $to_year ?: $to;
+    $from_year_not_exists = $from_year - 1;
+    $to_year_not_exists = $to_year + 1;
+
+    $this->drupalLogin($this->drupalCreateUser([], NULL, TRUE));
+    $this->getEntityFormDisplay('entity_test', 'entity_test', 'default')
+      ->setComponent('range', [
+        'type' => 'daterange_datelist',
+        'weight' => 10,
+        'settings' => [
+            'year_range' => $from . ':' . $to,
+          ] + DateRangeDatelistWidget::defaultSettings(),
+      ])
+      ->save();
+    $this->drupalGet('/entity_test/add');
+    $assert = $this->assertSession();
+    $assert->fieldExists('range[0][value][year]');
+    $assert->optionNotExists('range[0][value][year]', $from_year_not_exists);
+    $assert->optionNotExists('range[0][value][year]', $to_year_not_exists);
+    $assert->optionExists('range[0][value][year]', $from_year);
+    $assert->optionExists('range[0][value][year]', $to_year);
+  }
+
+  /**
+   * Data provider for testDateRangeYearRange().
+   */
+  public function providerTestDateRangeYearRange() {
+    return [
+      'year:year' => ['1978', '2017'],
+      'positive:year' => ['+3', '2040', date('Y') + 3],
+      'negative:year' => ['-3', '2017', date('Y') - 3],
+      'year:positive' => ['1978', '+3', NULL, date('Y') + 3],
+      'year:negative' => ['1978', '-3', NULL, date('Y') - 3],
+      'positive:positive' => ['+3', '+9', date('Y') + 3, date('Y') + 9],
+      'negative:negative' => ['-9', '-3', date('Y') - 9, date('Y') - 3],
+      'negative:positive' => ['-3', '+3', date('Y') - 3, date('Y') + 3],
+    ];
+  }
+
+}
diff --git a/core/modules/field/tests/src/Kernel/Migrate/d6/MigrateFieldWidgetSettingsTest.php b/core/modules/field/tests/src/Kernel/Migrate/d6/MigrateFieldWidgetSettingsTest.php
index 6e8e040..d7dd4e2 100644
--- a/core/modules/field/tests/src/Kernel/Migrate/d6/MigrateFieldWidgetSettingsTest.php
+++ b/core/modules/field/tests/src/Kernel/Migrate/d6/MigrateFieldWidgetSettingsTest.php
@@ -91,7 +91,7 @@ public function testWidgetSettings() {
     $component = $form_display->getComponent('field_test_date');
     $expected['type'] = 'datetime_default';
     $expected['weight'] = 10;
-    $expected['settings'] = [];
+    $expected['settings'] = ['year_range' => '1900:2050'];
     $this->assertIdentical($expected, $component);
 
     $component = $form_display->getComponent('field_test_datestamp');
diff --git a/core/tests/Drupal/Tests/Core/Render/Element/YearRangeTest.php b/core/tests/Drupal/Tests/Core/Render/Element/YearRangeTest.php
new file mode 100644
index 0000000..a93cf9b
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Render/Element/YearRangeTest.php
@@ -0,0 +1,73 @@
+<?php
+
+namespace Drupal\Tests\Core\Render\Element;
+
+use Drupal\Core\Form\FormState;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\Element\YearRange;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Core\Render\Element\YearRange
+ * @group Render
+ */
+class YearRangeTest extends UnitTestCase {
+
+  /**
+   * @covers ::valueCallback
+   */
+  public function testValueCallback() {
+    $expected = ['years_back' => '-3', 'years_forward' => '+3'];
+    $element = ['#default_value' => '-3:+3'];
+    $form_state = $this->prophesize(FormStateInterface::class)->reveal();
+    $this->assertSame($expected, YearRange::valueCallback($element, FALSE, $form_state));
+  }
+
+
+  /**
+   * @covers ::processRange
+   */
+  public function testProcessRange() {
+    $form_state = new FormState();
+
+    $element = [
+      '#value' => [
+        'years_back' => '-3',
+        'years_forward' => '+3',
+      ],
+    ];
+
+    $complete_form = [
+      'test_source' => [
+        '#type' => 'textfield',
+        '#id' => 'source',
+      ],
+      'test_year_range' => $element
+    ];
+
+    $form_state->setCompleteForm($complete_form);
+    $element = YearRange::processRange($element, $form_state, $complete_form);
+
+    $expected = [
+      '#type' => 'textfield',
+      '#size' => 10,
+      '#maxsize' => 10,
+      '#description' => 'Enter a relative value (-9, +9) or an absolute year such as 2015.',
+    ];
+    $expected_years_back = ['#title' => 'Starting year', '#default_value' => '-3'] + $expected;
+    $expected_years_forward = ['#title' => 'Ending year', '#default_value' => '+3'] + $expected;
+
+    $this->assertEquals($expected_years_back, $element['years_back']);
+    $this->assertEquals($expected_years_forward, $element['years_forward']);
+    $this->assertTrue($element['#tree']);
+  }
+
+}
+
+namespace Drupal\Core\Render\Element;
+
+if (!function_exists('t')) {
+  function t($string, array $args = []) {
+    return strtr($string, $args);
+  }
+}
