diff --git a/core/lib/Drupal/Core/Datetime/Element/Datetime.php b/core/lib/Drupal/Core/Datetime/Element/Datetime.php
index 44a3949..eaf9df1 100644
--- a/core/lib/Drupal/Core/Datetime/Element/Datetime.php
+++ b/core/lib/Drupal/Core/Datetime/Element/Datetime.php
@@ -61,6 +61,7 @@ public function getInfo() {
       '#date_year_range' => '1900:2050',
       '#date_increment' => 1,
       '#date_timezone' => '',
+      '#expose_timezone' => FALSE,
     );
   }
 
@@ -73,6 +74,11 @@ public static function valueCallback(&$element, $input, FormStateInterface $form
       $time_input  = $element['#date_time_element'] != 'none' && !empty($input['time']) ? $input['time'] : '';
       $date_format = $element['#date_date_element'] != 'none' ? static::getHtml5DateFormat($element) : '';
       $time_format = $element['#date_time_element'] != 'none' ? static::getHtml5TimeFormat($element) : '';
+
+      // Timezone.
+      if ($element['#expose_timezone'] && $input['timezone']) {
+        $element['#date_timezone'] = $input['timezone'];
+      }
       $timezone = !empty($element['#date_timezone']) ? $element['#date_timezone'] : NULL;
 
       // Seconds will be omitted in a post in case there's no entry.
@@ -100,6 +106,7 @@ public static function valueCallback(&$element, $input, FormStateInterface $form
         $input = array(
           'date'   => $date->format($element['#date_date_format']),
           'time'   => $date->format($element['#date_time_format']),
+          'timezone' => $date->getTimezone()->getName(),
           'object' => $date,
         );
       }
@@ -107,6 +114,7 @@ public static function valueCallback(&$element, $input, FormStateInterface $form
         $input = array(
           'date'   => '',
           'time'   => '',
+          'timezone' => '',
           'object' => NULL,
         );
       }
@@ -190,6 +198,8 @@ public static function valueCallback(&$element, $input, FormStateInterface $form
    *     provided, this value will be ignored, the timezone in the default date
    *     takes precedence. Defaults to the value returned by
    *     drupal_get_user_timezone().
+   *   - #expose_timezone: a boolean that if set to TRUE, will expose a timezone
+   *     select list. Defaults to FALSE.
    *
    * Example usage:
    * @code
@@ -308,6 +318,17 @@ public static function processDatetime(&$element, FormStateInterface $form_state
       }
     }
 
+    // Expose a timezone selector.
+    if ($element['#expose_timezone']) {
+      $element['timezone'] = array(
+        '#type' => 'select',
+        '#options' => array_combine(\DateTimeZone::listIdentifiers(), \DateTimeZone::listIdentifiers()),
+        // Default to user's timezone.
+        '#default_value' => $element['#date_timezone'],
+        '#required' => $element['#required'],
+      );
+    }
+
     return $element;
   }
 
diff --git a/core/modules/datetime/config/schema/datetime.schema.yml b/core/modules/datetime/config/schema/datetime.schema.yml
index 406a2fd..5da1701 100644
--- a/core/modules/datetime/config/schema/datetime.schema.yml
+++ b/core/modules/datetime/config/schema/datetime.schema.yml
@@ -7,6 +7,9 @@ field.storage_settings.datetime:
     datetime_type:
       type: string
       label: 'Date type'
+    timezone_handling:
+      type: string
+      label: 'Timezone handling'
 
 field.field_settings.datetime:
   type: mapping
@@ -26,6 +29,9 @@ field.value.datetime:
 field.formatter.settings.datetime_base:
   type: mapping
   mapping:
+    timezone_display:
+      type: string
+      label: 'Timezone display'
     timezone_override:
       type: string
       label: 'Time zone override'
diff --git a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeCustomFormatter.php b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeCustomFormatter.php
index 678ddc8..31bd1d1 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeCustomFormatter.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeCustomFormatter.php
@@ -44,7 +44,7 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
           // A date without time will pick up the current time, use the default.
           datetime_date_default_time($date);
         }
