diff --git a/core/includes/common.inc b/core/includes/common.inc
index 99fcdba..c448bb8 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -1850,7 +1850,9 @@ function format_interval($timestamp, $granularity = 2, $langcode = NULL) {
  *   A UNIX timestamp to format.
  * @param $type
  *   (optional) The format to use, one of:
- *   - 'short', 'medium', or 'long' (the corresponding built-in date formats).
+ *   - One of the built-in formats: 'short', 'medium', 'long', 'html_datetime',
+ *     'html_time', 'html_date', 'html_yearless_date', 'html_week',
+ *     'html_month', 'html_year'.
  *   - The name of a date type defined by a module in hook_date_format_types(),
  *     if it's been assigned a format.
  *   - The machine name of an administrator-defined date format.
@@ -1903,6 +1905,34 @@ function format_date($timestamp, $type = 'medium', $format = '', $timezone = NUL
       $format = variable_get('date_format_long', 'l, F j, Y - H:i');
       break;
 
+    case 'html_datetime':
+      $format = variable_get('date_format_html_datetime', 'Y-m-d\TH:i:sO');
+      break;
+
+    case 'html_time':
+      $format = variable_get('date_format_html_time', 'H:i:s');
+      break;
+
+    case 'html_date':
+      $format = variable_get('date_format_html_date', 'Y-m-d');
+      break;
+
+    case 'html_yearless_date':
+      $format = variable_get('date_format_html_yearless_date', 'm-d');
+      break;
+
+    case 'html_week':
+      $format = variable_get('date_format_html_week', 'Y-\WW');
+      break;
+
+    case 'html_month':
+      $format = variable_get('date_format_html_month', 'Y-m');
+      break;
+
+    case 'html_year':
+      $format = variable_get('date_format_html_year', 'Y');
+      break;
+
     case 'custom':
       // No change to format.
       break;
@@ -6640,6 +6670,9 @@ function drupal_common_theme() {
       'render element' => 'elements',
       'template' => 'region',
     ),
+    'datetime' => array(
+      'variables' => array('timestamp' => NULL, 'text' => NULL, 'options' => array('attributes' => array(), 'html' => FALSE)),
+    ),
     'status_messages' => array(
       'variables' => array('display' => NULL),
     ),
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index e6c0725..85f2f15 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1463,6 +1463,66 @@ function theme_disable($theme_list) {
  */
 
 /**
+ * Preprocess variables for theme_datetime().
+ */
+function template_preprocess_datetime(&$variables) {
+  // Use the datetime attribute if provided.
+  if (!isset($variables['options']['attributes']['datetime'])) {
+    // If the datetime attribute was not provided, attempt to use the timestamp
+    // value as the datetime attribute.
+    if (isset($variables['timestamp'])) {
+      // Format the datetime attribute.
+      // See http://www.w3.org/TR/html5-author/the-time-element.html#attr-time-datetime
+      $variables['options']['attributes']['datetime'] = format_date($variables['timestamp'], 'html_datetime', '', 'UTC');
+      // If no text for the <time> element was provided, print a human-readable
+      // version of the timestamp.
+      if (!isset($variables['text'])) {
+        $variables['text'] = format_date($variables['timestamp']);
+      }
+    }
+  }
+  // If no text was provided, use the datetime attribute as the text. If the
+  // the datetime attribute is not set then return an empty string.
+  if (!isset($variables['text'])) {
+    $variables['text'] = isset($variables['options']['attributes']['datetime']) ? $variables['options']['attributes']['datetime'] : '';
+  }
+}
+
+/**
+ * Returns HTML for a date / time.
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - timestamp: (optional) A UNIX timestamp for the datetime. If the
+ *     datetime cannot be represented as a UNIX timestamp, use a valid datetime
+ *     attribute value in $variables['options']['attributes']['datetime'].
+ *   - text: (optional) The content to display in the <time> element. Set
+ *     $variables['options']['html'] to TRUE if this value should be output
+ *     without any HTML filtering. Defaults to a human-readable version of the
+ *     timestamp value or the datetime attribute value.
+ *   - options: (optional) An associative array of additional options, with the
+ *     following elements:
+ *     - 'attributes': An associative array of HTML attributes to apply to the
+ *        time tag. If a datetime attribute is passed in, it will override the
+ *        timestamp. To create a valid datetime attribute value from a UNIX
+ *        timestamp, use format_html_datetime().
+ *        See http://www.w3.org/TR/html5-author/the-time-element.html#attr-time-datetime
+ *     - 'html' (default FALSE): Whether $text is HTML or just plain-text. For
+ *        example, to use a span tag within the time element, this must be set
+ *        to TRUE, or the span tag will be stripped. $text is not sanitized if
+ *        'html' is TRUE. The calling function must ensure that $text is
+ *        already safe.
+ *
+ * @see template_preprocess_datetime
+ */
+function theme_datetime($variables) {
+  $output = '<time' . drupal_attributes($variables['options']['attributes']) . '>';
+  $output .= !empty($variables['options']['html']) ? $variables['text'] : check_plain($variables['text']);
+  $output .= '</time>';
+  return $output;
+}
+
+/**
  * Returns HTML for status and/or error messages, grouped by type.
  *
  * An invisible heading identifies the messages for assistive technology.
diff --git a/core/modules/simpletest/tests/common.test b/core/modules/simpletest/tests/common.test
index 8936808..b2e05f6 100644
--- a/core/modules/simpletest/tests/common.test
+++ b/core/modules/simpletest/tests/common.test
@@ -2361,6 +2361,15 @@ class FormatDateUnitTest extends DrupalWebTestCase {
     $this->assertIdentical(format_date($timestamp, 'medium'), '25. marzo 2007 - 17:00', t('Test medium date format.'));
     $this->assertIdentical(format_date($timestamp, 'short'), '2007 Mar 25 - 5:00pm', t('Test short date format.'));
     $this->assertIdentical(format_date($timestamp), '25. marzo 2007 - 17:00', t('Test default date format.'));
+    // Test HTML time element formats.
+    debug(format_date($timestamp, 'html_datetime'));
+    $this->assertIdentical(format_date($timestamp, 'html_datetime'), '2007-03-25T17:00:00-0700', t('Test html_datetime date format.'));
+    $this->assertIdentical(format_date($timestamp, 'html_time'), '17:00:00', t('Test html_time date format.'));
+    $this->assertIdentical(format_date($timestamp, 'html_date'), '2007-03-25', t('Test html_date date format.'));
+    $this->assertIdentical(format_date($timestamp, 'html_yearless_date'), '03-25', t('Test html_yearless_date date format.'));
+    $this->assertIdentical(format_date($timestamp, 'html_week'), '2007-W12', t('Test html_week date format.'));
+    $this->assertIdentical(format_date($timestamp, 'html_month'), '2007-03', t('Test html_month date format.'));
+    $this->assertIdentical(format_date($timestamp, 'html_year'), '2007', t('Test html_year date format.'));
 
     // Restore the original user and language, and enable session saving.
     $user = $real_user;
diff --git a/core/modules/simpletest/tests/theme.test b/core/modules/simpletest/tests/theme.test
index 6fb6b3b..08e8740 100644
--- a/core/modules/simpletest/tests/theme.test
+++ b/core/modules/simpletest/tests/theme.test
@@ -490,3 +490,70 @@ class ThemeHtmlTplPhpAttributesTestCase extends DrupalWebTestCase {
     $this->assertTrue(count($attributes) == 1, t('Attribute set in the body element via hook_preprocess_html() found.'));
   }
 }
+
+/**
+ * Tests for theme_datetime().
+ */
+class ThemeDatetime extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Theme Datetime',
+      'description' => 'Test the theme_datetime() function.',
+      'group' => 'Theme',
+    );
+  }
+
+  /**
+   * Test function theme_datetime().
+   */
+  function testThemeDatetime() {
+    // Create timestamp and formatted date for testing.
+    $timestamp = 280281600;
+    $date = format_date($timestamp);
+
+    // Test with timestamp.
+    $variables = array(
+      'timestamp' => $timestamp,
+    );
+    $this->assertEqual('<time datetime="1978-11-19T00:00:00+0000">' . $date . '</time>', theme('datetime', $variables), t('Test theme_datetime with timestamp.'));
+
+    // Test with text and timestamp.
+    $variables = array(
+      'timestamp' => $timestamp,
+      'text' => 'Dries\'s birthday',
+    );
+    debug(theme('datetime', $variables));
+    $this->assertEqual('<time datetime="1978-11-19T00:00:00+0000">Dries&#039;s birthday</time>', theme('datetime', $variables), t('Test theme_datetime with text and timestamp.'));
+
+    // Test with datetime attribute.
+    $variables = array(
+      'options' => array(
+        'attributes' => array(
+          'datetime' => '1978-11-19',
+        ),
+      ),
+    );
+    $this->assertEqual('<time datetime="1978-11-19">1978-11-19</time>', theme('datetime', $variables), t('Test theme_datetime with datetime attribute.'));
+
+    // Test with text and datetime attribute.
+    $variables = array(
+      'text' => 'Dries\'s birthday',
+      'options' => array(
+        'attributes' => array(
+          'datetime' => '1978-11-19',
+        ),
+      ),
+    );
+    $this->assertEqual('<time datetime="1978-11-19">Dries&#039;s birthday</time>', theme('datetime', $variables), t('Test theme_datetime with text and datetime attribute.'));
+
+    // Test with HTML text.
+    $variables = array(
+      'timestamp' => $timestamp,
+      'text' => '<span>Dries\'s birthday</span>',
+      'options' => array(
+        'html' => TRUE,
+      ),
+    );
+    $this->assertEqual('<time datetime="1978-11-19T00:00:00+0000"><span>Dries\'s birthday</span></time>', theme('datetime', $variables), t('Test theme_datetime with HTML text.'));
+  }
+}
