[Rt-commit] rt branch, timezones_in_charts, updated. rt-3.8.7-312-g7b51ac9

Ruslan Zakirov ruz at bestpractical.com
Tue Mar 30 16:04:05 EDT 2010


The branch, timezones_in_charts has been updated
       via  7b51ac9707cdd344fc10e0a1080d065852571106 (commit)
       via  032d166ed543b8bdcadbe158756b58cda84e6bd2 (commit)
       via  24310a2caadd7ee53a53775c31d784c6d26bc377 (commit)
       via  7fc38ab9b96eb605b592a5d94fd4f14d5a235f68 (commit)
       via  8588d163279d0ef9cd373bfc450831ffb5a32ee8 (commit)
      from  e5e4b610bb4428980c36aa7bf0ea94458c4beac5 (commit)

Summary of changes:
 UPGRADING                      |    4 ++
 docs/timezones_in_charts.pod   |   84 ++++++++++++++++++++++++++++++++++++++++
 etc/RT_Config.pm.in            |   12 ++++++
 lib/RT/Report/Tickets.pm       |   48 ++++++++++++++++++----
 lib/RT/Report/Tickets/Entry.pm |   13 ++++--
 5 files changed, 147 insertions(+), 14 deletions(-)
 create mode 100644 docs/timezones_in_charts.pod

- Log -----------------------------------------------------------------
commit 8588d163279d0ef9cd373bfc450831ffb5a32ee8
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Tue Mar 30 21:34:47 2010 +0400

    introduce new option ChartsTimezonesInDB and implement Pg and mysql

diff --git a/lib/RT/Report/Tickets.pm b/lib/RT/Report/Tickets.pm
index 05f0100..c34d1cb 100644
--- a/lib/RT/Report/Tickets.pm
+++ b/lib/RT/Report/Tickets.pm
@@ -185,20 +185,50 @@ sub _FieldToFunction {
     if ($field =~ /^(.*)(Hourly|Daily|Monthly|Annually)$/) {
         my ($field, $grouping) = ($1, $2);
         my $alias = $args{'ALIAS'} || 'main';
+
+        my $func = "$alias.$field";
+
+        my $db_type = RT->Config->Get('DatabaseType');
+        if ( RT->Config->Get('ChartsTimezonesInDB') ) {
+            my $tz = $self->CurrentUser->UserObj->Timezone
+                || RT->Config->Get('Timezone')
+                || 'UTC';
+            if ( lc $tz eq 'utc' ) {
+                # do nothing
+            }
+            elsif ( $db_type eq 'Pg' ) {
+                $func = "timezone('UTC', $func)";
+                $func = "timezone(". $self->_Handle->dbh->quote($tz) .", $func)";
+            }
+            elsif ( $db_type eq 'mysql' ) {
+                $func = "CONVERT_TZ($func, 'UTC', "
+                    . $self->_Handle->dbh->quote($tz)
+                    .")";
+            }
+            else {
+                $RT::Logger->warning(
+                    "ChartsTimezonesInDB config option"
+                    ." is not supported on $db_type."
+                );
+            }
+        }
+
         # Pg 8.3 requires explicit casting
-        $field .= '::text' if RT->Config->Get('DatabaseType') eq 'Pg';
-        if ( $grouping =~ /Hourly/ ) {
-            $args{'FUNCTION'} = "SUBSTR($alias.$field,1,13)";
+        $func .= '::text' if $db_type eq 'Pg';
+
+        if ( $grouping eq 'Hourly' ) {
+            $func = "SUBSTR($func,1,13)";
         }
-        if ( $grouping =~ /Daily/ ) {
-            $args{'FUNCTION'} = "SUBSTR($alias.$field,1,10)";
+        if ( $grouping eq 'Daily' ) {
+            $func = "SUBSTR($func,1,10)";
         }
-        elsif ( $grouping =~ /Monthly/ ) {
-            $args{'FUNCTION'} = "SUBSTR($alias.$field,1,7)";
+        elsif ( $grouping eq 'Monthly' ) {
+            $func = "SUBSTR($func,1,7)";
         }
-        elsif ( $grouping =~ /Annually/ ) {
-            $args{'FUNCTION'} = "SUBSTR($alias.$field,1,4)";
+        elsif ( $grouping eq 'Annually' ) {
+            $func = "SUBSTR($func,1,4)";
         }
+        $args{'FUNCTION'} = $func;
     } elsif ( $field =~ /^(?:CF|CustomField)\.{(.*)}$/ ) { #XXX: use CFDecipher method
         my $cf_name = $1;
         my $cf = RT::CustomField->new( $self->CurrentUser );

commit 7fc38ab9b96eb605b592a5d94fd4f14d5a235f68
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Tue Mar 30 22:01:36 2010 +0400

    add documentation describing timezones in DBs for charts

diff --git a/docs/timezones_in_charts.pod b/docs/timezones_in_charts.pod
new file mode 100644
index 0000000..0033222
--- /dev/null
+++ b/docs/timezones_in_charts.pod
@@ -0,0 +1,84 @@
+=head1 INTRO
+
+Every date in RT's DB is stored in UTC format. This affects charts
+groupped by time periods (Annually, Monthly, etc.). To produce
+charts that are in a specific timezone we have to use DB's specific
+functions to convert time. Each DB has very different requirements.
+
+=head1 CONFIGURATION
+
+This code is experimental and you can turn it on and off using
+boolean option $ChartsTimezonesInDB in the RT config.
+
+=head1 DATABASE SPECIFIC NOTES
+
+=head2 mysql
+
+Time can not just be converted using numeric time shift as this
+shift value depends on day saving time properties of the time zone.
+
+mysql since 4.1.3 supports named timezones, but you have to fill
+special tables with up to date data. On modern systems it's Usually
+very easy:
+
+    mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql
+
+mysql's doc recommends to restart server. Read more about timezones
+in mysql in the following document
+http://dev.mysql.com/doc/refman/5.0/en/time-zone-support.html .
+
+=head2 Postgres
+
+Postgres database uses system's functions to deal with timezones.
+You shouldn't do anything particular except making sure that
+data in F</usr/share/zoneinfo> is up to date. On some systems
+this means upgrading a system package.
+
+=head3 Note for users of Pg 7.2 and older or users upgraded from those
+
+You should be sure that timestamps in RT DB have no TZ set. TIMESTAMP
+column type in Postgres prior to Pg 7.3 has timezone info by default.
+In newer versions it's not the case anymore. If you have such system
+then you should alter columns.
+
+=head2 Other databases
+
+There is no implementation for other DBs, yet.
+
+=head1 FOR DEVELOPERS
+
+=head2 Postgres
+
+We use timestamp type for all datetime fields. It either has timezone
+info or not, by default since Pg 7.3 it has no timezone. Conversion is
+kinda tricky:
+
+    timezone('Europe/Moscow', timezone('UTC', column_without_tz_info))
+    timezone('to_tz', timezone('from_tz', column_without_tz_info))
+    http://www.postgresql.org/docs/7.4/static/functions-datetime.html#FUNCTIONS-DATETIME-ZONECONVERT
+
+This function flips HAS_TZ flag on the argument. First call makes
+no conversion, but flips HAS_TZ flag. So next call flips it back
+and does actual conversion.
+
+http://www.postgresql.org/docs/7.4/static/datatype-datetime.html#DATATYPE-TIMEZONES
+
+=head2 mysql
+
+Once there is a timezone info loaded in tables on the server
+we have all the same set of named timezones like in system
+and DateTime (DateTime project has copy of the TZ data in a module).
+
+CONVERT_TZ(TS, from, to) exists since mysql 4.1.3. Note that it
+takes timestamp, so supports limitted range (usuall 1970-2038).
+
+=head2 Oracle
+
+Look at FROM_TZ function.
+
+=head2 SQLite
+
+As far as I can see has no support.
+
+=cut
+

commit 24310a2caadd7ee53a53775c31d784c6d26bc377
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Tue Mar 30 23:57:00 2010 +0400

    handle possible TZ shifts in "date is not set" detection

diff --git a/lib/RT/Report/Tickets/Entry.pm b/lib/RT/Report/Tickets/Entry.pm
index 4f2a8a3..525fb98 100644
--- a/lib/RT/Report/Tickets/Entry.pm
+++ b/lib/RT/Report/Tickets/Entry.pm
@@ -65,17 +65,20 @@ sub LabelValue {
     my $field = shift;
     my $value = $self->__Value( $field );
 
+    $RT::Logger->error("boo: $value");
+
     if ( $field =~ /(Daily|Monthly|Annually|Hourly)$/ ) {
         my $re;
-        $re = qr{1970-01-01 00} if $field =~ /Hourly$/;
-        $re = qr{1970-01-01} if $field =~ /Daily$/;
-        $re = qr{1970-01} if $field =~ /Monthly$/;
-        $re = qr{1970} if $field =~ /Annually$/;
+        # it's not just 1970-01-01 00:00:00 because of timezone shifts
+        # and conversion from UTC to user's TZ
+        $re = qr{19(?:70-01-01|69-12-31) [0-9]{2}} if $field =~ /Hourly$/;
+        $re = qr{19(?:70-01-01|69-12-31)} if $field =~ /Daily$/;
+        $re = qr{19(?:70-01|69-12)} if $field =~ /Monthly$/;
+        $re = qr{19(?:70|69)} if $field =~ /Annually$/;
         $value =~ s/^$re/Not Set/;
     }
 
     return $value;
-
 }
 
 eval "require RT::Report::Tickets::Entry_Vendor";

commit 032d166ed543b8bdcadbe158756b58cda84e6bd2
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Tue Mar 30 23:57:51 2010 +0400

    describe ChartsTimezonesInDB in the config

diff --git a/etc/RT_Config.pm.in b/etc/RT_Config.pm.in
index 4ad1411..3f415fc 100755
--- a/etc/RT_Config.pm.in
+++ b/etc/RT_Config.pm.in
@@ -1470,6 +1470,18 @@ Set(
     'others' => "$RT::BasePath/share/fonts/DroidSans.ttf",
 );
 
+=item C<$ChartsTimezonesInDB>
+
+Dates are stored using UTC timezone in the DB, so charts groupped
+by dates and time are not representative. Set C<$ChartsTimezonesInDB>
+to a true value to enable timezones conversions using DB's
+capabilities. You may need to do some work on DB side to use this
+feature, read more in F<docs/timezones_in_charts.pod>.
+
+=cut
+
+Set( $ChartsTimezonesInDB, 0 );
+
 =item C<@Active_MakeClicky>
 
 MakeClicky detects various formats of data in headers and email

commit 7b51ac9707cdd344fc10e0a1080d065852571106
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Wed Mar 31 00:03:51 2010 +0400

    update upgrading

diff --git a/UPGRADING b/UPGRADING
index 1aaccdb..d8962d3 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -18,6 +18,10 @@ If you are using MySQL, please read the instructions in UPGRADING.mysql as
 well.
 
 *******
+UPGRADING FROM 3.8.7 and earlier - Changes:
+
+New option ChartsTimezonesInDB in the config.
+
 UPGRADING FROM 3.8.6 and earlier - Changes:
 
 For MySQL and Oracle users:

-----------------------------------------------------------------------


More information about the Rt-commit mailing list