From 9a9405da0b6b5baf8157206d34ba3895fb33b788 Mon Sep 17 00:00:00 2001 From: Justin Wood Date: Thu, 4 Mar 2010 14:28:32 -0500 Subject: Bug 545299, XML-RPC WebService should take and return dates and times in UTC. Code part, r+=mkanat --- Bugzilla/WebService.pm | 27 ++++++++++++++++----------- Bugzilla/WebService/Bugzilla.pm | 24 ++++++++++-------------- Bugzilla/WebService/Server.pm | 9 +++++++++ Bugzilla/WebService/Server/JSONRPC.pm | 26 +++++++------------------- Bugzilla/WebService/Server/XMLRPC.pm | 10 ++++++---- 5 files changed, 48 insertions(+), 48 deletions(-) diff --git a/Bugzilla/WebService.pm b/Bugzilla/WebService.pm index 21c6b8175..3db28142e 100644 --- a/Bugzilla/WebService.pm +++ b/Bugzilla/WebService.pm @@ -21,6 +21,8 @@ package Bugzilla::WebService; use strict; use Date::Parse; use XMLRPC::Lite; +use Bugzilla::Util qw(datetime_from); +use Scalar::Util qw(blessed) # Used by the JSON-RPC server to convert incoming date fields apprpriately. use constant DATE_FIELDS => {}; @@ -36,21 +38,24 @@ sub login_exempt { sub type { my ($self, $type, $value) = @_; if ($type eq 'dateTime') { - $value = datetime_format($value); + $value = $self->datetime_format_outbound($value); } return XMLRPC::Data->type($type)->value($value); } -sub datetime_format { - my ($date_string) = @_; - - my $time = str2time($date_string); - my ($sec, $min, $hour, $mday, $mon, $year) = localtime $time; - # This format string was stolen from SOAP::Utils->format_datetime, - # which doesn't work but which has almost the right format string. - my $iso_datetime = sprintf('%d%02d%02dT%02d:%02d:%02d', - $year + 1900, $mon + 1, $mday, $hour, $min, $sec); - return $iso_datetime; +sub datetime_format_outbound { + my ($self, $date) = @_; + + my $time = $date; + if (blessed($date)) { + # We expect this to mean we were sent a datetime object + $time->set_time_zone('UTC'); + } else { + # We always send our time in UTC, for consistency. + # passed in value is likely a string, create a datetime object + $time = datetime_from($date, 'UTC'); + } + return $iso_datetime = $time->iso8601(); } diff --git a/Bugzilla/WebService/Bugzilla.pm b/Bugzilla/WebService/Bugzilla.pm index 6e74900b9..a66871dc6 100644 --- a/Bugzilla/WebService/Bugzilla.pm +++ b/Bugzilla/WebService/Bugzilla.pm @@ -21,6 +21,7 @@ package Bugzilla::WebService::Bugzilla; use strict; use base qw(Bugzilla::WebService); use Bugzilla::Constants; +use Bugzilla::Util qw(datetime_from); use DateTime; @@ -49,32 +50,27 @@ sub extensions { sub timezone { my $self = shift; - my $offset = Bugzilla->local_timezone->offset_for_datetime(DateTime->now()); - $offset = (($offset / 60) / 60) * 100; - $offset = sprintf('%+05d', $offset); - return { timezone => $self->type('string', $offset) }; + # All Webservices return times in UTC; Use UTC here for backwards compat. + return { timezone => $self->type('string', "+0000") }; } sub time { my ($self) = @_; + # All Webservices return times in UTC; Use UTC here for backwards compat. + # Hardcode values where appropriate my $dbh = Bugzilla->dbh; my $db_time = $dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)'); + $db_time = datetime_from($db_time, 'UTC'); my $now_utc = DateTime->now(); - my $tz = Bugzilla->local_timezone; - my $now_local = $now_utc->clone->set_time_zone($tz); - my $tz_offset = $tz->offset_for_datetime($now_local); - return { db_time => $self->type('dateTime', $db_time), - web_time => $self->type('dateTime', $now_local), + web_time => $self->type('dateTime', $now_utc), web_time_utc => $self->type('dateTime', $now_utc), - tz_name => $self->type('string', $tz->name), - tz_offset => $self->type('string', - $tz->offset_as_string($tz_offset)), - tz_short_name => $self->type('string', - $now_local->time_zone_short_name), + tz_name => $self->type('string', 'UTC'), + tz_offset => $self->type('string', '+0000'), + tz_short_name => $self->type('string', 'UTC'), }; } diff --git a/Bugzilla/WebService/Server.pm b/Bugzilla/WebService/Server.pm index 9571e8030..21f0f787c 100644 --- a/Bugzilla/WebService/Server.pm +++ b/Bugzilla/WebService/Server.pm @@ -19,6 +19,7 @@ package Bugzilla::WebService::Server; use strict; use Bugzilla::Error; +use Bugzilla::Util qw(datetime_from); sub handle_login { my ($self, $class, $method, $full_method) = @_; @@ -29,4 +30,12 @@ sub handle_login { Bugzilla->login(); } +sub datetime_format_inbound { + my ($self, $time) = @_; + + my $converted = datetime_from($time, Bugzilla->local_timezone); + $time = $converted->ymd() . ' ' . $converted->hms(); + return $time +} + 1; diff --git a/Bugzilla/WebService/Server/JSONRPC.pm b/Bugzilla/WebService/Server/JSONRPC.pm index f929b28ac..d07901a7f 100644 --- a/Bugzilla/WebService/Server/JSONRPC.pm +++ b/Bugzilla/WebService/Server/JSONRPC.pm @@ -27,7 +27,6 @@ use base qw(JSON::RPC::Server::CGI Bugzilla::WebService::Server); use Bugzilla::Error; use Bugzilla::WebService::Constants; use Bugzilla::WebService::Util qw(taint_data); -use Bugzilla::Util qw(datetime_from); sub new { my $class = shift; @@ -77,20 +76,17 @@ sub type { } elsif ($type eq 'dateTime') { # ISO-8601 "YYYYMMDDTHH:MM:SS" with a literal T - $retval = $self->datetime_format($value); + $retval = $self->datetime_format_outbound($value); } # XXX Will have to implement base64 if Bugzilla starts using it. return $retval; } -sub datetime_format { - my ($self, $date_string) = @_; - - # YUI expects ISO8601 in UTC time; uncluding TZ specifier - my $time = datetime_from($date_string, 'UTC'); - my $iso_datetime = $time->iso8601() . 'Z'; - return $iso_datetime; +sub datetime_format_outbound { + my $self = shift; + # YUI expects ISO8601 in UTC time; including TZ specifier + return $self->SUPER::datetime_format_outbound(@_) . 'Z'; } @@ -192,10 +188,10 @@ sub _argument_type_check { my $value = $params->{$field}; if (ref $value eq 'ARRAY') { $params->{$field} = - [ map { $self->_bz_convert_datetime($_) } @$value ]; + [ map { $self->datetime_format_inbound($_) } @$value ]; } else { - $params->{$field} = $self->_bz_convert_datetime($value); + $params->{$field} = $self->datetime_format_inbound($value); } } } @@ -220,14 +216,6 @@ sub _argument_type_check { return $params; } -sub _bz_convert_datetime { - my ($self, $time) = @_; - - my $converted = datetime_from($time, Bugzilla->local_timezone); - $time = $converted->ymd() . ' ' . $converted->hms(); - return $time -} - sub handle_login { my $self = shift; diff --git a/Bugzilla/WebService/Server/XMLRPC.pm b/Bugzilla/WebService/Server/XMLRPC.pm index f06c81fc7..04e38c4a0 100644 --- a/Bugzilla/WebService/Server/XMLRPC.pm +++ b/Bugzilla/WebService/Server/XMLRPC.pm @@ -106,10 +106,12 @@ sub decode_value { # We convert dateTimes to a DB-friendly date format. if ($type eq 'dateTime.iso8601') { - # We leave off the $ from the end of this regex to allow for possible - # extensions to the XML-RPC date standard. - $value =~ /^(\d{4})(\d{2})(\d{2})T(\d{2}):(\d{2}):(\d{2})/; - $value = "$1-$2-$3 $4:$5:$6"; + if ($value !~ /T.*[\-+Z]/i) { + # The caller did not specify a timezone, so we assume UTC. + # pass 'Z' specifier to datetime_from to force it + $value = $value . 'Z'; + } + $value = $self->datetime_format_inbound($value); } return $value; -- cgit v1.2.3-24-g4f1b