-        $this->setTimeZone($date);
+        $this->setTimeZone($date, $item->timezone);
 
         $output = $this->formatDate($date);
       }
@@ -66,7 +66,7 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
    */
   protected function formatDate($date) {
     $format = $this->getSetting('date_format');
-    $timezone = $this->getSetting('timezone_override');
+    $timezone = $this->getSetting('timezone_override') ?: $date->getTimezone()->getName();
     return $this->dateFormatter->format($date->getTimestamp(), 'custom', $format, $timezone != '' ? $timezone : NULL);
   }
 
diff --git a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeDefaultFormatter.php b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeDefaultFormatter.php
index 03c92ae..b330179 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeDefaultFormatter.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeDefaultFormatter.php
@@ -50,7 +50,7 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
         // Create the ISO date in Universal Time.
         $iso_date = $date->format("Y-m-d\TH:i:s") . 'Z';
 
-        $this->setTimeZone($date);
+        $this->setTimeZone($date, $item->timezone);
 
         $output = $this->formatDate($date);
       }
diff --git a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeFormatterBase.php b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeFormatterBase.php
index be9df38..9b8a670 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeFormatterBase.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimeFormatterBase.php
@@ -83,6 +83,7 @@ public static function create(ContainerInterface $container, array $configuratio
    */
   public static function defaultSettings() {
     return array(
+      'timezone_display' => DateTimeItem::TIMEZONE_USER,
       'timezone_override' => '',
     ) + parent::defaultSettings();
   }
@@ -93,13 +94,36 @@ public static function defaultSettings() {
   public function settingsForm(array $form, FormStateInterface $form_state) {
     $form = parent::settingsForm($form, $form_state);
 
-    $form['timezone_override'] = array(
-      '#type' => 'select',
-      '#title' => $this->t('Time zone override'),
-      '#description' => $this->t('The time zone selected here will always be used'),
-      '#options' => system_time_zones(TRUE),
-      '#default_value' => $this->getSetting('timezone_override'),
-    );
+    // Timezone display is only applicable to datetime items.
+    if ($this->fieldDefinition->getFieldStorageDefinition()->getSetting('datetime_type') === DateTimeItem::DATETIME_TYPE_DATETIME) {
+      $form['timezone_display'] = array(
+        '#type' => 'select',
+        '#title' => $this->t('Timezone display'),
+        '#description' => $this->t('The timezone to use when displaying this date.'),
+        '#options' => array(
+          DateTimeItem::TIMEZONE_USER => $this->t("The user's timezone"),
+          DateTimeItem::TIMEZONE_NONE => $this->t("Timezone override")
+        ),
+      );
+
+      // If this field is using per-date timezone storage, add that as an option.
+      if ($this->fieldDefinition->getFieldStorageDefinition()->getSetting('timezone_handling') === DateTimeItem::TIMEZONE_DATE) {
+        $form['timezone_display']['#options'][DateTimeItem::TIMEZONE_DATE] = $this->t("The date's timezone");
+      }
+
+      $form['timezone_override'] = array(
+        '#type' => 'select',
+        '#title' => $this->t('Time zone override'),
+        '#description' => $this->t('The time zone selected here will always be used'),
+        '#options' => system_time_zones(TRUE),
+        '#default_value' => $this->getSetting('timezone_override'),
+        '#states' => array(
+          'visible' => array(
+            ':input[name="fields[' . $this->fieldDefinition->getName() . '][settings_edit_form][settings][timezone_display]"]' => ['value' => DateTimeItem::TIMEZONE_NONE],
+          ),
+        )
+      );
+    }
 
     return $form;
   }
@@ -110,8 +134,15 @@ public function settingsForm(array $form, FormStateInterface $form_state) {
   public function settingsSummary() {
     $summary = parent::settingsSummary();
 
-    if ($override = $this->getSetting('timezone_override')) {
-      $summary[] = $this->t('Time zone: @timezone', array('@timezone' => $override));
+    if ($this->fieldDefinition->getFieldStorageDefinition()->getSetting('datetime_type') === DateTimeItem::DATETIME_TYPE_DATETIME) {
+      if ($override = $this->getSetting('timezone_override')) {
+        $summary[] = $this->t('Time zone: @timezone', array('@timezone' => $override));
+      }
+      else {
+        // @todo Make human-readable.
+        $summary[] = $this->t('Time zone display: @timezone', array('@timezone' => $this->getSetting('timezone_display')));
+
+      }
     }
 
     return $summary;
@@ -139,13 +170,15 @@ public function settingsSummary() {
    *
    * @param \Drupal\Core\Datetime\DrupalDateTime $date
    *   A DrupalDateTime object.
+   * @param string $timezone
+   *   (optional) A timezone to explicitly set the date to.
    */
-  protected function setTimeZone(DrupalDateTime $date) {
+  protected function setTimeZone(DrupalDateTime $date, $timezone = NULL) {
     if ($this->getFieldSetting('datetime_type') === DateTimeItem::DATETIME_TYPE_DATE) {
       // A date without time has no timezone conversion.
       $timezone = DATETIME_STORAGE_TIMEZONE;
     }
-    else {
+    elseif (empty($timezone)) {
       $timezone = drupal_get_user_timezone();
     }
     $date->setTimeZone(timezone_open($timezone));
diff --git a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimePlainFormatter.php b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimePlainFormatter.php
index 683d75c..6b80133 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimePlainFormatter.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldFormatter/DateTimePlainFormatter.php
@@ -34,7 +34,7 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
           // A date without time will pick up the current time, use the default.
           datetime_date_default_time($date);
         }
-        $this->setTimeZone($date);
+        $this->setTimeZone($date, $item->timezone);
 
         $output = $this->formatDate($date);
       }
@@ -56,7 +56,7 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
    */
   protected function formatDate($date) {
     $format = $this->getFieldSetting('datetime_type') == DateTimeItem::DATETIME_TYPE_DATE ? DATETIME_DATE_STORAGE_FORMAT : DATETIME_DATETIME_STORAGE_FORMAT;
-    $timezone = $this->getSetting('timezone_override');
+    $timezone = $this->getSetting('timezone_override') ?: $date->getTimezone()->getName();
     return $this->dateFormatter->format($date->getTimestamp(), 'custom', $format, $timezone != '' ? $timezone : NULL);
   }
 
diff --git a/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php b/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php
index f07d564..1727fd3 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php
@@ -28,6 +28,7 @@ class DateTimeItem extends FieldItemBase {
   public static function defaultStorageSettings() {
     return array(
       'datetime_type' => 'datetime',
+      'timezone_handling' => static::TIMEZONE_USER,
     ) + parent::defaultStorageSettings();
   }
 
@@ -42,6 +43,28 @@ public static function defaultStorageSettings() {
   const DATETIME_TYPE_DATETIME = 'datetime';
 
   /**
+   * Timezone uses the site's timezone, regardless of the user's timezone.
+   */
+  const TIMEZONE_SITE = 'site';
+
+  /**
+   * Timezone uses the user's timezone.
+   *
+   * @see drupal_get_user_timezone()
+   */
+  const TIMEZONE_USER = 'user';
+
+  /**
+   * Timezone is set per-date.
+   */
+  const TIMEZONE_DATE = 'date';
+
+  /**
+   * No timezone conversion is performed.
+   */
+  const TIMEZONE_NONE = 'none';
+
+  /**
    * {@inheritdoc}
    */
   public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
@@ -56,6 +79,9 @@ public static function propertyDefinitions(FieldStorageDefinitionInterface $fiel
       ->setClass('\Drupal\datetime\DateTimeComputed')
       ->setSetting('date source', 'value');
 
+    $properties['timezone'] = DataDefinition::create('string')
+      ->setLabel(t('Timezone'));
+
     return $properties;
   }
 
@@ -63,18 +89,25 @@ 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.',
           'type' => 'varchar',
           'length' => 20,
         ),
+        'timezone' => array(
+          'description' => 'The date timezone',
+          'type' => 'varchar',
+          'length' => 50,
+        ),
       ),
       'indexes' => array(
-        'value' => array('value'),
+        'value' => array('value', 'timezone'),
       ),
     );
+
+    return $schema;
   }
 
   /**
@@ -95,6 +128,29 @@ public function storageSettingsForm(array &$form, FormStateInterface $form_state
       '#disabled' => $has_data,
     );
 
+    $element['timezone_handling'] = array(
+      '#type' => 'select',
+      '#title' => t('Timezone handling'),
+      '#options' => array(
+        static::TIMEZONE_SITE => t("Site's timezone"),
+        static::TIMEZONE_DATE => t("Date's timezone"),
+        static::TIMEZONE_USER => t("User's timezone"),
+        static::TIMEZONE_NONE => t('No timezone conversion'),
+      ),
+      '#default_value' => $this->getSetting('timezone_handling'),
+      '#required' => TRUE,
+      '#states' => array(
+        // Hide the field if this is a date-only field.
+        'visible' => array(
+          ':input[name="settings[datetime_type]"]' => ['value' => static::DATETIME_TYPE_DATETIME],
+        ),
+        'disabled' => array(
+          ':input[name="settings[datetime_type]"]' => ['value' => static::DATETIME_TYPE_DATE],
+        ),
+      ),
+      '#disabled' => $has_data,
+    );
+
     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 aa6175a..f2b217f0 100644
--- a/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeWidgetBase.php
+++ b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeWidgetBase.php
@@ -30,7 +30,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
       '#type' => 'datetime',
       '#default_value' => NULL,
       '#date_increment' => 1,
-      '#date_timezone' => drupal_get_user_timezone(),
+      '#date_timezone' => $items[$delta]->timezone ?: drupal_get_user_timezone(),
       '#required' => $element['#required'],
     );
 
@@ -40,7 +40,12 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
       $element['value']['#date_timezone'] = DATETIME_STORAGE_TIMEZONE;
     }
 
+    if ($this->getFieldSetting('timezone_handling') === DateTimeItem::TIMEZONE_DATE) {
+      $element['value']['#expose_timezone'] = TRUE;
+    }
+
     if ($items[$delta]->date) {
+      /** @var \Drupal\Core\Datetime\DrupalDateTime $date */
       $date = $items[$delta]->date;
       // The date was created and verified during field_load(), so it is safe to
       // use without further inspection.
@@ -51,6 +56,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
       }
       $date->setTimezone(new \DateTimeZone($element['value']['#date_timezone']));
       $element['value']['#default_value'] = $date;
+      $element['timezone']['#default_value'] = $date->format('e');
     }
 
     return $element;
@@ -78,6 +84,15 @@ public function massageFormValues(array $values, array $form, FormStateInterface
             $format = DATETIME_DATETIME_STORAGE_FORMAT;
             break;
         }
+
+        // Store the timezone if set.
+        if ($this->getFieldSetting('timezone_handling') === DateTimeItem::TIMEZONE_DATE) {
+          $item['timezone'] = $date->getTimezone()->getName();
+        }
+        else {
+          $item['timezone'] = '';
+        }
+
         // Adjust the date for storage.
         $date->setTimezone(new \DateTimezone(DATETIME_STORAGE_TIMEZONE));
         $item['value'] = $date->format($format);
diff --git a/core/modules/datetime/src/Tests/DateTimeFieldTest.php b/core/modules/datetime/src/Tests/DateTimeFieldTest.php
index ce598bf..19868d6 100644
--- a/core/modules/datetime/src/Tests/DateTimeFieldTest.php
+++ b/core/modules/datetime/src/Tests/DateTimeFieldTest.php
@@ -7,6 +7,7 @@
 use Drupal\Core\Datetime\DrupalDateTime;
 use Drupal\Core\Datetime\Entity\DateFormat;
 use Drupal\Core\Entity\Entity\EntityViewDisplay;
+use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem;
 use Drupal\entity_test\Entity\EntityTest;
 use Drupal\field\Entity\FieldConfig;
 use Drupal\field\Entity\FieldStorageConfig;
@@ -114,6 +115,7 @@ protected function setUp() {
       ->save();
 
     $this->defaultSettings = array(
+      'timezone_display' => DateTimeItem::TIMEZONE_USER,
       'timezone_override' => '',
     );
 
@@ -297,6 +299,7 @@ function testDatetimeField() {
     $this->drupalGet('entity_test/add');
     $this->assertFieldByName("{$field_name}[0][value][date]", '', 'Date element found.');
     $this->assertFieldByName("{$field_name}[0][value][time]", '', 'Time element found.');
+    $this->assertNoFieldByName("{$field_name}[0][timezone]", '', 'No timezone field appears for dates that do not collect timezone information.');
 
     // Build up a date in the UTC timezone.
     $value = '2012-12-31 00:00:00';
@@ -422,6 +425,32 @@ function testDatetimeField() {
     ]);
     $this->renderTestEntity($id);
     $this->assertText($expected, SafeMarkup::format('Formatted date field using datetime_time_ago format displayed as %expected.', array('%expected' => $expected)));
+
+    // Verify timezone display settings.
+    $this->fieldStorage->setSetting('timezone_handling', DateTimeItem::TIMEZONE_DATE);
+    $this->fieldStorage->save();
+
+    $edit = array(
+      "{$field_name}[0][value][date]" => $date->format($date_format),
+      "{$field_name}[0][value][time]" => $date->format($time_format),
+      "{$field_name}[0][value][timezone]" => 'America/New_York',
+    );
+    $this->drupalPostForm('entity_test/add', $edit, t('Save'));
+    preg_match('|entity_test/manage/(\d+)|', $this->url, $match);
+    $id = $match[1];
+    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)));
+
+    $this->displayOptions['type'] = 'datetime_custom';
+    $this->displayOptions['settings'] = [
+      'date_format' => 'm/d/Y g:i:s A e',
+      'timezone_display' => DateTimeItem::TIMEZONE_DATE,
+    ] + $this->defaultSettings;
+    entity_get_display($this->field->getTargetEntityTypeId(), $this->field->getTargetBundle(), 'full')
+      ->setComponent($field_name, $this->displayOptions)
+      ->save();
+    $this->renderTestEntity($id);
+    $expected = $date->format($this->displayOptions['settings']['date_format'], ['timezone' => 'America/New_York']);
+    $this->assertText($expected);
   }
 
   /**
diff --git a/core/modules/datetime/tests/src/Kernel/DateTimeItemTest.php b/core/modules/datetime/tests/src/Kernel/DateTimeItemTest.php
index d26434b..e452e6c 100644
--- a/core/modules/datetime/tests/src/Kernel/DateTimeItemTest.php
+++ b/core/modules/datetime/tests/src/Kernel/DateTimeItemTest.php
@@ -31,7 +31,10 @@ protected function setUp() {
       'field_name' => 'field_datetime',
       'type' => 'datetime',
       'entity_type' => 'entity_test',
-      'settings' => array('datetime_type' => 'date'),
+      'settings' => array(
+        'datetime_type' => 'date',
+        'timezone_handling' => 'site',
+      ),
     ));
     $field_storage->save();
     $field = FieldConfig::create([
@@ -120,4 +123,28 @@ public function testSetValueProperty() {
     $this->assertEqual($entity->field_datetime[0]->value, $value, '"Value" property can be set directly.');
   }
 
+  /**
+   * Tests DateTimeItem with per-date timezone handling.
+   */
+  public function testTimezoneDate() {
+    /** @var \Drupal\field\FieldStorageConfigInterface $field_storage */
+    $field_storage = FieldStorageConfig::load('entity_test.field_datetime');
+    $field_storage->setSetting('timezone_handling', 'date');
+    $field_storage->save();
+
+    // Use a non-UTC timezone.
+    $timezone = 'America/Yellowknife';
+
+    $entity = EntityTest::create();
+    $value = '2014-01-01T20:00:00Z';
+
+    $entity->set('field_datetime', ['value' => $value, 'timezone' => $timezone]);
+    $entity->save();
+
+    // Load the entity.
+    $id = $entity->id();
+    $entity = EntityTest::load($id);
+    $this->assertEqual($timezone, $entity->field_datetime[0]->timezone, '"timezone" property can be set.');
+  }
+
 }
