diff --git a/modules/webform_node/webform_node.routing.yml b/modules/webform_node/webform_node.routing.yml
index 653303b8..afb4aaee 100644
--- a/modules/webform_node/webform_node.routing.yml
+++ b/modules/webform_node/webform_node.routing.yml
@@ -281,6 +281,22 @@ entity.node.webform_submission.resend_form:
   requirements:
     _custom_access: '\Drupal\webform_node\Access\WebformNodeAccess::checkWebformSubmissionAccess'
 
+entity.node.webform_submission.duplicate_form:
+  path: '/node/{node}/webform/submission/{webform_submission}/duplicate'
+  defaults:
+    _entity_form: 'webform_submission.duplicate'
+    _title_callback: 'Drupal\webform\Controller\WebformSubmissionController::title'
+    operation: webform_submission_duplicate
+    entity_access: 'webform_submission.update_any'
+    duplicate: TRUE
+  options:
+    _admin_route: TRUE
+    parameters:
+      node:
+        type: 'entity:node'
+  requirements:
+    _custom_access: '\Drupal\webform_node\Access\WebformNodeAccess::checkWebformSubmissionAccess'
+
 entity.node.webform_submission.delete_form:
   path: '/node/{node}/webform/submission/{webform_submission}/delete'
   defaults:
diff --git a/src/Controller/WebformSubmissionController.php b/src/Controller/WebformSubmissionController.php
index ea74b5c6..d312ba11 100644
--- a/src/Controller/WebformSubmissionController.php
+++ b/src/Controller/WebformSubmissionController.php
@@ -124,17 +124,21 @@ class WebformSubmissionController extends ControllerBase implements ContainerInj
    *
    * @param \Drupal\webform\WebformSubmissionInterface $webform_submission
    *   The webform submission.
+   * @param bool $duplicate
+   *   Flag indicating if submission is being duplicated.
    *
    * @return array
    *   The webform submission as a render array.
    */
-  public function title(WebformSubmissionInterface $webform_submission) {
+  public function title(WebformSubmissionInterface $webform_submission, $duplicate = TRUE) {
     $source_entity = $this->requestHandler->getCurrentSourceEntity('webform_submission');
     $t_args = [
       '@form' => ($source_entity) ? $source_entity->label() : $webform_submission->getWebform()->label(),
       '@id' => $webform_submission->serial(),
     ];
-    return $this->t('@form: Submission #@id', $t_args);
+
+    $title = $this->t('@form: Submission #@id', $t_args);
+    return ($duplicate) ? $this->t('Duplicate @title', ['@title' => $title]) : $title;
   }
 
 }
diff --git a/src/Entity/WebformSubmission.php b/src/Entity/WebformSubmission.php
index 3d35136d..ee44dc76 100644
--- a/src/Entity/WebformSubmission.php
+++ b/src/Entity/WebformSubmission.php
@@ -35,6 +35,7 @@ use Drupal\webform\WebformSubmissionInterface;
  *     "form" = {
  *       "default" = "Drupal\webform\WebformSubmissionForm",
  *       "notes" = "Drupal\webform\WebformSubmissionNotesForm",
+ *       "duplicate" = "Drupal\webform\WebformSubmissionDuplicateForm",
  *       "delete" = "Drupal\webform\Form\WebformSubmissionDeleteForm",
  *     },
  *   },
@@ -55,6 +56,7 @@ use Drupal\webform\WebformSubmissionInterface;
  *     "edit-form" = "/admin/structure/webform/manage/{webform}/submission/{webform_submission}/edit",
  *     "notes-form" = "/admin/structure/webform/manage/{webform}/submission/{webform_submission}/notes",
  *     "resend-form" = "/admin/structure/webform/manage/{webform}/submission/{webform_submission}/resend",
+ *     "duplicate-form" = "/admin/structure/webform/manage/{webform}/submission/{webform_submission}/duplicate",
  *     "delete-form" = "/admin/structure/webform/manage/{webform}/submission/{webform_submission}/delete",
  *     "collection" = "/admin/structure/webform/results/manage/list"
  *   },
@@ -622,7 +624,15 @@ class WebformSubmission extends ContentEntityBase implements WebformSubmissionIn
    * {@inheritdoc}
    */
   public function preSave(EntityStorageInterface $storage) {
+    // Set created.
+    if (!$this->created->value) {
+      $this->created->value = REQUEST_TIME;
+    }
+
+    // Set changed.
     $this->changed->value = REQUEST_TIME;
+
+    // Set completed.
     if ($this->isDraft()) {
       $this->completed->value = NULL;
     }
diff --git a/src/Tests/WebformSubmissionTest.php b/src/Tests/WebformSubmissionTest.php
index 6dfaf222..9a523373 100644
--- a/src/Tests/WebformSubmissionTest.php
+++ b/src/Tests/WebformSubmissionTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\webform\Tests;
 
+use Drupal\webform\Entity\Webform;
 use Drupal\webform\Entity\WebformSubmission;
 
 /**
@@ -78,4 +79,33 @@ class WebformSubmissionTest extends WebformTestBase {
     $this->assertEqual($webform_submission->label(), $webform->label() . ': Submission #' . $webform_submission->serial());
   }
 
+  /**
+   * Tests duplicating webform submission.
+   */
+  public function testDuplicateWebformSubmission() {
+    $this->createUsers();
+    $this->drupalLogin($this->adminSubmissionUser);
+
+    $webform = Webform::load('contact');
+    $sid = $this->postSubmission($webform, [
+      'subject' => '{Original Subject}',
+      'message' => '{Original Message}',
+    ]);
+
+    // Check duplicate form title.
+    $this->drupalGet("admin/structure/webform/manage/contact/submission/$sid/duplicate");
+    $this->assertRaw('Duplicate Contact: Submission #' . $sid);
+
+    // Duplicate submission.
+    $this->drupalPostForm("admin/structure/webform/manage/contact/submission/$sid/duplicate", ['subject' => '{Duplicate Subject}'], t('Send message'));
+    $duplicate_sid = $this->getLastSubmissionId($webform);
+    /** @var \Drupal\webform\WebformSubmissionInterface $duplicate_submission */
+    $duplicate_submission = WebformSubmission::load($duplicate_sid);
+
+    // Check duplicate submission.
+    $this->assertNotEqual($sid, $duplicate_sid);
+    $this->assertEqual($duplicate_submission->getData('subject'), '{Duplicate Subject}');
+    $this->assertEqual($duplicate_submission->getData('message'), '{Original Message}');
+  }
+
 }
