Index: includes/date.5x-1.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/signup/includes/Attic/date.5x-1.inc,v
retrieving revision 1.3.2.3
diff -u -p -r1.3.2.3 date.5x-1.inc
--- includes/date.5x-1.inc	19 Nov 2008 18:56:13 -0000	1.3.2.3
+++ includes/date.5x-1.inc	28 Nov 2008 22:35:01 -0000
@@ -1,6 +1,7 @@
 <?php
 // $Id: date.5x-1.inc,v 1.3.2.3 2008/11/19 18:56:13 dww Exp $
 
+
 /**
  * @file
  * Code required to support version 5.x-1.* of the CCK date field module.
@@ -11,28 +12,19 @@
  * @return Array of SQL clauses for cron reminder email query builder.
  */
 function _signup_date_reminder_sql($content_type) {
-  $field = signup_date_field($content_type);
+  require_once drupal_get_path('module', 'date') .'/date.inc';
   global $db_type;
-  switch ($db_type) {
-    case 'mysql':
-    case 'mysqli':
-      $where = array(
-        "NOW() + INTERVAL s.reminder_days_before DAY > ". date_sql('DATE', $field['database']['columns']['value']['column'], 'iso'),
-        "NOW() <= ". date_sql('DATE', $field['database']['columns']['value']['column'], 'iso'),
-      );
-      break;
+  $day = $db_type == 'pgsql' ? 'days' : 'DAY';
 
-    case 'pgsql':
-      $where = array(
-        "NOW() + INTERVAL s.reminder_days_before days > ". date_sql('DATE', $field['database']['columns']['value']['column'], 'iso'),
-        "NOW() <= ". date_sql('DATE', $field['database']['columns']['value']['column'], 'iso'),
-      );
-      break;
-  }
+  $field = signup_date_field($content_type);
+  $date_type = $field['type'] == 'datestamp' ? 'int' : 'iso';
+  $start_time = date_sql('DATE', $field['database']['columns']['value']['column'], $date_type);
+
+  $where = "NOW() + INTERVAL s.reminder_days_before ". $day ." > ". $start_time;
   return array(
     'fields' => array($field['database']['columns']['value']['column']),
     'joins' => array('LEFT JOIN {'. $field['database']['table'] .'}  ON {'. $field['database']['table'] .'}.vid = n.vid'),
-    'where' => $where,
+    'where' => array($where),
   );
 }
 
@@ -41,13 +33,31 @@ function _signup_date_reminder_sql($cont
  * @return Array of SQL clauses for cron auto-close query builder.
  */
 function _signup_date_autoclose_sql($content_type) {
+  require_once drupal_get_path('module', 'date') .'/date.inc';
+  global $db_type;
+
+  $close_early = variable_get('signup_close_early', 1);
+  switch ($db_type) {
+    case 'mysql':
+    case 'mysqli':
+      $interval = "INTERVAL '". $close_early ."' HOUR";
+      break;
+
+    case 'pgsql':
+      $interval = "INTERVAL '". $close_early ." hours'";
+      break;
+
+  }
+
   $field = signup_date_field($content_type);
+  $date_type = $field['type'] == 'datestamp' ? 'int' : 'iso';
+  $start_time = date_sql('DATE', $field['database']['columns']['value']['column'], $date_type);
+
+  $where = "NOW() + ". $interval ." > ". $start_time;
   return array(
     'fields' => array($field['database']['columns']['value']['column']),
-    'joins' => array(
-      'LEFT JOIN {'. $field['database']['table'] .'} ON {'. $field['database']['table'] .'}.vid = n.vid',
-    ),
-    'where' => array(date_sql('DATE', $field['database']['columns']['value']['column'], 'iso') ." < '". date('Y-m-d H:i:s', time() + variable_get('signup_close_early', 1) * 3600) ."'"),
+    'joins' => array('LEFT JOIN {'. $field['database']['table'] .'} ON {'. $field['database']['table'] .'}.vid = n.vid'),
+    'where' => array($where),
   );
 }
 
@@ -56,17 +66,28 @@ function _signup_date_autoclose_sql($con
  * has already passed the "Close x hours before" setting.
  */
 function _signup_date_node_completed($node) {
+  require_once drupal_get_path('module', 'date') .'/date.inc';
   $field = signup_date_field($node->type);
   if ($field && $field != 'none' && isset($node->{$field['field_name']})) {
-    $closing_time = time() + (variable_get('signup_close_early', 1) * 3600);
-    if (date_iso2unix($node->{$field['field_name']}[0]['value']) < $closing_time) {
+    switch ($field['type']) {
+      case 'date':
+        $start_time = date_iso2unix($node->{$field['field_name']}[0]['value']);
+        break;
+
+      case 'datestamp':
+        $start_time = $node->{$field['field_name']}[0]['value'];
+        break;
+
+    }
+    $close_time = $start_time - (variable_get('signup_close_early', 1) * 3600);
+    if (time() > $close_time) {
       return TRUE;
     }
   }
   return FALSE;
 }
 
-function _signup_date_format_date($node, $include_to_date = FALSE) {
+function _signup_date_format_date($node) {
   $field = signup_date_field($node->type);
   if (!$field || $field == 'none') {
     return '';
@@ -80,20 +101,24 @@ function _signup_date_format_date($node,
   else {
     $date_value = $node->{$field['database']['columns']['value']['column']};
   }
-  $date = date_show_date(date_make_date($date_value), $field['output_format_date'], 'db');
+  $date_obj = date_make_date($date_value, 'GMT', 'db', $field['type']);
+  switch ($field['tz_handling']) {
+    case 'site':
+      $timezone_name = date_get_site_timezone();
+      break;
 
-  if ($include_to_date) {
-    if (isset($node->{$field['field_name']})) {
-      $date_value = $node->{$field['field_name']}[0]['value2'];
-    }
-    else {
-      $date_value = $node->{$field['database']['columns']['value2']['column']};
-    }
-    if ($date_value) {
-      $date .= t(' to ') . date_show_date(date_make_date($date_value), $field['output_format_date'], 'db');
-    }
-  }
+    case 'date':
+      $timezone_name = $field['field_timezone'];
+      break;
 
-  return $date;
+  }
+  if (!empty($timezone_name)) {
+    $offset = date_offset(date_gmgetdate($date_obj->db->timestamp), $timezone_name);
+  }
+  else {
+    $offset = 0;
+    $timezone_name = NULL;
+  }
+  return date_format_date($field['output_format_date'], date_fuzzy_stamp($date_obj->db) + $offset, 0, $timezone_name);
 }
 
Index: includes/date.5x-2.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/signup/includes/Attic/date.5x-2.inc,v
retrieving revision 1.3.2.2
diff -u -p -r1.3.2.2 date.5x-2.inc
--- includes/date.5x-2.inc	19 Nov 2008 18:56:13 -0000	1.3.2.2
+++ includes/date.5x-2.inc	28 Nov 2008 22:35:01 -0000
@@ -12,29 +12,49 @@
  * @return Array of SQL clauses for cron reminder email query builder.
  */
 function _signup_date_reminder_sql($content_type) {
+  // Get the date field information for this content type.
   $field = signup_date_field($content_type);
-  global $db_type;
-  require_once drupal_get_path('module', 'date_api') .'/date_api_sql.inc';
-  $handler = new date_sql_handler();
-  switch ($db_type) {
-    case 'mysql':
-    case 'mysqli':
-      $where = array(
-        "NOW() + INTERVAL s.reminder_days_before DAY > ". $handler->sql_extract('DATE', $field['database']['columns']['value']['column']),
-        "NOW() <= ". $handler->sql_extract('DATE', $field['database']['columns']['value']['column']),
-      );
-      break;
+  $start_field = $field['database']['columns']['value']['column'];
 
-    case 'pgsql':
-      $where = array(
-        "NOW() + INTERVAL s.reminder_days_before days > ". $handler->sql_extract('DATE', $field['database']['columns']['value']['column']),
-        "NOW() <= ". $handler->sql_extract('DATE', $field['database']['columns']['value']['column']),
-      );
-      break;
+  // Figure out what TZ we want to do the date comparisons in.
+  $compare_tz = $field['tz_handling'] == 'none' ? date_default_timezone_name() : 'UTC';
+  // Get a DateAPI SQL handler class for this field.
+  // TODO
+  $handler = _signup_date_sql_handler($field, $compare_tz);
+
+  // Find the current time in the appropriate TZ for this field.
+  $now_date = date_now($compare_tz);
+  // Need to enclose this in ' marks to use directly in the SQL.
+  $now = "'". date_format($now_date, DATE_FORMAT_DATETIME) ."'";
+
+  // Extract the correct SQL to represent the start time.
+  $start_time = $handler->sql_field($start_field);
+  // Work-around evil code in date_api_sql that tries to workaround a views
+  // bug but breaks other callers. :(
+  $start_time = strtr($start_time, array('***SQLD***' => '%%d', '***SQLS***' => '%%s'));
+
+  // Create SQL to represent the time we should start sending reminders, based
+  // on the SQL for the start time and the reminder_days_before field.
+  $reminder_start = _signup_date_sql_math($start_time, 'SUB', 's.reminder_days_before', 'DAY');
+  $reminder_stop = _signup_date_sql_math($start_time, 'ADD', 1, 'HOUR');
+
+  // The WHERE clauses are now trivial: We want to make sure a) the current
+  // time is after the time we should start sending reminders, but before the
+  // actual start time itself.
+  $where = array(
+    "$now >= $reminder_start",
+    "$now <= $reminder_stop",
+  );
+
+  // See what fields to SELECT.
+  $fields[] = $start_field;
+  if (isset($field['database']['columns']['timezone']['column'])) {
+    $fields[] = $field['database']['columns']['timezone']['column'];
   }
+  $table = '{'. $field['database']['table'] .'}';
   return array(
-    'fields' => array($field['database']['columns']['value']['column']),
-    'joins' => array('LEFT JOIN {'. $field['database']['table'] .'} ON {'. $field['database']['table'] .'}.vid = n.vid'),
+    'fields' => $fields,
+    'joins' => array("LEFT JOIN $table ON $table.vid = n.vid"),
     'where' => $where,
   );
 }
@@ -44,15 +64,42 @@ function _signup_date_reminder_sql($cont
  * @return Array of SQL clauses for cron auto-close query builder.
  */
 function _signup_date_autoclose_sql($content_type) {
+  // Get the date field information for this content type.
   $field = signup_date_field($content_type);
-  require_once drupal_get_path('module', 'date_api') .'/date_api_sql.inc';
-  $handler = new date_sql_handler();
+  $start_field = $field['database']['columns']['value']['column'];
+
+  // Figure out what TZ we want to do the date comparisons in.
+  $compare_tz = $field['tz_handling'] == 'none' ? date_default_timezone_name() : 'UTC';
+  // Get a DateAPI SQL handler class for this field.
+  $handler = _signup_date_sql_handler($field, $compare_tz);
+
+  // Compute a string representing the moment when signups should start
+  // auto-closing.  If the field has no TZ handling, we just want to grab the
+  // current local time.  If the field has any TZ handling, the date will be
+  // stored in the DB in UTC time, so start from current UTC time.  Once we
+  // have the right current time, we need to add our close-in-advance offset.
+  $close_early_hours = variable_get('signup_close_early', 1);
+  $close_date = date_now($compare_tz);
+  date_modify($close_date, "+$close_early_hours hours");
+  $close_date_str = date_format($close_date, DATE_FORMAT_DATETIME);
+
+  // Use the DateAPI SQL handler to construct an appropriate WHERE clause.
+  // Make sure that the start time is <= NOW plus the auto-close window.
+  $where = $handler->sql_where_date('DATE', $start_field, '<=', $close_date_str);
+  // Work-around evil code in date_api_sql that tries to workaround a views
+  // bug but breaks other callers. :(
+  $where = strtr($where, array('***SQLD***' => '%%d', '***SQLS***' => '%%s'));
+
+  // See what fields to SELECT.
+  $fields[] = $start_field;
+  if (isset($field['database']['columns']['timezone']['column'])) {
+    $fields[] = $field['database']['columns']['timezone']['column'];
+  }
+  $table = '{'. $field['database']['table'] .'}';
   return array(
-    'fields' => array($field['database']['columns']['value']['column']),
-    'joins' => array(
-      'LEFT JOIN {'. $field['database']['table'] .'} ON {'. $field['database']['table'] .'}.vid = n.vid',
-    ),
-    'where' => array($handler->sql_extract('DATE', $field['database']['columns']['value']['column']) ." < '". date('Y-m-d\TH:i:s', time() + variable_get('signup_close_early', 1) * 3600) ."'"),
+    'fields' => $fields,
+    'joins' => array("LEFT JOIN $table ON $table.vid = n.vid"),
+    'where' => $where,
   );
 }
 
@@ -63,8 +110,28 @@ function _signup_date_autoclose_sql($con
 function _signup_date_node_completed($node) {
   $field = signup_date_field($node->type);
   if ($field && $field != 'none' && isset($node->{$field['field_name']})) {
-    $closing_time = time() + (variable_get('signup_close_early', 1) * 3600);
-    if (strtotime($node->{$field['field_name']}[0]['value']) < $closing_time) {
+    // Grab whatever date value we actually have, regardless of format.
+    $date_value = $node->{$field['field_name']}[0]['value'];
+    // Figure out the timezone handling for this date.
+    if ($field['tz_handling'] == 'date') {
+      $tz = $node->{$field['field_name']}[0]['timezone'];
+    }
+    else {
+      $tz = date_default_timezone_name();
+    }
+    $db_tz = date_get_timezone_db($field['tz_handling'], $tz);
+    // Create a date object
+    $date = date_make_date($date_value, $db_tz, $field['type']);
+    // Make sure the date object is going to print UTC values.
+    date_timezone_set($date, timezone_open('UTC'));
+    // Find out how early signups should be automatically closed.
+    $close_early_hours = variable_get('signup_close_early', 1);
+    date_modify($date, "-$close_early_hours hours");
+    $close_time = date_format($date, 'U');
+    // Find the current UTC time.
+    $now = date_now('UTC');
+    if (date_format($now, 'U') >= $close_time) {
+      // It's now later than when this node would automatically close signups.
       return TRUE;
     }
   }
@@ -77,7 +144,12 @@ function _signup_date_format_date($node,
     return '';
   }
   if ($field['tz_handling'] == 'date') {
-    $tz = $node->{$field['field_name']}[0]['timezone'];
+    if (isset($node->{$field['field_name']})) {
+      $tz = $node->{$field['field_name']}[0]['timezone'];
+    }
+    else {
+      $tz = $node->{$field['database']['columns']['timezone']['column']};
+    }
   }
   else {
     $tz = date_default_timezone_name();
@@ -117,3 +189,76 @@ function _signup_date_format_date($node,
   return $date_out;
 }
 
+/**
+ * Generate a DateAPI SQL handler for the given CCK date field.
+ *
+ * This can be removed once revision 1.39.2.48 of date/date.module is widely
+ * available in an official release.
+ */
+function _signup_date_sql_handler($field, $compare_tz = NULL) {
+  require_once drupal_get_path('module', 'date_api') .'/date_api_sql.inc';
+
+  // Create a DateAPI SQL handler class for this field type.
+  $handler = new date_sql_handler();
+  $handler->construct($field['type']);
+
+  // If this date field stores a timezone in the DB, tell the handler about it.
+  if ($field['tz_handling'] == 'date') {
+    // The field has a date column
+    $handler->db_timezone_field = $field['database']['columns']['timezone']['column'];
+  }
+  else {
+    $handler->db_timezone = date_get_timezone_db($field);
+  }
+
+  if (empty($compare_tz)) {
+    $compare_tz = date_get_timezone($field);
+  }
+  $handler->local_timezone = $compare_tz;
+
+  // Now that the handler is properly initialized, tell the DB what TZ to use.
+  $handler->set_db_timezone();
+
+  return $handler;
+}
+
+/**
+ * Helper function to handle date math across DB types.
+ *
+ * This can be removed once date_api_sql.inc revision 1.4.2.35 is widely
+ * available in an official release.
+ *
+ * @param $field
+ *   The field to be adjusted.
+ * @param $direction
+ *   Either ADD or SUB.
+ * @param $count
+ *   The number of values to adjust.
+ * @param $granularity
+ *   The granularity of the adjustment, should be singular,
+ *   like SECOND, MINUTE, DAY, HOUR.
+ */
+function _signup_date_sql_math($field, $direction, $count, $granularity) {
+  $granularity = strtoupper($granularity);
+  switch ($GLOBALS['db_type']) {
+    case 'mysql':
+    case 'mysqli':
+      if ($direction == 'ADD') {
+        return "DATE_ADD($field, INTERVAL $count $granularity)";
+      }
+      else {
+        return "DATE_SUB($field, INTERVAL $count $granularity)";
+      }
+      
+    case 'pgsql':
+      $granularity .= 'S';
+      if ($direction == 'ADD') {
+        return "($field + INTERVAL '$count $granularity')";
+      }
+      else {
+        return "($field - INTERVAL '$count $granularity')";
+      }
+  }
+  return $field;
+}
+
Index: includes/date.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/signup/includes/date.inc,v
retrieving revision 1.3.2.5
diff -u -p -r1.3.2.5 date.inc
--- includes/date.inc	19 Nov 2008 23:48:01 -0000	1.3.2.5
+++ includes/date.inc	28 Nov 2008 22:35:01 -0000
@@ -13,10 +13,17 @@
  * @return Array of SQL clauses for admin overview page query builder.
  */
 function _signup_date_admin_sql($content_type) {
+  // Get the date field information for this content type.
   $field = signup_date_field($content_type);
+  // See what fields to SELECT.
+  $fields[] = $field['database']['columns']['value']['column'];
+  if (isset($field['database']['columns']['timezone']['column'])) {
+    $fields[] = $field['database']['columns']['timezone']['column'];
+  }
+  $table = '{'. $field['database']['table'] .'}';
   return array(
-    'fields' => array($field['database']['columns']['value']['column']),
-    'joins' => array('LEFT JOIN {'. $field['database']['table'] .'} ON {'. $field['database']['table'] .'}.vid = n.vid'),
+    'fields' => $fields,
+    'joins' => array("LEFT JOIN $table ON $table.vid = n.vid"),
   );
 }
 
