Index: date.css
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/date/date.css,v
retrieving revision 1.20.4.14
diff -u -p -r1.20.4.14 date.css
--- date.css	8 Dec 2008 12:15:57 -0000	1.20.4.14
+++ date.css	10 Jan 2009 15:39:25 -0000
@@ -149,4 +149,19 @@ span.date-display-separator {
  .date-clear-block { 	 
    display: block; 	 
  } 	 
- /* End hide from IE-mac */
\ No newline at end of file
+ /* End hide from IE-mac */
+
+.date-container .date-format-delete {
+  margin-top: 1.8em;
+  margin-left: 1.5em;
+  float: left;
+}
+.date-container .date-format-name {
+  float: left;
+}
+.date-container .date-format-type {
+  float: left;
+  padding-left: 10px;
+}
+
+
Index: date_api.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/date/date_api.install,v
retrieving revision 1.16.2.1.2.9
diff -u -p -r1.16.2.1.2.9 date_api.install
--- date_api.install	4 Oct 2008 12:43:31 -0000	1.16.2.1.2.9
+++ date_api.install	10 Jan 2009 15:39:25 -0000
@@ -46,17 +46,143 @@ function date_api_set_variables() {
 }
 
 /**
+ * Implementation of hook_schema().
+ */
+function date_api_schema() {
+  $schema['date_format_types'] = array(
+    'description' => 'For storing configured date format types.',
+    'fields' => array(
+      'type' => array(
+        'description' => 'The date format type, e.g. medium.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+      'title' => array(
+        'description' => 'The human readable name of the format type.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+      'system_type' => array(
+        'description' => 'Whether or not this is a system provided format.',
+        'type' => 'int',
+        'size' => 'tiny',
+        'default' => 0,
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('type'),
+  );
+
+  $schema['date_format'] = array(
+    'description' => 'For storing configured date formats.',
+    'fields' => array(
+      'format' => array(
+        'description' => 'The date format string.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+      'type' => array(
+        'description' => 'The date format type, e.g. medium.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+      'custom' => array(
+        'description' => 'Whether or not this is a user inputted format.',
+        'type' => 'int',
+        'size' => 'tiny',
+        'default' => 0,
+        'not null' => TRUE,
+      ),
+      'modified' => array(
+        'description' => 'Whether or not this format has been modified.',
+        'type' => 'int',
+        'size' => 'tiny',
+        'default' => 0,
+        'not null' => TRUE,
+      ),
+      'locked' => array(
+        'description' => 'Whether or not this format can be modified.',
+        'type' => 'int',
+        'size' => 'tiny',
+        'default' => 0,
+        'not null' => TRUE,
+      ),
+      'orig_format' => array(
+        'description' => 'The original format if this has been modified.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('format'),
+  );
+
+  $schema['date_format_locale'] = array(
+    'description' => 'For storing configured date formats for each locale.',
+    'fields' => array(
+      'format' => array(
+        'description' => 'The date format string.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+      'type' => array(
+        'description' => 'The date format type, e.g. medium.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+      'langcode' => array(
+        'description' => 'Language code, can be 2 or 5 characters, e.g. en, en-US.',
+        'type' => 'varchar',
+        'length' => 12,
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('type', 'langcode'),
+  );
+
+  return $schema;
+}
+
+/**
  * Implementation of hook_install().
  */
 function date_api_install() {
+  drupal_install_schema('date_api');
+
+  // date_api_set_variables can install date_timezone and date_php4.  The
+  // date_timezone_install() function does a module_enable('date_api').  This
+  // means that date_api_enable() can be called before date_api_install()
+  // finishes!  So the date_api schema needs to be installed before this line!
   date_api_set_variables();
+
   $ret = array();
   db_add_field($ret, "users", "timezone_name", array('type' => 'varchar', 'length' => 50, 'not null' => TRUE, 'default' => ''));
   return $ret;
 }
 
+/**
+ * Implementation of hook_enable().
+ */
 function date_api_enable() {
+  /* When module is enabled, build the list of date formats and types.  This
+   * includes those provided by this module and other contrib modules.  As the
+   * date_format tables are created but the schema hasn't been updated, force
+   * a refresh so we can use the schema API. */
+  drupal_get_schema('', TRUE);
+  // Ensure schema has been installed - order of things gets out of sync because
+  // date_api_set_variables() in date_api_install() enables the 'date_timezone'
+  // module, which in return enables the 'date_api' module!
+  if (db_table_exists('date_format_types')) {
+    date_formats_rebuild();
+  }
   date_api_set_variables();
+
 }
 
 /**
@@ -83,6 +209,7 @@ function date_api_uninstall() {
     );
   db_query("DELETE FROM {views_display} WHERE display_plugin IN ('". implode("','", $displays) ."')");
   db_query("DELETE FROM {cache_views}");
+  drupal_uninstall_schema('date_api');
   return $ret;
 }
 
@@ -170,4 +297,17 @@ function date_api_update_6001() {
   }    
   db_query("DELETE FROM {cache} where cid LIKE 'theme_registry%'");
   return $ret;
-}
\ No newline at end of file
+}
+
+function date_api_update_6002() {
+  $ret = array();
+
+  $schema = drupal_get_schema_unprocessed('date_api');
+
+  db_create_table($ret, 'date_format_types', $schema['date_format_types']);
+  db_create_table($ret, 'date_format', $schema['date_format']);
+  db_create_table($ret, 'date_format_locale', $schema['date_format_locale']);
+
+  return $ret;
+}
+
Index: date_api.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/date/date_api.module,v
retrieving revision 1.64.2.5.2.56
diff -u -p -r1.64.2.5.2.56 date_api.module
--- date_api.module	29 Nov 2008 16:22:12 -0000	1.64.2.5.2.56
+++ date_api.module	10 Jan 2009 15:39:27 -0000
@@ -45,6 +45,54 @@ function date_api_init() {
 }
 
 /**
+ * Implementation of hook_menu().
+ */
+function date_api_menu() {
+  $items = array();
+  $items['admin/settings/date-time/formats'] = array(
+    'title' => 'Formats',
+    'description' => 'Allow users to add additional date format types.',
+    'type' => MENU_LOCAL_TASK,
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('date_api_date_formats_form'),
+    'access arguments' => array('administer site configuration'),
+    'weight' => 1,
+  );
+  $items['admin/settings/date-time/delete/%'] = array(
+    'title' => 'Delete date format',
+    'description' => 'Allow users to delete a configured date format.',
+    'type' => MENU_CALLBACK,
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('date_api_delete_format_type_form', 4),
+    'access arguments' => array('administer site configuration'),
+  );
+
+  return $items;
+}
+
+/**
+ * Implementation of hook_menu_alter().
+ */
+function date_api_menu_alter(&$callbacks) {
+  $callbacks['admin/settings/date-time/configure'] = $callbacks['admin/settings/date-time'];
+  $callbacks['admin/settings/date-time/configure']['type'] = MENU_DEFAULT_LOCAL_TASK;
+
+  $callbacks['admin/settings/date-time']['page callback'] = 'date_api_menu_callback';
+  $form = $callbacks['admin/settings/date-time']['page arguments'][0];
+  $callbacks['admin/settings/date-time']['page arguments'] = array('drupal_get_form', $form);
+}
+
+/**
+ * Wrapper function to be able to set menu callbacks.
+ */
+function date_api_menu_callback() {
+  $args = func_get_args();
+  $function = array_shift($args);
+  return call_user_func_array($function, $args);
+}
+
+
+/**
  * Helper function for getting the format string for a date type.
  */
 function date_type_format($type) {
@@ -356,42 +404,28 @@ function date_ampm($required = FALSE) {
 }
 
 /**
- * An array of short date formats.
- *
- * @return array an array of short date format strings.
- */
-function date_short_formats() {
-  return array(
-    'Y-m-d H:i',    'm/d/Y - H:i',  'd/m/Y - H:i', 'Y/m/d - H:i',
-    'd.m.Y - H:i',  'm/d/Y - g:ia', 'd/m/Y - g:ia', 'Y/m/d - g:ia',
-    'M j Y - H:i',  'j M Y - H:i',  'Y M j - H:i',
-    'M j Y - g:ia', 'j M Y - g:ia', 'Y M j - g:ia');
-}
-
-/**
- * An array of medium date formats.
+ * Implementation of hook_date_formats().
  *
- * @return array an array of medium date format strings.
+ * @return
+ *   An array of date formats with attributes 'type' (short, medium or long),
+ *   'format' (the format string) and 'locales'.  The 'locales' attribute is an
+ *   array of locales, which can include both 2 character language codes like
+ *   'en', 'fr', but also 5 character language codes like 'en-gb' and 'en-us'.
  */
-function date_medium_formats() {
-  return array(
-    'D, Y-m-d H:i',    'D, m/d/Y - H:i',  'D, d/m/Y - H:i',
-    'D, Y/m/d - H:i',  'F j, Y - H:i',    'j F, Y - H:i',
-    'Y, F j - H:i',    'D, m/d/Y - g:ia', 'D, d/m/Y - g:ia',
-    'D, Y/m/d - g:ia', 'F j, Y - g:ia',   'j F Y - g:ia',
-    'Y, F j - g:ia',   'j. F Y - G:i');
+function date_api_date_formats() {
+  include_once('./'. drupal_get_path('module', 'date_api') .'/date_api_formats_list.inc');
+  return _date_api_date_formats_list();
 }
 
 /**
- * An array of long date formats.
- *
- * @return array an array of long date format strings.
+ * Implementation of hook_date_format_types().
  */
-function date_long_formats() {
+function date_api_date_format_types() {
   return array(
-    'l, F j, Y - H:i',  'l, j F, Y - H:i', 'l, Y,  F j - H:i',
-    'l, F j, Y - g:ia', 'l, j F Y - g:ia', 'l, Y,  F j - g:ia',
-    'l, j. F Y - G:i');
+    'long' => t('Long'),
+    'medium' => t('Medium'),
+    'short' => t('Short'),
+  );
 }
 
 /**
@@ -586,9 +620,11 @@ function date_format_date($object, $type
   }
   switch ($type) {
     case 'small':
+    case 'short':
       $format = variable_get('date_format_short', 'm/d/Y - H:i');
       break;
     case 'large':
+    case 'long':
       $format = variable_get('date_format_long', 'l, F j, Y - H:i');
       break;
     case 'custom':
@@ -1514,6 +1550,319 @@ function date_api_views_fetch_fields($ba
 }
 
 /**
+ * Get the list of date formats for a particular format length.
+ *
+ * @param $type
+ *   The format type: 'short', 'medium', 'long', 'custom'.  If empty, then all
+ *   available formats will be returned.
+ * @param $reset
+ *   Whether or not to reset this function's internal cache (defaults to FALSE).
+ * @return
+ *   Array of date formats.
+ */
+function date_get_formats($type = NULL, $reset = FALSE) {
+  static $_date_formats;
+
+  if ($reset || !isset($_date_formats)) {
+    $_date_formats = array();
+    $_date_formats = _date_formats_build();
+  }
+
+  return $type ? (isset($_date_formats[$type]) ? $_date_formats[$type] : FALSE) : $_date_formats;
+}
+
+/**
+ * Get the list of available date format types and attributes.
+ *
+ * @param $type
+ *   The format type: 'short', 'medium', 'long', 'custom'.  If empty, then all
+ *   attributes for that type will be returned.
+ * @param $reset
+ *   Whether or not to reset this function's internal cache (defaults to FALSE).
+ * @return
+ *   Array of date format types.
+ */
+function date_get_format_types($type = NULL, $reset = FALSE) {
+  static $_date_format_types;
+
+  if ($reset || !isset($_date_format_types)) {
+    $_date_format_types = array();
+    $_date_format_types = _date_format_types_build();
+  }
+
+  return $type ? (isset($_date_format_types[$type]) ? $_date_format_types[$type] : FALSE) : $_date_format_types;
+}
+
+
+/**
+ * Implementation of hook_flush_caches().
+ */
+function date_api_flush_caches() {
+  // Rebuild list of date formats.
+  date_formats_rebuild();
+  return array();
+}
+
+/**
+ * Resets the database cache of date formats, and saves all new date formats to
+ * the database.
+ */
+function date_formats_rebuild() {
+  $date_formats = date_get_formats(NULL, TRUE);
+
+  foreach ($date_formats as $format_type => $formats) {
+    foreach ($formats as $format => $info) {
+      date_format_save($info);
+    }
+  }
+
+  // Rebuild configured date formats locale list.
+  date_format_locale(NULL, NULL, TRUE);
+
+  _date_formats_build();
+}
+
+/**
+ * Save a date format type to the database.
+ *
+ * @param $date_format_type
+ *   An array of attributes for a date format type.
+ */
+function date_format_type_save($date_format_type) {
+  $type = array();
+  $type['type'] = $date_format_type['type'];
+  $type['title'] = $date_format_type['title'];
+  $type['system_type'] = $date_format_type['system_type'];
+
+  // Update date_format table.
+  if (isset($date_format_type['is_new']) && !empty($date_format_type['is_new'])) {
+    drupal_write_record('date_format_types', $type);
+  }
+  else {
+    drupal_write_record('date_format_types', $type, 'type');
+  }
+}
+
+
+/**
+ * Save a date format to the database.
+ *
+ * @param $date_format
+ *   An array of attributes for a date format.
+ */
+function date_format_save($date_format) {
+  $format = array();
+  $format['type'] = $date_format['type'];
+  $format['format'] = $date_format['format'];
+
+  // Update date_format table.
+  if (isset($date_format['is_new']) && !empty($date_format['is_new'])) {
+    drupal_write_record('date_format', $format);
+  }
+  else {
+    drupal_write_record('date_format', $format, 'format');
+  }
+
+  $languages = language_list('enabled');
+  $languages = $languages[1];
+  // If site_country module is enabled, add country specific languages to
+  // languages array.
+  if (module_exists('site_country')) {
+    $country_code = variable_get('site_country_default_country', '');
+    if (!empty($country_code)) {
+      foreach ($languages as $langcode => $details) {
+        $country_language = $langcode . '-' . $country_code;
+        if (drupal_strlen($langcode) == 2 && !in_array($country_language, array_keys($languages))) {
+          $name = $details->name;
+          $languages[$country_language] = "$name ($country_code)";
+        }
+      }
+    }
+  }
+
+  $locale_format = array();
+  $locale_format['type'] = $date_format['type'];
+  $locale_format['format'] = $date_format['format'];
+
+  // Check if the suggested language codes are configured and enabled.
+  foreach ($date_format['locales'] as $langcode) {
+    // Only proceed if language is enabled.
+    if (in_array($langcode, $languages)) {
+      $is_existing = db_result(db_query("SELECT COUNT(*) FROM {date_format_locale} WHERE type = '%s' AND langcode = '%s'", $date_format['type'], $langcode));
+      if (!$is_existing) {
+        $locale_format['langcode'] = $langcode;
+        drupal_write_record('date_format_locale', $locale_format);
+      }
+    }
+  }
+}
+
+/**
+ * Builds and returns the list of available date format types.
+ *
+ * @return
+ *   Array of date format types.
+ */
+function _date_format_types_build() {
+  $types = array();
+
+  // Get list of modules which 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['system_type'] = 1;
+      $type['is_new'] = TRUE; // Will be over-ridden later if in the db.
+      $types[$module_type] = $type;
+    }
+  }
+
+  // Get custom formats added to the database by the end user.
+  $result = db_query('SELECT dft.type, dft.title, dft.system_type FROM {date_format_types} dft ORDER BY dft.title');
+  while ($object = db_fetch_object($result)) {
+    if (!in_array($object->type, $types)) {
+      $type = array();
+      $type['is_new'] = FALSE;
+      $type['module'] = '';
+      $type['type'] = $object->type;
+      $type['title'] = $object->title;
+      $type['system_type'] = $object->system_type;
+      $types[$object->type] = $type;
+    }
+    else {
+        $type = array();
+        $type['is_new'] = FALSE;  // Over-riding previous setting.
+        $types[$object->type] = array_merge($types[$object->type], $type);
+    }
+  }
+
+  // Allow other modules to modify these format types.
+  drupal_alter('date_format_types', $types);
+
+  return $types;
+}
+
+/**
+ * Builds and returns the list of available date formats.
+ *
+ * @return
+ *   Array of date formats.
+ */
+function _date_formats_build() {
+  $date_formats = array();
+
+  // First handle hook_date_format_types().
+  $types = _date_format_types_build();
+  foreach ($types as $type => $info) {
+    date_format_type_save($info);
+  }
+
+  // Get formats supplied by various contrib modules.
+  $module_formats = module_invoke_all('date_formats');
+
+  foreach ($module_formats as $module_format) {
+    // If no format type is specified, assign 'custom'.
+    if (!isset($module_format['type'])) {
+      $module_format['type'] = 'custom';
+    }
+    if (!in_array($module_format['type'], array_keys($types))) {
+      continue;
+    }
+    if (!isset($date_formats[$module_format['type']])) {
+      $date_formats[$module_format['type']] = array();
+    }
+
+    // If another module already set this format, merge in the new settings.
+    if (isset($date_formats[$module_format['type']][$module_format['format']])) {
+      $date_formats[$module_format['type']][$module_format['format']] = array_merge_recursive($date_formats[$module_format['type']][$module_format['format']], $format);
+    }
+    else {
+      // This setting will be overridden later if it already exists in the db.
+      $module_format['is_new'] = TRUE;
+      $date_formats[$module_format['type']][$module_format['format']] = $module_format;
+    }
+  }
+
+  // Get custom formats added to the database by the end user.
+  $result = db_query('SELECT df.format, df.type, dfl.langcode FROM {date_format} df LEFT JOIN {date_format_types} dft ON df.type = dft.type LEFT JOIN {date_format_locale} dfl ON df.format = dfl.format AND df.type = dfl.type WHERE dft.type IS NOT NULL ORDER BY df.type, df.format');
+  while ($object = db_fetch_object($result)) {
+    // If this format type isn't set, initialise the array.
+    if (!isset($date_formats[$object->type])) {
+      $date_formats[$object->type] = array();
+    }
+    // If this format not already present, add it to the array.
+    if (!isset($date_formats[$object->type][$object->format])) {
+      // We don't set 'is_new' as it is already in the db.
+      $format = array();
+      $format['module'] = '';
+      $format['format'] = $object->format;
+      $format['type'] = $object->type;
+      $format['locales'] = array($object->langcode);
+      $date_formats[$object->type][$object->format] = $format;
+    }
+    // Format already present, so merge in settings.
+    else {
+      $format = array();
+      $format['is_new'] = FALSE; // It's in the db, so override this setting.
+      $format['format'] = $object->format;
+      $format['type'] = $object->type;
+      if (!empty($object->langcode)) {
+        $format['locales'] = array_merge($date_formats[$object->type][$object->format]['locales'], array($object->langcode));
+      }
+      $date_formats[$object->type][$object->format] = array_merge($date_formats[$object->type][$object->format], $format);
+    }
+  }
+
+  // Allow other modules to modify these formats.
+  drupal_alter('date_formats', $date_formats);
+
+  return $date_formats;
+}
+
+
+/**
+ * Get the appropriate date format for a type and locale.
+ *
+ * @param $langcode
+ *   Language code for the current locale.  This can be a 2 character language
+ *   code like 'en', 'fr', or a longer 5 character code like 'en-gb'.
+ * @param $type
+ *   Date format type: short, medium, long, custom.
+ * @param $reset
+ *   Whether or not to reset this function's internal cache (defaults to FALSE).
+ * @return
+ *   The format string, or NULL if no matching format found.
+ */
+function date_format_locale($langcode = NULL, $type = NULL, $reset = FALSE) {
+  static $formats;
+  
+  if ($reset || empty($formats)) {
+    $formats = array();
+    $result = db_query("SELECT format, type, langcode FROM {date_format_locale}");
+    while ($object = db_fetch_object($result)) {
+      if (!isset($formats[$object->langcode])) {
+        $formats[$object->langcode] = array();
+      }
+      $formats[$object->langcode][$object->type] = $object->format;
+    }
+  }
+
+  if ($type && $langcode && !empty($formats[$langcode][$type])) {
+    return $formats[$langcode][$type];
+  }
+  elseif ($langcode && !empty($formats[$langcode])) {
+    return $formats[$langcode];
+  }
+
+  return FALSE;
+}
+
+/**
  * Store personalized format options for each user.
  *
  * Store to avoid work of re-creating it over and over,
@@ -1527,19 +1876,21 @@ function date_format_options() {
   $cached = cache_get('date_format_options:'. $user->uid);
   $options = isset($cached->data) ? $cached->data : array();
   if (empty($options)) {
-    $formats = array_merge(date_short_formats(), date_medium_formats(), date_long_formats());
+    $formats = date_get_formats();
     $options = array();
     $now = date_example_date();
     if (!empty($now)) {
-      foreach ($formats as $format) {
-        // Create an option that shows date only without time, along with the
-        // default string which has both date and time.
-        $no_time = date_limit_format($format, array('month', 'day', 'year'));
-        $zones = array('', 'O', 'P', 'e');
-        foreach ($zones as $zone) {
-          $time_format = !empty($zone) ? $format .' '. $zone : $format;
-          $options[$no_time] = date_format_date($now, 'custom', $no_time);
-          $options[$time_format] = date_format_date($now, 'custom', $time_format);
+      foreach ($formats as $type => $format_types) {
+        foreach ($format_types as $format => $format_attributes) {
+          // Create an option that shows date only without time, along with the
+          // default string which has both date and time.
+          $no_time = date_limit_format($format, array('month', 'day', 'year'));
+          $zones = array('', 'O', 'P', 'e');
+          foreach ($zones as $zone) {
+            $time_format = !empty($zone) ? $format .' '. $zone : $format;
+            $options[$no_time] = date_format_date($now, 'custom', $no_time);
+            $options[$time_format] = date_format_date($now, 'custom', $time_format);
+          }
         }
       }
       asort($options);
@@ -1717,4 +2068,190 @@ function date_api_schema_alter(&$schema)
     'default' => '',
     'description' => t('Per-user timezone name.'),
   );
-}
\ No newline at end of file
+}
+
+/**
+ * Implementation of hook_form_alter().
+ *
+ * Add new submit handler for system_modules form.
+ */
+function date_api_form_system_modules_alter(&$form, $form_state, $form_id = 'system_modules') {
+  $form['#submit'][] = 'date_api_system_modules_submit';
+}
+
+/**
+ * Rebuild list of date formats when modules list is saved.
+ */
+function date_api_system_modules_submit($form, &$form_state) {
+  date_formats_rebuild();
+}
+
+/**
+ * Implementation of hook_form_alter().
+ *
+ * Add in additional date format handling.
+ */
+function date_api_form_system_date_time_settings_alter(&$form, $form_state, $form_id = 'system_date_time_settings') {
+  $form['date_formats'] = NULL;
+}
+
+/**
+ * Allow users to configure additional date format types.
+ */
+function date_api_date_formats_form($form_state) {
+  drupal_add_js(drupal_get_path('module', 'system') .'/system.js', 'module');
+  drupal_add_js(array('dateTime' => array('lookup' => url('admin/settings/date-time/lookup'))), 'setting');
+
+  $form = array();
+
+  // Display existing format types and their formats.
+  date_api_date_format_form_elements($form);
+
+  $form = system_settings_form($form);
+  // We will call system_settings_form_submit() manually, so remove it for now.
+  unset($form['#submit']);
+
+  return $form;
+}
+
+/**
+ * Add drop down selects for date format types.
+ *
+ * @param &$form
+ *   The form being altered.
+ */
+function date_api_date_format_form_elements(&$form) {
+  $form['date_formats'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Date formats'),
+  );
+
+  // Get list of all available date format types.
+  $format_types = date_get_format_types('', TRUE);
+
+  // Get list of all available date formats.
+  $all_formats = array();
+  $date_formats = date_get_formats('', TRUE);
+  foreach ($date_formats as $type => $format_info) {
+    $all_formats = array_merge($all_formats, $format_info);
+  }
+
+  foreach ($format_types as $type => $type_info) {
+    // If a system type, only show the available formats for that type.
+    if ($type_info['system_type'] == 1) {
+      $formats = date_get_formats($type);
+      if (empty($formats)) {
+        $formats = $all_formats;
+      }
+    }
+    // If a user configured type, show all available date formats.
+    else {
+      $formats = $all_formats;
+    }
+
+    $choices = array();
+    foreach ($formats as $f => $format) {
+      $choices[$f] = format_date(time(), 'custom', $f);
+    }
+    $choices['custom'] = t('Custom format');
+    $default = variable_get('date_format_' . $type, array_shift(array_keys($formats)));
+
+    // Get format type info for this format type.
+    $type_info = date_get_format_types($type);
+
+    date_api_date_format_select_field($form, $type, $type_info, $default, $choices, 1);
+  }
+}
+
+/**
+ * Process date_api_date_formats_form form submissions.
+ */
+function date_api_date_formats_form_submit($form, &$form_state) {
+  // Get list of all available date format types.
+  $format_types = date_get_format_types('', TRUE);
+  foreach ($format_types as $type => $type_info) {
+    if ($form_state['values']['date_format_' . $type] == 'custom') {
+      $form_state['values']['date_format_' . $type] = $form_state['values']['date_format_' . $type .'_custom'];
+    }
+  }
+  return system_settings_form_submit($form, $form_state);
+}
+
+/**
+ * Menu callback; present a form for deleting a date format type.
+ */
+function date_api_delete_format_type_form(&$form_state, $format_type) {
+  $form = array();
+  $form['format_type'] = array(
+    '#type' => 'value',
+    '#value' => $format_type,
+  );
+
+  $type_info = date_get_format_types($format_type);
+
+  $output = confirm_form($form,
+    t('Are you sure you want to remove the format type %format?', array('%format' => $type_info['title'])),
+    'admin/settings/date-time/formats',
+    t('This action cannot be undone.'),
+    t('Remove'), t('Cancel'),
+    'confirm'
+  );
+
+  return $output;
+}
+
+/**
+ * Delete a configured date format type.
+ */
+function date_api_delete_format_type_form_submit($form, &$form_state) {
+  if ($form_state['values']['confirm']) {
+    $type_info = date_get_format_types($form_state['values']['format_type']);
+
+    db_query("DELETE FROM {date_format} WHERE type = '%s'", $form_state['values']['format_type']);
+    db_query("DELETE FROM {date_format_types} WHERE type = '%s'", $form_state['values']['format_type']);
+    db_query("DELETE FROM {date_format_locale} WHERE type = '%s'", $form_state['values']['format_type']);
+
+    drupal_set_message(t('Removed date format %format.', array('%format' => $type_info['title'])));
+    $form_state['redirect'] = 'admin/settings/date-time/formats';
+  }
+}
+
+/**
+ * Helper function; return form fields for date format selects.
+ */
+function date_api_date_format_select_field(&$form, $type, $type_info, $default, $choices, $show_remove = 0) {
+  // Show date format select list.
+  $form['date_formats']['date_format_' . $type] = array(
+    '#prefix' => '<div class="date-container"><div class="select-container">',
+    '#suffix' => '</div>',
+    '#type' => 'select',
+    '#title' => t('!type date format', array('!type' => $type_info['title'])),
+    '#attributes' => array('class' => 'date-format'),
+    '#default_value' => (isset($choices[$default]) ? $default : 'custom'),
+    '#options' => $choices,
+  );
+
+  // If a custom entered format is being used, then show textfield.
+  $default_custom = variable_get('date_format_' . $type . '_custom', (isset($choices[$default]) ? $default : ''));
+  $default_custom = (!isset($choices[$default]) ? $default : $default_custom);
+  $form['date_formats']['date_format_' . $type . '_custom'] = array(
+    '#prefix' => '<div class="custom-container">',
+    '#suffix' => ($show_remove == 1 && $type_info['system_type'] == 0) ? '</div>' : '</div></div>', 
+    '#type' => 'textfield',
+    '#title' => t('Custom !type date format', array('!type' => $type_info['title'])),
+    '#attributes' => array('class' => 'custom-format'),
+    '#default_value' => $default_custom,
+    '#description' => t('A user-defined date format. See the <a href="@url">PHP manual</a> for available options. This format is currently set to display as <span>%date</span>.', array('@url' => 'http://php.net/manual/function.date.php', '%date' => format_date(time(), 'custom', $default_custom))),
+  );
+
+  // If this isn't a system provided type, allow the user to remove it from
+  // the system.
+  if ($show_remove == 1 && $type_info['system_type'] == 0) {
+    $form['date_formats']['date_format_' . $type . '_delete'] = array(
+      '#prefix' => '<div class="date-format-delete">',
+      '#suffix' => '</div></div>', 
+      '#value' => l(t('remove'), 'admin/settings/date-time/delete/' . $type),
+    );
+  }
+}
+
Index: date_api_formats_list.inc
===================================================================
RCS file: date_api_formats_list.inc
diff -N date_api_formats_list.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ date_api_formats_list.inc	10 Jan 2009 15:39:27 -0000
@@ -0,0 +1,193 @@
+<?php
+// $Id$
+/**
+ * @file
+ * Initialize the list of date formats and their locales.
+ */
+
+function _date_api_date_formats_list() {
+  $formats = array();
+
+  // Short date formats.
+  $formats[] = array(
+    'type' => 'short',
+    'format' => 'Y-m-d H:i',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'short',
+    'format' => 'm/d/Y - H:i',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'short',
+    'format' => 'd/m/Y - H:i',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'short',
+    'format' => 'Y/m/d - H:i',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'short',
+    'format' => 'd.m.Y - H:i',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'short',
+    'format' => 'm/d/Y - g:ia',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'short',
+    'format' => 'd/m/Y - g:ia',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'short',
+    'format' => 'Y/m/d - g:ia',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'short',
+    'format' => 'M j Y - H:i',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'short',
+    'format' => 'j M Y - H:i',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'short',
+    'format' => 'Y M j - H:i',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'short',
+    'format' => 'M j Y - g:ia',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'short',
+    'format' => 'j M Y - g:ia',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'short',
+    'format' => 'Y M j - g:ia',
+    'locales' => array(),
+  );
+
+  // Medium date formats.
+  $formats[] = array(
+    'type' => 'medium',
+    'format' => 'D, Y-m-d H:i',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'medium',
+    'format' => 'D, m/d/Y - H:i',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'medium',
+    'format' => 'D, d/m/Y - H:i',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'medium',
+    'format' => 'D, Y/m/d - H:i',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'medium',
+    'format' => 'F j, Y - H:i',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'medium',
+    'format' => 'j F, Y - H:i',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'medium',
+    'format' => 'Y, F j - H:i',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'medium',
+    'format' => 'D, m/d/Y - g:ia',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'medium',
+    'format' => 'D, d/m/Y - g:ia',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'medium',
+    'format' => 'D, Y/m/d - g:ia',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'medium',
+    'format' => 'F j, Y - g:ia',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'medium',
+    'format' => 'j F Y - g:ia',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'medium',
+    'format' => 'Y, F j - g:ia',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'medium',
+    'format' => 'j. F Y - G:i',
+    'locales' => array(),
+  );
+
+  // Long date formats.
+  $formats[] = array(
+    'type' => 'long',
+    'format' => 'l, F j, Y - H:i',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'long',
+    'format' => 'l, j F, Y - H:i',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'long',
+    'format' => 'l, Y,  F j - H:i',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'long',
+    'format' => 'l, F j, Y - g:ia',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'long',
+    'format' => 'l, j F Y - g:ia',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'long',
+    'format' => 'l, Y,  F j - g:ia',
+    'locales' => array(),
+  );
+  $formats[] = array(
+    'type' => 'long',
+    'format' => 'l, j. F Y - G:i',
+    'locales' => array(),
+  );
+
+  return $formats;
+}
Index: date/date.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/date/date/date.module,v
retrieving revision 1.61.2.4.2.39
diff -u -p -r1.61.2.4.2.39 date.module
--- date/date.module	6 Jan 2009 22:48:31 -0000	1.61.2.4.2.39
+++ date/date.module	10 Jan 2009 15:39:29 -0000
@@ -15,7 +15,9 @@ function date_init() {
     require_once('./'. drupal_get_path('module', 'date') .'/date_token.inc');
   }
 }
-
+/**
+ * Implementation of hook_menu().
+ */
 function date_menu() {
   $items = array();
   // Repeat dates tab on node
@@ -30,6 +32,7 @@ function date_menu() {
     'access arguments' => array(1),
     'type' => MENU_LOCAL_TASK, 
   );
+
   return $items;  
 }
 
@@ -210,7 +213,7 @@ function date_input_value($field, $eleme
  * Implementation of hook_field_formatter_info().
  */
 function date_field_formatter_info() {
-  return array(
+  $formatters = array(
     'default' => array('label' => t('Default'),
       'field types' => array('date', 'datestamp', 'datetime'),
       'multiple values' => CONTENT_HANDLE_CORE),
@@ -245,13 +248,29 @@ function date_field_formatter_info() {
       'field types' => array('date', 'datestamp', 'datetime'),
       'multiple values' => CONTENT_HANDLE_CORE),
   );
+
+  $system_formats = array('long', 'medium', 'short');
+  $format_types = date_get_format_types('', TRUE);
+  if (!empty($format_types)) {
+    foreach ($format_types as $type => $type_info) {
+      if (!in_array($type, $system_formats)) {
+        $formatters[$type] = array(
+          'label' => $type_info['title'], // @todo translate this?
+          'field types' => array('date', 'datestamp', 'datetime'),
+          'multiple values' => CONTENT_HANDLE_CORE
+        );
+      }
+    }
+  }
+
+  return $formatters;
 }
 
 /**
  * Implementation of hook_theme().
  */
 function date_theme() {
-  return array(
+  $themes = array(
     'date_combo' => array(
       'arguments' => array('element' => NULL)),
     'date_all_day' => array(
@@ -303,6 +322,21 @@ function date_theme() {
       'function' => 'theme_date_repeat_display',
       ),  
   );
+
+  $system_formats = array('long', 'medium', 'short');
+  $format_types = date_get_format_types('', TRUE);
+  if (!empty($format_types)) {
+    foreach ($format_types as $type => $type_info) {
+      if (!in_array($type, $system_formats)) {
+        $themes['date_formatter_' . $type] = array(
+          'arguments' => array('element' => NULL), 
+          'function' => 'theme_date_display_combination',
+        );
+      }
+    }
+  }
+
+  return $themes;
 }
 
 /**
@@ -556,12 +590,13 @@ function date_formatter_format($formatte
     case 'medium':
     case 'short':
     case 'default':
+    default:
       $custom = 'output_format_custom'. ($formatter != 'default' ? '_'. $formatter : '');
       $value = 'output_format_date'. ($formatter != 'default' ? '_'. $formatter : '');
       if ($field[$custom] > '') {
         $format = $field[$custom];
       }
-      elseif ($field[$value]) {
+      elseif ($field[$value] && !module_exists('date_locale')) {
         $format = $field[$value];
       }
       else {
@@ -572,9 +607,15 @@ function date_formatter_format($formatte
           case 'medium':
             $format = variable_get('date_format_medium',  'D, m/d/Y - H:i');
             break;
-          default:
+          case 'short':
             $format = variable_get('date_format_short', 'm/d/Y - H:i');
             break;
+          default:
+            $format = variable_get('date_format_' . $formatter, '');
+            if (empty($format)) {
+              $format = variable_get('date_format_short', 'm/d/Y - H:i');
+            }
+            break;
         }
       }
       break;
@@ -715,3 +756,70 @@ function date_handler_fields($view) {
   return $handler;
 }
 
+/**
+ * Implementation of hook_form_alter().
+ *
+ * Adding ability to configure new date format types.
+ */
+function date_form_date_api_date_formats_form_alter(&$form, $form_state, $form_id = 'date_api_date_formats_form') {
+  // Add form entry field for adding new format type.
+  $form['add_format'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Add format type'),
+    '#weight' => 1,
+  );
+  $form['add_format']['add_date_format_title'] = array(
+    '#title' => t('Name'),
+    '#description' => t('The human-readable name for this format type.'),
+    '#type' => 'textfield',
+    '#size' => 20,
+    '#prefix' => '<div class="date-container"><div class="date-format-name">',
+    '#suffix' => '</div>',
+  );
+  $form['add_format']['add_date_format_type'] = array(
+    '#title' => t('Type'),
+    '#description' => t('The machine-readable name of this format type. <br>This name must contain only lowercase letters, numbers, and underscores and must be unique.'),
+    '#type' => 'textfield',
+    '#size' => 20,
+    '#prefix' => '<div class="date-format-type">',
+    '#suffix' => '</div></div>',
+  );
+
+  $form['#submit'][] = 'date_date_time_settings_submit';
+  $form['#validate'][] = 'date_date_time_settings_validate';
+  $form['buttons']['#weight'] = 2;
+}
+
+/**
+ * Validate new date format type details.
+ */
+function date_date_time_settings_validate($form, &$form_state) {
+  if (!empty($form_state['values']['add_date_format_type']) && !empty($form_state['values']['add_date_format_title'])) {
+    if (!preg_match("/^[a-zA-Z0-9_]+$/", $form_state['values']['add_date_format_type'])) {
+      form_set_error('add_date_format_type', t('The format type must contain only alphanumeric characters and underscores.'));
+    }
+    $types = date_get_format_types();
+    if (in_array($form_state['values']['add_date_format_type'], array_keys($types))) {
+      form_set_error('add_date_format_type', t('This format type already exists.  Please enter a unique type.'));
+    }
+  }
+}
+
+/**
+ * Save date format(s) to database.
+ */
+function date_date_time_settings_submit($form, &$form_state) {
+  if (!empty($form_state['values']['add_date_format_type']) && !empty($form_state['values']['add_date_format_title'])) {
+    $format_type = array();
+    $format_type['title'] = $form_state['values']['add_date_format_title'];
+    $format_type['type'] = $form_state['values']['add_date_format_type'];
+    $format_type['system_type'] = 0;
+    $format_type['is_new'] = 1;
+    date_format_type_save($format_type);
+  }
+
+  // Unset, to prevent this getting saved as a variables.
+  unset($form_state['values']['add_date_format_type']);
+  unset($form_state['values']['add_date_format_title']);
+}
+
Index: date/date_admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/date/date/date_admin.inc,v
retrieving revision 1.40.2.3.2.26
diff -u -p -r1.40.2.3.2.26 date_admin.inc
--- date/date_admin.inc	13 Dec 2008 23:31:11 -0000	1.40.2.3.2.26
+++ date/date_admin.inc	10 Jan 2009 15:39:29 -0000
@@ -107,7 +107,7 @@ function date_widget_settings_form($widg
   }
   else {
     // example input formats must show all possible date parts, so add seconds.
-    $formats = str_replace('i', 'i:s', date_short_formats());
+    $formats = str_replace('i', 'i:s', array_keys(date_get_formats('short')));
     $formats = drupal_map_assoc($formats);
     $default_format = str_replace('i', 'i:s', variable_get('date_format_short', 'm/d/Y - H:i'));
   }
@@ -251,24 +251,16 @@ function _date_field_settings($op, $fiel
     case 'save':
 
       $options = array('granularity', 'timezone_db', 'tz_handling', 'todate', 'repeat', 'repeat_collapsed');
-      for ($i = 0; $i <= 3; $i++) {
-        switch ($i) {
-        case(1):
-          $name = 'long';
-          break;
-        case(2):
-          $name = 'medium';
-          break;
-        case(3):
-          $name = 'short';
-          break;
-        default:
-          $name = 'default';
+      $format_types = date_get_format_types();
+      if (!empty($format_types)) {
+        foreach ($format_types as $type => $type_info) {
+          $options[] = 'output_format_date_'. $type;
+          $options[] = 'output_format_custom_'. $type;
         }
-        $append = ($i > 0 ? '_'. $name : '');
-        $options[] = 'output_format_date'. $append;
-        $options[] = 'output_format_custom'. $append;
       }
+      $options[] = 'output_format_date';
+      $options[] = 'output_format_custom';
+
       return $options;
 
     case 'database columns':
@@ -372,10 +364,14 @@ function date_field_settings_form($field
     '#type' => 'fieldset', '#title' => t('Additional Display Settings'),
     '#collapsible' => TRUE,
     '#collapsed' => TRUE,
-    '#description' => t('Options other than the default are made available to views and themes. Possible formats are default, long, medium, and short.'),
+    '#description' => t('Options other than the default are made available to views and themes. Possible formats include default, long, medium, and short.'),
   );
-  for ($i = 1; $i <= 3; $i++) {
-    $form['output']['advanced'][$i] = date_formatter_setup_form($field, $i);
+
+  $format_types = date_get_format_types();
+  if (!empty($format_types)) {
+    foreach ($format_types as $type => $type_info) {
+      $form['output']['advanced'][$type] = date_formatter_setup_form($field, $type);
+    }
   }
   $description = t('Select the timezone handling method to be used for this date field.');
   $description .= date_data_loss_warning('Time zone handling');
@@ -432,6 +428,7 @@ function date_data_loss_warning($name) {
  */
 function date_formatter_setup_form($field, $delta) {
 
+  $format_types = date_get_format_types();
   switch ($delta) {
   case(1):
     $name = 'long';
@@ -449,11 +446,21 @@ function date_formatter_setup_form($fiel
     $default = variable_get('date_format_short', 'm/d/Y - H:i');
     break;
   default:
-    $name = 'default';
-    $label = t('Default');
-    $default = variable_get('date_format_short', 'm/d/Y - H:i');
+    if (!empty($format_types) && isset($format_types[$delta])) {
+      $name = $delta;
+      $label = $format_types[$delta]['title'];
+      $default = variable_get('date_format_' . $delta, 'm/d/Y - H:i');
+      if (empty($default)) {
+        $default = variable_get('date_format_short', 'm/d/Y - H:i');
+      }
+    }
+    else {
+      $name = 'default';
+      $label = t('Default');
+      $default = variable_get('date_format_short', 'm/d/Y - H:i');
+    }
   }
-  $append = ($delta > 0 ? '_'. $name : '');
+  $append = ($delta == 0 ? '_'. $delta : '');
   $form = array(
     '#type' => 'fieldset', '#title' => $label,
     );
@@ -625,4 +632,4 @@ function date_field_default_values($fiel
   $field['db_storage'] = content_storage_type($field);
   
   return $field;
-}
\ No newline at end of file
+}
Index: date_locale/date_locale.info
===================================================================
RCS file: date_locale/date_locale.info
diff -N date_locale/date_locale.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ date_locale/date_locale.info	10 Jan 2009 15:39:29 -0000
@@ -0,0 +1,6 @@
+; $Id$
+name = Date Locale
+description = Allows the site admin to configure multiple formats for date/time display to taylor dates for a specific locale or audience.
+package = Date/Time
+dependencies[] = date_api
+core = 6.x
Index: date_locale/date_locale.install
===================================================================
RCS file: date_locale/date_locale.install
diff -N date_locale/date_locale.install
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ date_locale/date_locale.install	10 Jan 2009 15:39:29 -0000
@@ -0,0 +1,6 @@
+<?php
+// $Id$
+
+function date_locale_install() {
+}
+
Index: date_locale/date_locale.module
===================================================================
RCS file: date_locale/date_locale.module
diff -N date_locale/date_locale.module
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ date_locale/date_locale.module	10 Jan 2009 15:39:29 -0000
@@ -0,0 +1,296 @@
+<?php
+// $Id$
+/**
+ * @file
+ * Enable different locales to have their own date formats.
+ */
+
+/**
+ * Implementation of hook_init().
+ *
+ * Initialize date formats according to the user's current locale.
+ */
+function date_locale_init() {
+  global $conf;
+  global $language;
+  // Don't do this on the general date and time formats settings page, as we
+  // want to display the defaults, not the ones specific to the language we're
+  // currently browsing the site in.
+  if (!drupal_match_path($_GET['q'], 'admin/settings/date-time/formats')) {
+    $languages = array($language->language);
+    if (module_exists('site_country')) {
+      $country_code = variable_get('site_country_default_country', '');
+      if (!empty($country_code)) {
+        $country_language = $language->language . '-' . $country_code;
+        array_unshift($languages, $country_language);
+      }
+    }
+    drupal_alter('date_format_languages', $languages);
+
+    // Setup appropriate date formats for this locale.
+    $formats = date_locale_get_locale_date_format($languages);
+    foreach ($formats as $format_type => $format) {
+      $conf[$format_type] = $format;
+    }
+  }
+}
+
+/**
+ * Implementation of hook_menu().
+ */
+function date_locale_menu() {
+  $items = array();
+  $items['admin/settings/date-time/locale'] = array(
+    'title' => 'Locale date settings',
+    'description' => 'Configure date formats for each locale',
+    'type' => MENU_LOCAL_TASK,
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('date_locale_format_form'),
+    'access arguments' => array('administer site configuration'),
+    'weight' => 1,
+  );
+  return $items;
+}
+
+/**
+ * Write a record to the date_format_locale table.
+ *
+ * @param $type
+ *   Date format type, e.g. 'short', 'medium', 'large'.
+ * @param $langcode
+ *   Language code.
+ * @param $format
+ *   Date format string.
+ */
+function date_locale_write_locale_record($type, $langcode, $format) {
+  $primary_keys = array('langcode', 'type');
+
+  $date_format = new stdClass();
+  $date_format->langcode = $langcode;
+  $date_format->type = $type;
+  $date_format->format = $format;
+  $is_existing = db_result(db_query("SELECT COUNT(*) FROM {date_format_locale} dfl WHERE dfl.type = '%s' AND dfl.langcode = '%s'", $type, $langcode));
+  if ($is_existing) {
+    drupal_write_record('date_format_locale', $date_format, $primary_keys);
+  }
+  else {
+    drupal_write_record('date_format_locale', $date_format);
+  }
+}
+
+/**
+ * Select locale date format details from database.
+ *
+ * @param $languages
+ *   An array of language codes.
+ * @return
+ *   An array of date formats.
+ */
+function date_locale_get_locale_date_format($languages) {
+  $formats = array();
+
+  // Get list of different format types.
+  $format_types = date_get_format_types();
+  $short_default = variable_get('date_format_short', 'm/d/Y - H:i');
+
+  // Loop through each language until we find one with some date formats
+  // configured.
+  foreach ($languages as $language) {
+    $date_formats = date_format_locale($language);
+    if (!empty($date_formats)) {
+      // We have locale-specific date formats, so check for their types.  If
+      // we're missing a type, use the default setting instead.
+      foreach ($format_types as $type => $type_info) {
+        $format = $date_formats[$type];
+
+        // If format exists for this language, use it.
+        if (!empty($format)) {
+          $formats['date_format_' . $type] = $format;
+        }
+        // Otherwise get default variable setting.  If this is not set, default
+        // to the short format.
+        else {
+          $formats['date_format_' . $type] = variable_get('date_format_' . $type, $short_default);
+        }
+      }
+
+      // Return on the first match.
+      return $formats;
+    }
+  }
+
+  // No locale specific formats found, so use defaults.
+  $system_types = array('short', 'medium', 'long');
+  // Handle system types separately as they have defaults if no variable exists.
+  $formats['date_format_short'] = $short_default;
+  $formats['date_format_medium'] = variable_get('date_format_medium', 'D, m/d/Y - H:i');
+  $formats['date_format_long'] = variable_get('date_format_long', 'l, F j, Y - H:i');
+
+  // For non-system types, get the default setting, otherwise use the short
+  // format.
+  foreach ($format_types as $type => $type_info) {
+    if (!in_array($type, $system_types)) {
+      $formats['date_format_' . $type] = variable_get('date_format_' . $type, $short_default);
+    }
+  }
+
+  return $formats;
+}
+
+/**
+ * Display list of enabled languages to configure date formats for.
+ */
+function date_locale_format_form($form_state) {
+  $form = array();
+
+  if (!isset($form_state['values'])) {
+    $step = 'languages';
+  }
+  else {
+    $step = 'config';
+  }
+  $form['step'] = array(
+    '#type' => 'value',
+    '#value' => $step,
+  );
+
+  // Form part 1: show language selection.
+  if ($step == 'languages') {
+    // Get list of languages.
+    $languages = locale_language_list('native');
+
+    // If site_country module is enabled, add country specific languages to
+    // languages array.
+    if (module_exists('site_country')) {
+      $country_code = variable_get('site_country_default_country', '');
+      if (!empty($country_code)) {
+        foreach ($languages as $langcode => $name) {
+          $country_language = $langcode . '-' . $country_code;
+          if (drupal_strlen($langcode) == 2 && !in_array($country_language, array_keys($languages))) {
+            $languages[$country_language] = "$name ($country_code)";
+          }
+        }
+      }
+    }
+
+    $form['langcode'] = array(
+      '#title' => t('Language'),
+      '#type' => 'select',
+      '#options' => $languages,
+      '#multiple' => false,
+    );
+
+    $form['buttons']['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Search'),
+      '#submit' => array('date_locale_format_form_language_submit'),
+    );
+
+  }
+
+  // Form part 2: show date formats for this language.
+  else {
+    drupal_add_js(drupal_get_path('module', 'system') .'/system.js', 'module');
+    drupal_add_js(array('dateTime' => array('lookup' => url('admin/settings/date-time/lookup'))), 'setting');
+    $langcode = $form_state['values']['langcode'];
+
+    // Get list of date format types.
+    $types = date_get_format_types();
+
+    // Get list of available formats.
+    $formats = date_get_formats();
+    $choices = array();
+    foreach ($formats as $type => $list) {
+      foreach ($list as $f => $format) {
+        $choices[$f] = format_date(time(), 'custom', $f);
+      }
+    }
+    $choices['custom'] = t('Custom format');
+
+    // Get configured formats for each language.
+    $locale_formats = date_format_locale($langcode);
+    // Display a form field for each format type.
+    foreach ($types as $type => $type_info) {
+      if (!empty($locale_formats) && in_array($type, array_keys($locale_formats))) {
+        $default = $locale_formats[$type];
+      }
+      else {
+        $default = variable_get('date_format_' . $type, array_shift(array_keys($formats)));
+      }
+      date_api_date_format_select_field(&$form, $type, $type_info, $default, $choices);
+    }
+
+    $form['buttons']['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Save'),
+      '#submit' => array('date_locale_format_form_formats_submit'),
+    );
+  }
+
+  return $form;
+}
+
+/**
+ * Submit handler for choosing a language on the date_locale_format_form.
+ *
+ * @param $form
+ *   Array, containing the form structure.
+ * @param &$form_state
+ *   The 'rebuild' key inside $form_state['rebuild'] structure, overrides the
+ *   'redirect' key: when it is set to TRUE, the form will be rebuilt from
+ *   scratch and displayed on screen.
+ */
+function date_locale_format_form_language_submit($form, &$form_state) {
+  $form_state['rebuild'] = TRUE;
+  $form_state['storage']['langcode'] = $form_state['values']['langcode'];
+}
+
+/**
+ * Submit handler for choosing a language on the date_locale_format_form.
+ */
+function date_locale_format_form_formats_submit($form, &$form_state) {
+  $langcode = $form_state['storage']['langcode'];
+
+  // Get list of date format types.
+  $types = date_get_format_types();
+  foreach ($types as $type => $type_info) {
+    $format = $form_state['values']['date_format_' . $type];
+    if ($format == 'custom') {
+      $format = $form_state['values']['date_format_' . $type . '_custom'];
+    }
+    date_locale_locale_format_save($langcode, $type, $format);
+  }
+  drupal_set_message(t('Configuration saved.'));
+  $form_state['storage'] = FALSE;
+  $form_state['rebuild'] = FALSE;
+  $form_state['redirect'] = 'admin/settings/date-time/locale';
+}
+
+/**
+ * Save locale specific date formats to the database.
+ *
+ * @param $langcode
+ *   Language code, can be 2 characters, e.g. 'en' or 5 characters, e.g.
+ *   'en-CA'.
+ * @param $type
+ *   Date format type, e.g. 'short', 'medium'.
+ * @param $format
+ *   The date format string.
+ */
+function date_locale_locale_format_save($langcode, $type, $format) {
+  $locale_format = array();
+  $locale_format['langcode'] = $langcode;
+  $locale_format['type'] = $type;
+  $locale_format['format'] = $format;
+
+  $is_existing = db_result(db_query("SELECT COUNT(*) FROM {date_format_locale} WHERE langcode = '%s' AND type = '%s'", $langcode, $type));
+  if ($is_existing) {
+    $keys = array('type', 'langcode');
+    drupal_write_record('date_format_locale', $locale_format, $keys);
+  }
+  else {
+    drupal_write_record('date_format_locale', $locale_format);
+  }
+
+}
+
