[development] Patch for fixing date support in 4.7b4
Sammy Spets
sammys-drupal at synerger.com
Thu Feb 2 07:03:38 UTC 2006
Hi ya'll,
Here is my first patch submission of this series. Hope you like it.
Problems solved:
* Date field data is now returned to the integer state before code
reaches the submit stage (changed actually by the validation stage). The
change is transparent to modules expecting the integer value to be in
$edit.
* Dates were creeping backwards by a day each time a form was submitted.
This is now fixed. Problem was with expand_date() using the timestamps
if user timestamps are enabled. Problem was only evident when using
positive timezone offsets. See discussion at the end of this mail for
more details.
* Date field data is now automatically validated for correctness as a
date. I.e whether the silly user entered in 31/Feb/2001. An error
message is added with form_set_error().
* Select fields didn't flag errors found in their data. I.e the class
attribute of select fields was not set by theme_select.
* Date fields didn't display errors as the error cases didn't cascade
into the child elements in the form array structures.
Lemme know if there is something wrong with this stuff.
Discussion
----------
IMO date fields can be classified into two different requirements. First
is the kind of date which is the same regardless of your timezone. An
example of this is a birthday. Second, the kind of date that changes
depending on location such as the submission time of a comment.
Dates must to be placed into one of these categories before timezone
support is feasible. The first category, dates without timezone, can be
displayed by the current date implementation. Unfortunately, the second
cannot and must be linked with the time part of the timestamp
_at_all_times_. For this reason I proposed a time and datetime time to
be placed in core.
I'm going to implement the two types and submit a patch. The datetime
field will support timezones and the time field will not for the
reasons above.
As for timezone support overall... there are two snags i ran into while
doing some testing. 1) format_date() will break on Windows because it
uses gmdate/date. 2) format_date() is broken anyway in the way it
calculates the new timestamp. I.e the timestamp must be converted to
UTC before adding the timezone to it. Here is an example:
say system timezone is +1100 (UNIX timestamp) and user timezone is -0300
timestamp = 2006-02-01 00:00:00
timestamp += timezone // == 2006-01-31 21:00 **wrong**
timestamp = 2006-02-01 00:00:00
timestamp -= system_timezone // == 2006-01-31 13:00
timestamp += timezone // == 2006-01-31 10:00 **right!**
I haven't fixed this yet as I need more information from developers and
decision makers involved with drupal. I have the solution to this in my
head. The decision to be made is whether the database stores localtime
or UTC. localtime is better because it makes it possible to query the
database without doing conversions from UTC. UTC is better because it
avoids the common time hurdle with drupal - timezone support sucks.
Many of the developers on this list have responded to me with
workarounds for various things. Thank you for those. Additionally, i've
received something like, "we don't have enough time to put this stuff
into drupal before releasing 4.7". The efforts you've all put in has
been astounding and by far 4.7 is a major leap forward for drupal.
Unfortunately, the celebration of 4.7 is marred for me, and no doubt
many others, because fundamental things like date support are still
broken since the days of 4.4. How can you even suggest releasing a
product out to market that fails to meet the minimum standard of
operability and call it a release? Would an OS be released if dates were
broken? Even MS won't do that anymore! Drupal is like an OS and the
applications are the modules. Don't forget that!
<take in a deep breath>
All better now. I'm off to add these types to the system. Happy
patching!
--
Sammy Spets
Synerger Pty Ltd
http://www.synerger.com/
-------------- next part --------------
? includes/.common.inc.swp
? includes/fields.inc
? modules/calendar.module
? modules/committee.module
? modules/executive.module
? modules/member.module
? modules/organiser.module
? modules/payment.module
? modules/pes.module
? modules/quote.module
? modules/registration.module
? scripts/excludefiles
? scripts/maketags.sh
? sites/uwc.synerger.com
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.512
diff -u -p -r1.512 common.inc
--- includes/common.inc 29 Jan 2006 07:36:29 -0000 1.512
+++ includes/common.inc 2 Feb 2006 06:08:09 -0000
@@ -844,10 +844,10 @@ function format_date($timestamp, $type =
for ($i = 0; $i < $max; $i++) {
$c = $format[$i];
if (strpos('AaDFlM', $c) !== false) {
- $date .= t(gmdate($c, $timestamp));
+ $date .= t(date($c, $timestamp));
}
else if (strpos('BdgGhHiIjLmnsStTUwWYyz', $c) !== false) {
- $date .= gmdate($c, $timestamp);
+ $date .= date($c, $timestamp);
}
else if ($c == 'r') {
$date .= format_date($timestamp - $timezone, 'custom', 'D, d M Y H:i:s O', $timezone);
Index: includes/form.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/form.inc,v
retrieving revision 1.61
diff -u -p -r1.61 form.inc
--- includes/form.inc 27 Jan 2006 15:57:43 -0000 1.61
+++ includes/form.inc 2 Feb 2006 06:08:11 -0000
@@ -482,7 +482,9 @@ function form_options_flatten($array, $r
function theme_select($element) {
$select = '';
$size = $element['#size'] ? ' size="' . $element['#size'] . '"' : '';
- return theme('form_element', $element['#title'], '<select name="'. $element['#name'] .''. ($element['#multiple'] ? '[]' : '') .'"'. ($element['#multiple'] ? ' multiple="multiple" ' : '') . drupal_attributes($element['#attributes']) .' id="' . $element['#id'] .'" '. $size .'>'. form_select_options($element) .'</select>', $element['#description'], $element['#id'], $element['#required'], form_get_error($element));
+ $class = _form_get_class('form-select', $element['#required'], form_get_error($element));
+
+ return theme('form_element', $element['#title'], '<select name="'. $element['#name'] .''. ($element['#multiple'] ? '[]' : '') .'" class="' . $class .'"'. ($element['#multiple'] ? ' multiple="multiple" ' : '') . drupal_attributes($element['#attributes']) .' id="' . $element['#id'] .'" '. $size .'>'. form_select_options($element) .'</select>', $element['#description'], $element['#id'], $element['#required'], form_get_error($element));
}
function form_select_options($element, $choices = NULL) {
@@ -630,13 +632,20 @@ function theme_date($element) {
* Roll out a single date element.
*/
function expand_date($element) {
- // Default to current date
- if (!isset($element['#value'])) {
- $element['#value'] = array('day' => format_date(time(), 'custom', 'j'),
- 'month' => format_date(time(), 'custom', 'n'),
- 'year' => format_date(time(), 'custom', 'Y'));
+ // Default to current date or if the value is a timestamp set value accordingly
+ if (!is_array($element['#value'])) {
+ $t = (isset($element['#value']) && is_numeric($element['#value'])
+ ? $element['#value'] : time());
+
+ // can't use a non-zero timezone here because date fields don't store time
+ // data to correctly deal with timezones. as a result the date fields will
+ // creep backwards by one day each time form is submitted when the timezone
+ // is positive (i.e east of UTC) <sammys>
+ $element['#value'] = array('day' => format_date($t, 'custom', 'j', 0),
+ 'month' => format_date($t, 'custom', 'n', 0),
+ 'year' => format_date($t, 'custom', 'Y', 0));
}
-
+
$element['#tree'] = TRUE;
// Determine the order of day, month, year in the site's chosen date format.
@@ -648,6 +657,7 @@ function expand_date($element) {
asort($sort);
$order = array_keys($sort);
+ $error = form_get_error($element);
// Output multi-selector for date
foreach ($order as $type) {
switch ($type) {
@@ -674,6 +684,30 @@ function expand_date($element) {
return $element;
}
+function validate_date($elements, $args)
+{
+ global $form_values;
+
+ $fld = $elements['#parents'][0];
+ $f =& $elements['#value'];
+
+ if (!is_array($f) || !checkdate($f['month'], $f['day'], $f['year']))
+ form_set_error($fld, 'Invalid date');
+}
+
+function shrink_date($elements)
+{
+ global $form_values, $user;
+
+ $fld = $elements['#parents'][0];
+
+ $f =& $form_values[$fld];
+ $val = strtotime("{$f['year']}-{$f['month']}-{$f['day']}");
+ $form_values[$fld] = $val;
+
+ return $elements;
+}
+
/**
* Helper function for usage with drupal_map_assoc to display month names.
*/
Index: modules/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system.module,v
retrieving revision 1.286
diff -u -p -r1.286 system.module
--- modules/system.module 1 Feb 2006 15:34:55 -0000 1.286
+++ modules/system.module 2 Feb 2006 06:08:48 -0000
@@ -76,7 +76,7 @@ function system_elements() {
$type['checkboxes'] = array('#input' => TRUE, '#process' => array('expand_checkboxes' => array()), '#tree' => TRUE);
$type['select'] = array('#input' => TRUE);
$type['weight'] = array('#input' => TRUE, '#delta' => 10, '#default_value' => 0);
- $type['date'] = array('#input' => TRUE, '#process' => array('expand_date' => array()));
+ $type['date'] = array('#input' => TRUE, '#process' => array('expand_date' => array()), '#after_build' => 'shrink_date', '#validate' => array('validate_date' => ''));
$type['file'] = array('#input' => TRUE, '#size' => 60);
// Form structure
More information about the development
mailing list