Commit 615cfb88 authored by lpsolit%gmail.com's avatar lpsolit%gmail.com

Bug 182238: Allow users to choose what time zone to display times in - Patch by…

Bug 182238: Allow users to choose what time zone to display times in - Patch by Fré©ric Buclin <LpSolit@gmail.com> r/a=mkanat
parent 68c8ee64
...@@ -51,6 +51,7 @@ use Bugzilla::Flag; ...@@ -51,6 +51,7 @@ use Bugzilla::Flag;
use File::Basename; use File::Basename;
use File::Spec::Functions; use File::Spec::Functions;
use DateTime::TimeZone;
use Safe; use Safe;
# This creates the request cache for non-mod_perl installations. # This creates the request cache for non-mod_perl installations.
...@@ -463,6 +464,16 @@ sub hook_args { ...@@ -463,6 +464,16 @@ sub hook_args {
return $class->request_cache->{hook_args}; return $class->request_cache->{hook_args};
} }
sub local_timezone {
my $class = shift;
if (!defined $class->request_cache->{local_timezone}) {
$class->request_cache->{local_timezone} =
DateTime::TimeZone->new(name => 'local');
}
return $class->request_cache->{local_timezone};
}
sub request_cache { sub request_cache {
if ($ENV{MOD_PERL}) { if ($ENV{MOD_PERL}) {
require Apache2::RequestUtil; require Apache2::RequestUtil;
...@@ -699,4 +710,10 @@ is unreadable or is not valid perl, we C<die>. ...@@ -699,4 +710,10 @@ is unreadable or is not valid perl, we C<die>.
If you are running inside a code hook (see L<Bugzilla::Hook>) this If you are running inside a code hook (see L<Bugzilla::Hook>) this
is how you get the arguments passed to the hook. is how you get the arguments passed to the hook.
=item C<local_timezone>
Returns the local timezone of the Bugzilla installation,
as a DateTime::TimeZone object. This detection is very time
consuming, so we cache this information for future references.
=back =back
...@@ -62,7 +62,9 @@ sub SETTINGS { ...@@ -62,7 +62,9 @@ sub SETTINGS {
default => ${Bugzilla->languages}[0] }, default => ${Bugzilla->languages}[0] },
# 2007-07-02 altlist@gmail.com -- Bug 225731 # 2007-07-02 altlist@gmail.com -- Bug 225731
quote_replies => { options => ['quoted_reply', 'simple_reply', 'off'], quote_replies => { options => ['quoted_reply', 'simple_reply', 'off'],
default => "quoted_reply" } default => "quoted_reply" },
# 2008-08-27 LpSolit@gmail.com -- Bug 182238
timezone => { subclass => 'Timezone', default => 'local' },
} }
}; };
......
...@@ -69,6 +69,12 @@ sub REQUIRED_MODULES { ...@@ -69,6 +69,12 @@ sub REQUIRED_MODULES {
module => 'Date::Format', module => 'Date::Format',
version => '2.21' version => '2.21'
}, },
# 0.28 fixed some important bugs in DateTime.
{
package => 'DateTime',
module => 'DateTime',
version => '0.28'
},
{ {
package => 'PathTools', package => 'PathTools',
module => 'File::Spec', module => 'File::Spec',
......
...@@ -604,7 +604,15 @@ sub create { ...@@ -604,7 +604,15 @@ sub create {
}, },
# Format a time for display (more info in Bugzilla::Util) # Format a time for display (more info in Bugzilla::Util)
time => \&Bugzilla::Util::format_time, time => [ sub {
my ($context, $format) = @_;
return sub {
my $time = shift;
return format_time($time, $format);
};
},
1
],
# Bug 120030: Override html filter to obscure the '@' in user # Bug 120030: Override html filter to obscure the '@' in user
# visible strings. # visible strings.
......
...@@ -50,6 +50,7 @@ use Bugzilla::Classification; ...@@ -50,6 +50,7 @@ use Bugzilla::Classification;
use Bugzilla::Field; use Bugzilla::Field;
use Scalar::Util qw(blessed); use Scalar::Util qw(blessed);
use DateTime::TimeZone;
use base qw(Bugzilla::Object Exporter); use base qw(Bugzilla::Object Exporter);
@Bugzilla::User::EXPORT = qw(is_available_username @Bugzilla::User::EXPORT = qw(is_available_username
...@@ -349,6 +350,22 @@ sub settings { ...@@ -349,6 +350,22 @@ sub settings {
return $self->{'settings'}; return $self->{'settings'};
} }
sub timezone {
my $self = shift;
if (!defined $self->{timezone}) {
my $tz = $self->settings->{timezone}->{value};
if ($tz eq 'local') {
# The user wants the local timezone of the server.
$self->{timezone} = Bugzilla->local_timezone;
}
else {
$self->{timezone} = DateTime::TimeZone->new(name => $tz);
}
}
return $self->{timezone};
}
sub flush_queries_cache { sub flush_queries_cache {
my $self = shift; my $self = shift;
...@@ -1884,6 +1901,11 @@ value - the value of this setting for this user. Will be the same ...@@ -1884,6 +1901,11 @@ value - the value of this setting for this user. Will be the same
is_default - a boolean to indicate whether the user has chosen to make is_default - a boolean to indicate whether the user has chosen to make
a preference for themself or use the site default. a preference for themself or use the site default.
=item C<timezone>
Returns the timezone used to display dates and times to the user,
as a DateTime::TimeZone object.
=item C<groups> =item C<groups>
Returns an arrayref of L<Bugzilla::Group> objects representing Returns an arrayref of L<Bugzilla::Group> objects representing
......
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Frédéric Buclin.
# Portions created by Frédéric Buclin are Copyright (c) 2008 Frédéric Buclin.
# All rights reserved.
#
# Contributor(s): Frédéric Buclin <LpSolit@gmail.com>
package Bugzilla::User::Setting::Timezone;
use strict;
use DateTime::TimeZone;
use base qw(Bugzilla::User::Setting);
use Bugzilla::Constants;
sub legal_values {
my ($self) = @_;
return $self->{'legal_values'} if defined $self->{'legal_values'};
my @timezones = DateTime::TimeZone->all_names;
# Remove old formats, such as CST6CDT, EST, EST5EDT.
@timezones = grep { $_ =~ m#.+/.+#} @timezones;
# Append 'local' to the list, which will use the timezone
# given by the server.
push(@timezones, 'local');
return $self->{'legal_values'} = \@timezones;
}
1;
__END__
=head1 NAME
Bugzilla::User::Setting::Timezone - Object for a user preference setting for desired timezone
=head1 DESCRIPTION
Timezone.pm extends Bugzilla::User::Setting and implements a class specialized for
setting the desired timezone.
=head1 METHODS
=over
=item C<legal_values()>
Description: Returns all legal timezones
Params: none
Returns: A reference to an array containing the names of all legal timezones
=back
...@@ -50,6 +50,7 @@ use Bugzilla::Constants; ...@@ -50,6 +50,7 @@ use Bugzilla::Constants;
use Date::Parse; use Date::Parse;
use Date::Format; use Date::Format;
use DateTime;
use Text::Wrap; use Text::Wrap;
# This is from the perlsec page, slightly modified to remove a warning # This is from the perlsec page, slightly modified to remove a warning
...@@ -398,36 +399,39 @@ sub wrap_hard { ...@@ -398,36 +399,39 @@ sub wrap_hard {
sub format_time { sub format_time {
my ($date, $format) = @_; my ($date, $format) = @_;
# If $format is undefined, try to guess the correct date format. # If $format is undefined, try to guess the correct date format.
my $show_timezone;
if (!defined($format)) { if (!defined($format)) {
if ($date =~ m/^(\d{4})[-\.](\d{2})[-\.](\d{2}) (\d{2}):(\d{2})(:(\d{2}))?$/) { if ($date =~ m/^(\d{4})[-\.](\d{2})[-\.](\d{2}) (\d{2}):(\d{2})(:(\d{2}))?$/) {
my $sec = $7; my $sec = $7;
if (defined $sec) { if (defined $sec) {
$format = "%Y-%m-%d %T"; $format = "%Y-%m-%d %T %Z";
} else { } else {
$format = "%Y-%m-%d %R"; $format = "%Y-%m-%d %R %Z";
} }
} else { } else {
# Default date format. See Date::Format for other formats available. # Default date format. See DateTime for other formats available.
$format = "%Y-%m-%d %R"; $format = "%Y-%m-%d %R %Z";
} }
# By default, we want the timezone to be displayed.
$show_timezone = 1;
} }
else {
# Search for %Z or %z, meaning we want the timezone to be displayed.
# Till bug 182238 gets fixed, we assume Bugzilla->params->{'timezone'}
# is used.
$show_timezone = ($format =~ s/\s?%Z$//i);
}
# str2time($date) is undefined if $date has an invalid date format.
my $time = str2time($date);
if (defined $time) { # strptime($date) returns an empty array if $date has an invalid date format.
$date = time2str($format, $time); my @time = strptime($date);
$date .= " " . Bugzilla->params->{'timezone'} if $show_timezone;
if (scalar @time) {
# strptime() counts years from 1900, and months from 0 (January).
# We have to fix both values.
my $dt = DateTime->new({year => 1900 + $time[5],
month => ++$time[4],
day => $time[3],
hour => $time[2],
minute => $time[1],
second => $time[0],
# Use the timezone specified by the server.
time_zone => Bugzilla->local_timezone});
# Now display the date using the user's timezone.
$dt->set_time_zone(Bugzilla->user->timezone);
$date = $dt->strftime($format);
} }
else { else {
# Don't let invalid (time) strings to be passed to templates! # Don't let invalid (time) strings to be passed to templates!
......
...@@ -1183,7 +1183,7 @@ if (scalar(@bugowners) > 1 && Bugzilla->user->in_group('editbugs')) { ...@@ -1183,7 +1183,7 @@ if (scalar(@bugowners) > 1 && Bugzilla->user->in_group('editbugs')) {
$vars->{'splitheader'} = $cgi->cookie('SPLITHEADER') ? 1 : 0; $vars->{'splitheader'} = $cgi->cookie('SPLITHEADER') ? 1 : 0;
$vars->{'quip'} = GetQuip(); $vars->{'quip'} = GetQuip();
$vars->{'currenttime'} = time(); $vars->{'currenttime'} = localtime(time());
# The following variables are used when the user is making changes to multiple bugs. # The following variables are used when the user is making changes to multiple bugs.
if ($dotweak && scalar @bugs) { if ($dotweak && scalar @bugs) {
......
...@@ -292,7 +292,7 @@ sub wrap { ...@@ -292,7 +292,7 @@ sub wrap {
# We create a Chart object so we can validate the parameters # We create a Chart object so we can validate the parameters
my $chart = new Bugzilla::Chart($cgi); my $chart = new Bugzilla::Chart($cgi);
$vars->{'time'} = time(); $vars->{'time'} = localtime(time());
$vars->{'imagebase'} = $cgi->canonicalise_query( $vars->{'imagebase'} = $cgi->canonicalise_query(
"action", "action-wrap", "ctype", "format", "width", "height"); "action", "action-wrap", "ctype", "format", "width", "height");
......
...@@ -226,7 +226,7 @@ foreach my $tbl (@tbl_names) { ...@@ -226,7 +226,7 @@ foreach my $tbl (@tbl_names) {
$vars->{'col_field'} = $col_field; $vars->{'col_field'} = $col_field;
$vars->{'row_field'} = $row_field; $vars->{'row_field'} = $row_field;
$vars->{'tbl_field'} = $tbl_field; $vars->{'tbl_field'} = $tbl_field;
$vars->{'time'} = time(); $vars->{'time'} = localtime(time());
$vars->{'col_names'} = \@col_names; $vars->{'col_names'} = \@col_names;
$vars->{'row_names'} = \@row_names; $vars->{'row_names'} = \@row_names;
......
...@@ -33,11 +33,13 @@ BEGIN { ...@@ -33,11 +33,13 @@ BEGIN {
use_ok(Bugzilla::Util); use_ok(Bugzilla::Util);
} }
# We need to override Bugzilla->params so we can get an expected value when # We need to override user preferences so we can get an expected value when
# Bugzilla::Util::format_time() calls ask for the 'timezone' parameter. # Bugzilla::Util::format_time() calls ask for the 'timezone' user preference.
# This will also prevent the tests from failing on site that do not have a Bugzilla->user->settings->{'timezone'}->{'value'} = "local";
# data/params file containing 'timezone' yet.
Bugzilla->params->{'timezone'} = "TEST"; # We need to know the local timezone for the date chosen in our tests.
# Below, tests are run against Nov. 24, 2002.
my $tz = Bugzilla->local_timezone->short_name_for_datetime(DateTime->new(year => 2002, month => 11, day => 24));
# we don't test the taint functions since that's going to take some more work. # we don't test the taint functions since that's going to take some more work.
# XXX: test taint functions # XXX: test taint functions
...@@ -58,7 +60,7 @@ is(lsearch(\@list,'kiwi'),-1,'lsearch 3 (missing item)'); ...@@ -58,7 +60,7 @@ is(lsearch(\@list,'kiwi'),-1,'lsearch 3 (missing item)');
is(trim(" fg<*\$%>+=~~ "),'fg<*$%>+=~~','trim()'); is(trim(" fg<*\$%>+=~~ "),'fg<*$%>+=~~','trim()');
#format_time(); #format_time();
is(format_time("2002.11.24 00:05"),'2002-11-24 00:05 TEST','format_time("2002.11.24 00:05")'); is(format_time("2002.11.24 00:05"), "2002-11-24 00:05 $tz",'format_time("2002.11.24 00:05") is ' . format_time("2002.11.24 00:05"));
is(format_time("2002.11.24 00:05:56"),'2002-11-24 00:05:56 TEST','format_time("2002.11.24 00:05:56")'); is(format_time("2002.11.24 00:05:56"), "2002-11-24 00:05:56 $tz",'format_time("2002.11.24 00:05:56")');
is(format_time("2002.11.24 00:05:56", "%Y-%m-%d %R"), '2002-11-24 00:05', 'format_time("2002.11.24 00:05:56", "%Y-%m-%d %R") (with no timezone)'); is(format_time("2002.11.24 00:05:56", "%Y-%m-%d %R"), '2002-11-24 00:05', 'format_time("2002.11.24 00:05:56", "%Y-%m-%d %R") (with no timezone)');
is(format_time("2002.11.24 00:05:56", "%Y-%m-%d %R %Z"), '2002-11-24 00:05 TEST', 'format_time("2002.11.24 00:05:56", "%Y-%m-%d %R %Z") (with timezone)'); is(format_time("2002.11.24 00:05:56", "%Y-%m-%d %R %Z"), "2002-11-24 00:05 $tz", 'format_time("2002.11.24 00:05:56", "%Y-%m-%d %R %Z") (with timezone)');
...@@ -43,5 +43,7 @@ ...@@ -43,5 +43,7 @@
"quote_replies" => "Quote the associated comment when you click on its reply link", "quote_replies" => "Quote the associated comment when you click on its reply link",
"quoted_reply" => "Quote the full comment", "quoted_reply" => "Quote the full comment",
"simple_reply" => "Reference the comment number only", "simple_reply" => "Reference the comment number only",
"timezone" => "Timezone used to display dates and times",
"local" => "Same as the server",
} }
%] %]
...@@ -54,11 +54,7 @@ ...@@ -54,11 +54,7 @@
<div class="bz_query_head" align="center"> <div class="bz_query_head" align="center">
<span class="bz_query_timestamp"> <span class="bz_query_timestamp">
[% IF Param('timezone') %] <b>[% currenttime FILTER time('%a %b %e %Y %T %Z') FILTER html %]</b><br>
<b>[% time2str("%a %b %e %Y %T %Z", currenttime, Param('timezone')) %]</b><br>
[% ELSE %]
<b>[% time2str("%a %b %e %Y %T", currenttime) %]</b><br>
[% END %]
</span> </span>
[% IF debug %] [% IF debug %]
......
...@@ -25,9 +25,11 @@ ...@@ -25,9 +25,11 @@
height = 350 height = 350
%] %]
[% time = time FILTER time('%Y-%m-%d %H:%M:%S') FILTER html %]
[% PROCESS global/header.html.tmpl [% PROCESS global/header.html.tmpl
title = "Chart" title = "Chart"
header_addl_info = time2str("%Y-%m-%d %H:%M:%S", time) header_addl_info = time
%] %]
<div align="center"> <div align="center">
......
...@@ -66,6 +66,8 @@ ...@@ -66,6 +66,8 @@
[% col_field_disp FILTER html %] [% col_field_disp FILTER html %]
[% END %] [% END %]
[% time = time FILTER time('%Y-%m-%d %H:%M:%S') FILTER html %]
[% PROCESS global/header.html.tmpl [% PROCESS global/header.html.tmpl
style = " style = "
.t1 { background-color: #ffffff } /* white */ .t1 { background-color: #ffffff } /* white */
...@@ -74,7 +76,7 @@ ...@@ -74,7 +76,7 @@
.t4 { background-color: #c3d3ed } /* darker blue */ .t4 { background-color: #c3d3ed } /* darker blue */
.ttotal { background-color: #cfffdf } /* light green */ .ttotal { background-color: #cfffdf } /* light green */
" "
header_addl_info = time2str("%Y-%m-%d %H:%M:%S", time) header_addl_info = time
%] %]
[% IF debug %] [% IF debug %]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment