aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrank Becker <Frank@Frank-Becker.de>2010-04-02 14:49:22 +0200
committerFrédéric Buclin <LpSolit@gmail.com>2010-04-02 14:49:22 +0200
commit929eec53d42d93313125e17d43ccc15e0e4f348c (patch)
treea5586d4f5c93329b8f401fcfd4318e4979c4eeea
parentBug 548327: Administration page should have hooks to extend the admin links (diff)
downloadbugzilla-929eec53d42d93313125e17d43ccc15e0e4f348c.tar.gz
bugzilla-929eec53d42d93313125e17d43ccc15e0e4f348c.tar.bz2
bugzilla-929eec53d42d93313125e17d43ccc15e0e4f348c.zip
Bug 515515: For clients, mid-air collision results when user's timezone preference differs from server's
r/a=mkanat
-rw-r--r--Bugzilla/Util.pm51
-rwxr-xr-xprocess_bug.cgi47
2 files changed, 75 insertions, 23 deletions
diff --git a/Bugzilla/Util.pm b/Bugzilla/Util.pm
index 1d5785d34..d8be89246 100644
--- a/Bugzilla/Util.pm
+++ b/Bugzilla/Util.pm
@@ -40,7 +40,7 @@ use base qw(Exporter);
diff_arrays
trim wrap_hard wrap_comment find_wrap_point
format_time format_time_decimal validate_date
- validate_time
+ validate_time datetime_from
file_mod_time is_7bit_clean
bz_crypt generate_random_password
validate_email_syntax clean_text
@@ -463,6 +463,46 @@ sub format_time {
return trim($date);
}
+sub datetime_from {
+ my ($date, $timezone) = @_;
+
+ # strptime($date) returns an empty array if $date has an invalid
+ # date format.
+ my @time = strptime($date);
+
+ unless (scalar @time) {
+ # If an unknown timezone is passed (such as MSK, for Moskow),
+ # strptime() is unable to parse the date. We try again, but we first
+ # remove the timezone.
+ $date =~ s/\s+\S+$//;
+ @time = strptime($date);
+ }
+
+ return undef if !@time;
+
+ # strptime() counts years from 1900, and months from 0 (January).
+ # We have to fix both values.
+ my $dt = DateTime->new({
+ year => $time[5] + 1900,
+ month => $time[4] + 1,
+ day => $time[3],
+ hour => $time[2],
+ minute => $time[1],
+ # DateTime doesn't like fractional seconds.
+ # Also, sometimes seconds are undef.
+ second => int($time[0] || 0),
+ # If a timezone was specified, use it. Otherwise, use the
+ # local timezone.
+ time_zone => Bugzilla->local_timezone->offset_as_string($time[6])
+ || Bugzilla->local_timezone,
+ });
+
+ # Now display the date using the given timezone,
+ # or the user's timezone if none is given.
+ $dt->set_time_zone($timezone || Bugzilla->user->timezone);
+ return $dt;
+}
+
sub format_time_decimal {
my ($time) = (@_);
@@ -939,6 +979,15 @@ This routine is mainly called from templates to filter dates, see
Returns a number with 2 digit precision, unless the last digit is a 0. Then it
returns only 1 digit precision.
+=item C<datetime_from($time, $timezone)>
+
+Returns a DateTime object given a date string. If the string is not in some
+valid date format that C<strptime> understands, we return C<undef>.
+
+You can optionally specify a timezone for the returned date. If not
+specified, defaults to the currently-logged-in user's timezone, or
+the Bugzilla server's local timezone if there isn't a logged-in user.
+
=back
diff --git a/process_bug.cgi b/process_bug.cgi
index 7df7b1c5f..0432dc94f 100755
--- a/process_bug.cgi
+++ b/process_bug.cgi
@@ -163,31 +163,34 @@ print $cgi->header() unless Bugzilla->usage_mode == USAGE_MODE_EMAIL;
# Check for a mid-air collision. Currently this only works when updating
# an individual bug.
-if (defined $cgi->param('delta_ts')
- && $cgi->param('delta_ts') ne $first_bug->delta_ts)
+if (defined $cgi->param('delta_ts'))
{
- ($vars->{'operations'}) =
- Bugzilla::Bug::GetBugActivity($first_bug->id, undef,
- scalar $cgi->param('delta_ts'));
-
- $vars->{'title_tag'} = "mid_air";
+ my $delta_ts_z = datetime_from($cgi->param('delta_ts'));
+ my $first_delta_tz_z = datetime_from($first_bug->delta_ts);
+ if ($first_delta_tz_z ne $delta_ts_z) {
+ ($vars->{'operations'}) =
+ Bugzilla::Bug::GetBugActivity($first_bug->id, undef,
+ scalar $cgi->param('delta_ts'));
+
+ $vars->{'title_tag'} = "mid_air";
- ThrowCodeError('undefined_field', { field => 'longdesclength' })
- if !defined $cgi->param('longdesclength');
-
- $vars->{'start_at'} = $cgi->param('longdesclength');
- # Always sort midair collision comments oldest to newest,
- # regardless of the user's personal preference.
- $vars->{'comments'} = Bugzilla::Bug::GetComments($first_bug->id,
- "oldest_to_newest");
- $vars->{'bug'} = $first_bug;
- # The token contains the old delta_ts. We need a new one.
- $cgi->param('token', issue_hash_token([$first_bug->id, $first_bug->delta_ts]));
+ ThrowCodeError('undefined_field', { field => 'longdesclength' })
+ if !defined $cgi->param('longdesclength');
+
+ $vars->{'start_at'} = $cgi->param('longdesclength');
+ # Always sort midair collision comments oldest to newest,
+ # regardless of the user's personal preference.
+ $vars->{'comments'} = Bugzilla::Bug::GetComments($first_bug->id,
+ "oldest_to_newest");
+ $vars->{'bug'} = $first_bug;
+ # The token contains the old delta_ts. We need a new one.
+ $cgi->param('token', issue_hash_token([$first_bug->id, $first_bug->delta_ts]));
- # Warn the user about the mid-air collision and ask them what to do.
- $template->process("bug/process/midair.html.tmpl", $vars)
- || ThrowTemplateError($template->error());
- exit;
+ # Warn the user about the mid-air collision and ask them what to do.
+ $template->process("bug/process/midair.html.tmpl", $vars)
+ || ThrowTemplateError($template->error());
+ exit;
+ }
}
# We couldn't do this check earlier as we first had to validate bug IDs