diff --git a/core/includes/common.inc b/core/includes/common.inc
index a4fcf51..a3eab05 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -1844,7 +1844,7 @@ function format_interval($interval, $granularity = 2, $langcode = NULL) {
 }
 
 /**
- * Formats a date, using a date type or a custom date format string.
+ * Formats a date, using a date type.
  *
  * @param $timestamp
  *   A UNIX timestamp to format.
@@ -1853,15 +1853,35 @@ function format_interval($interval, $granularity = 2, $langcode = NULL) {
  *   - 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 name of a date type defined by a module in hook_date_format_types().
  *   - The machine name of an administrator-defined date format.
  *   - 'custom', to use $format.
  *   Defaults to 'medium'.
+ * @param $timezone
+ *   (optional) Time zone identifier, as described at
+ *   http://php.net/manual/en/timezones.php Defaults to the time zone used to
+ *   display the page.
+ * @param $langcode
+ *   (optional) Language code to translate to. Defaults to the language used to
+ *   display the page.
+ *
+ * @return
+ *   A translated date string in the requested date type.
+ */
+function format_date($timestamp, $type = 'medium', $timezone = NULL, $langcode = NULL) {
+  $format = variable_get("date_format_$type");
+  return format_date_format($timestamp, $format, $timezone, $langcode);
+}
+
+/**
+ * Formats a date, using a custom date format string.
+ *
+ * @param $timestamp
+ *   A UNIX timestamp to format.
  * @param $format
- *   (optional) If $type is 'custom', a PHP date format string suitable for
- *   input to date(). Use a backslash to escape ordinary text, so it does not
- *   get interpreted as date format characters.
+ *   A PHP date format string suitable for input to date(). Use a backslash to
+ *   escape ordinary text, so it does not get interpreted as date format
+ *   characters.
  * @param $timezone
  *   (optional) Time zone identifier, as described at
  *   http://php.net/manual/en/timezones.php Defaults to the time zone used to
@@ -1873,7 +1893,7 @@ function format_interval($interval, $granularity = 2, $langcode = NULL) {
  * @return
  *   A translated date string in the requested format.
  */
