diff --git a/token.tokens.inc b/token.tokens.inc
index 70c8672..3927c38 100644
--- a/token.tokens.inc
+++ b/token.tokens.inc
@@ -1339,6 +1339,17 @@ function field_token_info_alter(&$info) {
           ];
         }
       }
+      // Provide format token for datetime fields.
+      if ($field->getType() == 'datetime') {
+        $info['tokens'][$field_token_name]['date'] = $info['tokens'][$field_token_name]['value'];
+        $info['tokens'][$field_token_name]['date']['type'] = 'date';
+      }
+      if ($field->getType() == 'daterange') {
+        $info['tokens'][$field_token_name]['date'] = $info['tokens'][$field_token_name]['value'];
+        $info['tokens'][$field_token_name]['date']['type'] = 'date';
+        $info['tokens'][$field_token_name]['end_date'] = $info['tokens'][$field_token_name]['end_value'];
+        $info['tokens'][$field_token_name]['end_date']['type'] = 'date';
+      }
     }
   }
 }
@@ -1565,6 +1576,15 @@ function field_tokens($type, $tokens, array $data = array(), array $options = ar
           }
         }
       }
+      elseif ($field_item->getFieldDefinition()->getType() == 'datetime' || $field_item->getFieldDefinition()->getType() == 'daterange') {
+        foreach (['date', 'end_date'] as $property) {
+          $date_tokens = \Drupal::token()->findWithPrefix($tokens, $property);
+          if ($date_tokens) {
+            $datetime = strtotime($field_item->$property);
+            $replacements += \Drupal::token()->generate('date', $date_tokens, ['date' => $datetime], $options, $bubbleable_metadata);
+          }
+        }
+      }
       else {
         $replacements[$original] = $field_item->$property_name;
       }
