diff --git a/core/includes/common.inc b/core/includes/common.inc
index 2f14740..693c0f2 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_date', 'html_time', '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_date':
+      $format = variable_get('date_format_html_date', 'Y-m-d');
+      break;
+
+    case 'html_time':
+      $format = variable_get('date_format_html_time', 'H:i:s');
+      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;
@@ -6717,6 +6747,9 @@ function drupal_common_theme() {
       'render element' => 'elements',
       'template' => 'region',
     ),
+    'datetime' => array(
+      'variables' => array('timestamp' => NULL, 'text' => NULL, 'attributes' => array(), 'html' => FALSE),
+    ),
     'status_messages' => array(
       'variables' => array('display' => NULL),
     ),
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 0c955e8..117b589 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1475,6 +1475,66 @@ function theme_disable($theme_list) {
  */
 
 /**
+ * Preprocess variables for theme_datetime().
+ */
+function template_preprocess_datetime(&$variables) {
+  // Format the 'datetime' attribute based on the timestamp.
+  // @see http://www.w3.org/TR/html5-author/the-time-element.html#attr-time-datetime
+  if (!isset($variables['attributes']['datetime']) && isset($variables['timestamp'])) {
+    $variables['attributes']['datetime'] = format_date($variables['timestamp'], 'html_datetime', '', 'UTC');
+  }
+
+  // If no text was provided, try to auto-generate it.
+  if (!isset($variables['text'])) {
+    // Format and use a human-readable version of the timestamp, if any.
+    if (isset($variables['timestamp'])) {
+      $variables['text'] = format_date($variables['timestamp']);
+      $variables['html'] = FALSE;
+    }
+    // Otherwise, use the literal datetime attribute.
+    elseif (isset($variables['attributes']['datetime'])) {
+      $variables['text'] = $variables['attributes']['datetime'];
+      $variables['html'] = FALSE;
+    }
+  }
+}
+
+/**
+ * Returns HTML for a date / time.
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - timestamp: (optional) A UNIX timestamp for the datetime attribute. If the
+ *     datetime cannot be represented as a UNIX timestamp, use a valid datetime
+ *     attribute value in $variables['attributes']['datetime'].
+ *   - text: (optional) The content to display within the <time> element. Set
+ *     'html' to TRUE if this value is already sanitized for output in HTML.
+ *     Defaults to a human-readable representation of the timestamp value or the
+ *     datetime attribute value using format_date().
+ *     When invoked as #theme or #theme_wrappers of a render element, the
+ *     rendered #children are autoamtically taken over as 'text', unless #text
+ *     is explicitly set.
+ *   - attributes: (optional) An associative array of HTML attributes to apply
+ *     to the <time> element. A datetime attribute in 'attributes' overrides the
+ *     'timestamp'. To create a valid datetime attribute value from a UNIX
+ *     timestamp, use format_date() with one of the predefined 'html_*' formats.
+ *   - html: (optional) Whether 'text' is HTML markup (TRUE) or plain-text
+ *     (FALSE). Defaults to FALSE. For example, to use a SPAN tag within the
+ *     TIME element, this must be set to TRUE, or the SPAN tag will be escaped.
+ *     It is the responsibility of the caller to properly sanitize the value
+ *     contained in 'text' (or within the SPAN tag in aforementioned example).
+ *
+ * @see template_preprocess_datetime()
+ * @see http://www.w3.org/TR/html5-author/the-time-element.html#attr-time-datetime
+ */
+function theme_datetime($variables) {
+  $output = '<time' . drupal_attributes($variables['attributes']) . '>';
+  $output .= !empty($variables['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 b07ad18..cb35a83 100644
--- a/core/modules/simpletest/tests/common.test
+++ b/core/modules/simpletest/tests/common.test
@@ -2361,6 +2361,14 @@ 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.
+    $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_date'), '2007-03-25', t('Test html_date date format.'));
+    $this->assertIdentical(format_date($timestamp, 'html_time'), '17:00:00', t('Test html_time 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 9870545..21a69bd 100644
--- a/core/modules/simpletest/tests/theme.test
+++ b/core/modules/simpletest/tests/theme.test
@@ -592,3 +592,65 @@ class ThemeRegistryTestCase extends DrupalWebTestCase {
     $this->assertTrue($registry['theme_test_template_test_2'], 'Offset was returned correctly from the theme registry');
   }
 }
+
+/**
+ * Tests for theme_datetime().
+ */
+class ThemeDatetime extends DrupalWebTestCase {
+  protected $profile = 'testing';
+
+  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));
+
+    // Test with text and timestamp.
+    $variables = array(
+      'timestamp' => $timestamp,
+      'text' => "Dries' birthday",
+    );
+    $this->assertEqual('<time datetime="1978-11-19T00:00:00+0000">Dries&#039; birthday</time>', theme('datetime', $variables));
+
+    // Test with datetime attribute.
+    $variables = array(
+      'attributes' => array(
+        'datetime' => '1978-11-19',
+      ),
+    );
+    $this->assertEqual('<time datetime="1978-11-19">1978-11-19</time>', theme('datetime', $variables));
+
+    // Test with text and datetime attribute.
+    $variables = array(
+      'text' => "Dries' birthday",
+      'attributes' => array(
+        'datetime' => '1978-11-19',
+      ),
+    );
+    $this->assertEqual('<time datetime="1978-11-19">Dries&#039; birthday</time>', theme('datetime', $variables));
+
+    // Test with HTML text.
+    $variables = array(
+      'timestamp' => $timestamp,
+      'text' => "<span>Dries' birthday</span>",
+      'html' => TRUE,
+    );
+    $this->assertEqual('<time datetime="1978-11-19T00:00:00+0000"><span>Dries\' birthday</span></time>', theme('datetime', $variables));
+  }
+}