-function format_date($timestamp, $type = 'medium', $format = '', $timezone = NULL, $langcode = NULL) {
+function format_date_format($timestamp, $format, $timezone = NULL, $langcode = NULL) {
   // Use the advanced drupal_static() pattern, since this is called very often.
   static $drupal_static_fast;
   if (!isset($drupal_static_fast)) {
@@ -1896,60 +1916,6 @@ function format_date($timestamp, $type = 'medium', $format = '', $timezone = NUL
     $langcode = isset($language->langcode) ? $language->langcode : LANGUAGE_SYSTEM;
   }
 
-  switch ($type) {
-    case 'short':
-      $format = variable_get('date_format_short', 'm/d/Y - H:i');
-      break;
-
-    case 'long':
-      $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;
-
-    case 'medium':
-    default:
-      // Retrieve the format of the custom $type passed.
-      if ($type != 'medium') {
-        $format = variable_get('date_format_' . $type, '');
-      }
-      // Fall back to 'medium'.
-      if ($format === '') {
-        $format = variable_get('date_format_medium', 'D, m/d/Y - H:i');
-      }
-      break;
-  }
-
   // Create a DateTime object from the timestamp.
   $date_time = date_create('@' . $timestamp);
   // Set the time zone for the DateTime object.
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index 00c4c41..7be3a1d 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -1954,6 +1954,10 @@ function system_date_time_settings() {
   $custom_formats = system_get_date_formats('custom');
   if (!empty($format_types)) {
     foreach ($format_types as $type => $type_info) {
+      if ($type_info['hidden']) {
+        continue;
+      }
+
       // If a system type, only show the available formats for that type and
       // custom ones.
       if ($type_info['locked'] == 1) {
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index 8947ac1..6f56a44 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -3520,15 +3520,8 @@ function hook_archiver_info_alter(&$info) {
  *
  * Date types are used in the administration interface: a user can assign
  * date format types defined in hook_date_formats() to date types defined in
- * this hook. Once a format has been assigned by a user, the machine name of a
- * type can be used in the format_date() function to format a date using the
- * chosen formatting.
- *
- * To define a date type in a module and make sure a format has been assigned to
- * it, without requiring a user to visit the administrative interface, use
- * @code variable_set('date_format_' . $type, $format); @endcode
- * where $type is the machine-readable name defined here, and $format is a PHP
- * date format string.
+ * this hook. The machine name of a type can be used in the format_date()
+ * function to format a date using the chosen formatting.
  *
  * To avoid namespace collisions with date types defined by other modules, it is
  * recommended that each date type starts with the module name. A date type
@@ -3536,7 +3529,13 @@ function hook_archiver_info_alter(&$info) {
  *
  * @return
  *   An array of date types where the keys are the machine-readable names and
- *   the values are the human-readable labels.
+ *   the values are arrays with the following keys:
+ *   - title: The human-readable name of the date type.
+ *   - default format: The default date format to use for this date type, if
+ *     none has been explicitly set.
+ *   - hidden: (optional) Whether or not this date type should be hidden from
+ *     the user interface. The date type can still be configured via
+ *     variable_set(). Defaults to FALSE.
  *
  * @see hook_date_formats()
  * @see format_date()
@@ -3544,9 +3543,24 @@ function hook_archiver_info_alter(&$info) {
 function hook_date_format_types() {
   // Define the core date format types.
   return array(
-    'long' => t('Long'),
-    'medium' => t('Medium'),
-    'short' => t('Short'),
+    'long' => array(
+      'title' => t('Long'),
+      'default format' => 'l, F j, Y - H:i',
+    ),
+    'medium' => array(
+      'title' => t('Medium'),
+      'default format' => 'D, m/d/Y - H:i',
+    ),
+    'short' => array(
+      'title' => t('Short'),
+      'default format' => 'm/d/Y - H:i',
+    ),
+    'html_datetime' => array(
+      'title' => t('HTML datetime'),
+      'default format' => 'Y-m-d\TH:i:sO',
+      'hidden' => TRUE,
+    ),
+    // Core actually defines further HTML-related date types.
   );
 }
 
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 332e559..0c231eb 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -3527,9 +3527,53 @@ function system_get_date_types($type = NULL) {
  */
 function system_date_format_types() {
   return array(
-    'long' => t('Long'),
-    'medium' => t('Medium'),
-    'short' => t('Short'),
+    'long' => array(
+      'title' => t('Long'),
+      'default format' => 'l, F j, Y - H:i',
+    ),
+    'medium' => array(
+      'title' => t('Medium'),
+      'default format' => 'D, m/d/Y - H:i',
+    ),
+    'short' => array(
+      'title' => t('Short'),
+      'default format' => 'm/d/Y - H:i',
+    ),
+    'html_datetime' => array(
+      'title' => t('HTML datetime'),
+      'default format' => 'Y-m-d\TH:i:sO',
+      'hidden' => TRUE,
+    ),
+    'html_date' => array(
+      'title' => t('HTML date'),
+      'default format' => 'Y-m-d',
+      'hidden' => TRUE,
+    ),
+    'html_time' => array(
+      'title' => t('HTML time'),
+      'default format' => 'H:i:s',
+      'hidden' => TRUE,
+    ),
+   'html_yearless_date' => array(
+      'title' => t('HTML yearless date'),
+      'default format' => 'm-d',
+      'hidden' => TRUE,
+    ),
+    'html_week' => array(
+      'title' => t('HTML week'),
+      'default format' => 'Y-\WW',
+      'hidden' => TRUE,
+    ),
+    'html_month' => array(
+      'title' => t('HTML month'),
+      'default format' => 'Y-m',
+      'hidden' => TRUE,
+    ),
+    'html_year' => array(
+      'title' => t('HTML year'),
+      'default format' => 'Y',
+      'hidden' => TRUE,
+    ),
   );
 }
 
@@ -3669,22 +3713,30 @@ function system_date_format_locale($langcode = NULL, $type = NULL) {
  *     unsaved in the database.
  */
 function _system_date_format_types_build() {
-  $types = array();
+  $date_types = array();
 
   // Get list of modules that implement hook_date_format_types().
   $modules = module_implements('date_format_types');
 
   foreach ($modules as $module) {
     $module_types = module_invoke($module, 'date_format_types');
-    foreach ($module_types as $module_type => $type_title) {
-      $type = array();
-      $type['module'] = $module;
-      $type['type'] = $module_type;
-      $type['title'] = $type_title;
-      $type['locked'] = 1;
-      // Will be over-ridden later if in the db.
-      $type['is_new'] = TRUE;
-      $types[$module_type] = $type;
+    foreach ($module_types as $machine_name => $info) {
+      $date_type = array();
+      $date_type['module'] = $module;
+      $date_type['type'] = $module_type;
+      $date_type['title'] = $info['title'];
+      $date_type['locked'] = 1;
+      $date_type['hidden'] = (isset($info['hidden']) ? $info['hidden'] : FALSE);
+      // This will be overridden later if there is already a corresponding
+      // record in the database.
+      $date_type['is_new'] = TRUE;
+      $date_types[$machine_name] = $date_type;
+
+      // Set the date format, if not set.
+      $format = variable_get("date_format_$machine_name");
+      if (!isset($format)) {
+        variable_set("date_format_$machine_name", $info['default format']);
+      }
     }
   }
 
@@ -3692,17 +3744,20 @@ function _system_date_format_types_build() {
   $result = db_query('SELECT dft.type, dft.title, dft.locked FROM {date_format_type} dft ORDER BY dft.title');
   foreach ($result as $record) {
     if (!isset($types[$record->type])) {
-      $type = array();
-      $type['is_new'] = FALSE;
-      $type['module'] = '';
-      $type['type'] = $record->type;
-      $type['title'] = $record->title;
-      $type['locked'] = $record->locked;
-      $types[$record->type] = $type;
+      $date_type = array();
+      $date_type['is_new'] = FALSE;
+      $date_type['module'] = '';
+      $date_type['type'] = $record->type;
+      $date_type['title'] = $record->title;
+      $date_type['locked'] = $record->locked;
+      // Date types added in the user interface are never hidden.
+      $date_types['hidden'] = FALSE;
+      $date_types[$record->type] = $type;
     }
     else {
       $type = array();
-      $type['is_new'] = FALSE;  // Over-riding previous setting.
+      // Override previous setting.
+      $type['is_new'] = FALSE;
       $types[$record->type] = array_merge($types[$record->type], $type);
     }
   }
