diff --git a/core/modules/node/lib/Drupal/node/NodeFormController.php b/core/modules/node/lib/Drupal/node/NodeFormController.php
index 215ad81e4a9df6aaca7f7178a40f495a533edf67..5859f854ae3398231e29f6e2d66a8c46c9c70072 100644
--- a/core/modules/node/lib/Drupal/node/NodeFormController.php
+++ b/core/modules/node/lib/Drupal/node/NodeFormController.php
@@ -44,6 +44,9 @@ protected function prepareEntity(EntityInterface $node) {
       // Remove the log message from the original node entity.
       $node->log = NULL;
     }
+    if (!empty($node->published)) {
+      $node->pub_date = format_date($node->published, 'custom', 'Y-m-d H:i:s O');
+    }
     // Always use the default revision setting.
     $node->setNewRevision(in_array('revision', $node_options));
 
@@ -222,6 +225,14 @@ public function form(array $form, array &$form_state, EntityInterface $node) {
       '#default_value' => $node->status,
     );
 
+    $form['options']['pub_date'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Published on'),
+      '#maxlength' => 25,
+      '#description' => t('Format: %time. The date format is YYYY-MM-DD and %timezone is the time zone offset from UTC. Leave blank to use the time of form submission.', array('%time' => !empty($node->pub_date) ? date_format(date_create($node->pub_date), 'Y-m-d H:i:s O') : format_date($node->published, 'custom', 'Y-m-d H:i:s O'), '%timezone' => !empty($node->pub_date) ? date_format(date_create($node->pub_date), 'O') : format_date($node->published, 'custom', 'O'))),
+      '#default_value' => !empty($node->pub_date) ? $node->pub_date : '',
+    );
+
     $form['options']['promote'] = array(
       '#type' => 'checkbox',
       '#title' => t('Promoted to front page'),
@@ -294,6 +305,12 @@ public function validate(array $form, array &$form_state) {
       form_set_error('date', t('You have to specify a valid date.'));
     }
 
+    // Validate the "published on" field.
+    $pub_date = new DrupalDateTime($node->pub_date);
+    if ($pub_date->hasErrors()) {
+      form_set_error('pub_date', t('You have to specify a valid publication date.'));
+    }
+
     // Invoke hook_validate() for node type specific validation and
     // hook_node_validate() for miscellaneous validation needed by modules.
     // Can't use node_invoke() or module_invoke_all(), because $form_state must
diff --git a/core/modules/node/lib/Drupal/node/NodeStorageController.php b/core/modules/node/lib/Drupal/node/NodeStorageController.php
index d855384e95a821682ff64e63e5bf5a926ed66920..d5b6a55f6a5d55aeb2e7a852a77a8ee9841d5673 100644
--- a/core/modules/node/lib/Drupal/node/NodeStorageController.php
+++ b/core/modules/node/lib/Drupal/node/NodeStorageController.php
@@ -95,6 +95,11 @@ protected function invokeHook($hook, EntityInterface $node) {
   protected function preSave(EntityInterface $node) {
     // Before saving the node, set changed and revision times.
     $node->changed = REQUEST_TIME;
+
+    // If this is being published for the first time, set the published time.
+    if (!empty($node->status) && empty($node->published)) {
+      $node->published = REQUEST_TIME;
+    }
   }
 
   /**
diff --git a/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php
index 1fd8fc8efcd6fa6d088a9a2c5a32bc68835477b0..3751371e2f3393557eab922f3c5a1b5721f5f933 100644
--- a/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php
+++ b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/Node.php
@@ -141,6 +141,13 @@ class Node extends Entity implements ContentEntityInterface {
   public $changed;
 
   /**
+   * The node publication timestamp.
+   *
+   * @var integer
+   */
+  public $published;
+
+  /**
    * The node comment status indicator.
    *
    * COMMENT_NODE_HIDDEN => no comments
diff --git a/core/modules/node/node.install b/core/modules/node/node.install
index c6fd7e6819901fed635f176b27a0e54d39c8e10e..c8d791476012f1f2c97629fc47b4c68b2fb18811 100644
--- a/core/modules/node/node.install
+++ b/core/modules/node/node.install
@@ -79,6 +79,12 @@ function node_schema() {
         'not null' => TRUE,
         'default' => 0,
       ),
+      'published' => array(
+        'description' => 'The Unix timestamp when the node was first published.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
       'comment' => array(
         'description' => 'Whether comments are allowed on this node: 0 = no, 1 = closed (read only), 2 = open (read/write).',
         'type' => 'int',
@@ -114,6 +120,7 @@ function node_schema() {
     'indexes' => array(
       'node_changed'        => array('changed'),
       'node_created'        => array('created'),
+      'node_published'      => array('published'),
       'node_frontpage'      => array('promote', 'status', 'sticky', 'created'),
       'node_status_type'    => array('status', 'type', 'nid'),
       'node_title_type'     => array('title', array('type', 4)),
@@ -717,6 +724,29 @@ function node_update_8012() {
   update_module_enable(array('history'));
 }
 
+/**
+ * Create a published column for nodes.
+ */
+function node_update_8013() {
+  $spec = array(
+    'description' => 'The Unix timestamp when the node was first published.',
+    'type' => 'int',
+    'not null' => TRUE,
+    'default' => 0,
+  );
+  $keys = array(
+    'indexes' => array(
+      'node_published' => array('published'),
+    ),
+  );
+  db_add_field('node', 'published', $spec, $keys);
+  // Set the pulished timestamp to changed for already published nodes.
+  db_update('node')
+    ->condition('status', 1, '=')
+    ->expression('published', 'changed')
+    ->execute();
+}
+
 
 /**
  * @} End of "addtogroup updates-7.x-to-8.x"
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 08d781080a989e03279abe4812a51e31d8ce5c4b..a0e4809b4d2b60761835a459acbef01c3b4a95b8 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -981,6 +981,14 @@ function node_submit(Node $node) {
     $node->created = REQUEST_TIME;
   }
 
+  if (!empty($node->pub_date)) {
+    $node_published = new DrupalDateTime($node->pub_date);
+    $node->published = $node_published->getTimestamp();
+  }
+  elseif (!empty($node->status)) {
+    $node->published = REQUEST_TIME;
+  }
+
   $node->validated = TRUE;
 
   return $node;