diff --git a/src/WebformSubmissionDuplicateForm.php b/src/WebformSubmissionDuplicateForm.php
new file mode 100644
index 00000000..4334f92d
--- /dev/null
+++ b/src/WebformSubmissionDuplicateForm.php
@@ -0,0 +1,71 @@
+<?php
+
+namespace Drupal\webform;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Form\FormStateInterface;
+use \Drupal\Component\Uuid\Php;
+use Drupal\Core\Url;
+
+/**
+ * Provides a webform to duplicate existing submissions.
+ */
+class WebformSubmissionDuplicateForm extends WebformSubmissionForm {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setEntity(EntityInterface $entity) {
+    /** @var \Drupal\webform\WebformSubmissionInterface $entity */
+    $entity = clone $entity;
+
+    // Clear IDs.
+    $entity->set('uuid', (new Php())->generate());
+    $entity->set('sid', NULL);
+    $entity->set('serial', NULL);
+
+    // Clear state.
+    $entity->set('in_draft', FALSE);
+
+    // Create timestamps.
+    $entity->set('created', NULL);
+    $entity->set('changed', NULL);
+    $entity->set('completed', NULL);
+
+    // Clear admin notes and sticky.
+    $entity->set('notes', '');
+    $entity->set('sticky', FALSE);
+
+    $this->messageManager->setWebformSubmission($entity);
+    $this->messageManager->setWebform($entity->getWebform());
+    $this->messageManager->setSourceEntity($entity->getSourceEntity());
+
+    $this->entity = $entity;
+    return $this;
+  }
+
+  /**
+   * Set webform state confirmation redirect and message.
+   *
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   */
+  protected function setConfirmation(FormStateInterface $form_state) {
+    parent::setConfirmation($form_state);
+
+    // If the form is just reloading the duplicate form, redirect to the
+    // new submission.
+    $redirect = $form_state->getRedirect();
+    $route_name = $this->getRouteMatch()->getRouteName();
+    if ($redirect instanceof Url && $redirect->getRouteName() === $route_name) {
+      /** @var \Drupal\webform\WebformSubmissionInterface $entity */
+      $webform_submission = $this->entity;
+      $webform = $webform_submission->getWebform();
+      $source_entity = $webform_submission->getSourceEntity();
+
+      $redirect_route_name = $this->requestHandler->getRouteName($webform_submission, $source_entity, 'webform_submission.canonical');
+      $redirect_route_parameters = $this->requestHandler->getRouteParameters($webform_submission, $source_entity);
+      $form_state->setRedirect($redirect_route_name, $redirect_route_parameters);
+    }
+  }
+}
diff --git a/src/WebformSubmissionListBuilder.php b/src/WebformSubmissionListBuilder.php
index 36389e09..ac9262e3 100644
--- a/src/WebformSubmissionListBuilder.php
+++ b/src/WebformSubmissionListBuilder.php
@@ -387,7 +387,7 @@ class WebformSubmissionListBuilder extends EntityListBuilder {
       case 'created':
       case 'completed':
       case 'changed':
-        return ($is_raw) ? $entity->created->value : \Drupal::service('date.formatter')->format($entity->created->value);
+        return ($is_raw) ? $entity->created->value : $entity->created->value ? \Drupal::service('date.formatter')->format($entity->created->value) : '';
 
       case 'entity':
         $source_entity = $entity->getSourceEntity();
@@ -518,6 +518,11 @@ class WebformSubmissionListBuilder extends EntityListBuilder {
         'weight' => 22,
         'url' => Url::fromRoute("$base_route_name.webform_submission.resend_form", $route_parameters, $route_options),
       ];
+      $operations['duplicate'] = [
+        'title' => $this->t('Duplicate'),
+        'weight' => 23,
+        'url' => Url::fromRoute("$base_route_name.webform_submission.duplicate_form", $route_parameters, $route_options),
+      ];
     }
 
     if ($entity->access('delete')) {
diff --git a/webform.routing.yml b/webform.routing.yml
index 111f008a..64d40565 100644
--- a/webform.routing.yml
+++ b/webform.routing.yml
@@ -406,6 +406,15 @@ entity.webform_submission.resend_form:
   requirements:
     _custom_access: '\Drupal\webform\Access\WebformAccess::checkEmailAccess'
 
+entity.webform_submission.duplicate_form:
+  path: '/admin/structure/webform/manage/{webform}/submission/{webform_submission}/duplicate'
+  defaults:
+    _entity_form: 'webform_submission.duplicate'
+    _title_callback: 'Drupal\webform\Controller\WebformSubmissionController::title'
+    duplicate: TRUE
+  requirements:
+    _entity_access: 'webform_submission.update_any'
+
 entity.webform_submission.delete_form:
   path: '/admin/structure/webform/manage/{webform}/submission/{webform_submission}/delete'
   defaults:
