bug-cvs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Patch for timezone handling in cvs log


From: Bart Robinson
Subject: Re: Patch for timezone handling in cvs log
Date: Wed, 5 May 2004 12:37:09 -0700 (PDT)

On 2004-5-1 Derek Robert Price <derek@ximbiot.com> wrote:
 > Bart Robinson wrote:
 > 
 > >Here is a simpler patch incorporating Derek's ideas with getting
 > >rid of the -z and omitting the gratuitous MT stuff in log.c.
 > >
 > >OVERVIEW
 > >--------
 > >
 > >These changes make log/rlog output dates in local time by
 > >default.  If the user wants GMT or any other timezone supported
 > >by their system, they can modify their TZ env var accordingly.
 > 
 > 
 > This is almost perfect short of a few minor issues:
 > 
 >    1. tm_diff should be static and not have a prototype in cvs.h until
 >       it is actually being used elsewhere.
 >    2. both tm_diff & format_date_alloc should probably be in subr.c
 >       rather than main.
 >    3. the output date format should use dashes instead of slashes for
 >       compliance with the ISO 8601 specification.

Here is the new patch, including changes (1) and (3) and also
ChangeLogs and texinfo/man changes.

I held off on change (2) since main.c already has a bunch of
time/date-related functions in that spot, so it makes sense to
have tm_diff (now static) and format_date_alloc around there.
It would probably make more sense if *all* of them were in subr.c,
or some new file, but that is kind of outside the scope of this
patch.

Thanks
-- bart

Index: ChangeLog
===================================================================
RCS file: /cvsroot/ccvs/ChangeLog,v
retrieving revision 1.1003
diff -u -p -r1.1003 ChangeLog
--- ChangeLog   3 May 2004 14:59:41 -0000       1.1003
+++ ChangeLog   5 May 2004 19:30:32 -0000
@@ -1,3 +1,7 @@
+2004-05-05  Bart Robinson  <lomew@riverbed.com>
+
+       * TODO (224): Remove completed item.
+
 2004-05-03  Derek Price  <derek@ximbiot.com>
 
        * srclist.txt: Note bison.m4 forked from GNULIB.
Index: TODO
===================================================================
RCS file: /cvsroot/ccvs/TODO,v
retrieving revision 1.80
diff -u -p -r1.80 TODO
--- TODO        7 Apr 2004 00:54:52 -0000       1.80
+++ TODO        5 May 2004 19:30:32 -0000
@@ -855,19 +855,6 @@ administrative file interfaces do not.)
 of universal character set (ISO 10646?) internally and converting on
 input and output, which opens the locale can of worms.
 
-224.  Better timezone handling.  Many people would like to see times
-output in local time rather than UTC, but that's tricky since the
-conversion from internal form is currently done by the server who has no
-idea what the user's timezone even is, let alone the rules for
-converting to it.
-
-   -  On the contrary, I think the MT server response should be easily 
adaptable
-for this purpose.  It is defined in cvsclient.texi as processed by the client
-if it knows how and printed to stdout otherwise.  A "time" tag or the like
-could be the usual CVS server UTC time string.  An old client could just print
-the time in UTC and a new client would know that it could convert the time to a
-local time string according to the localization settings before printing it.
-
 225.  Add support for --allow-root to server command.
 
 227.  'cvs release' should use the CVS/Root in the directory being released
Index: doc/ChangeLog
===================================================================
RCS file: /cvsroot/ccvs/doc/ChangeLog,v
retrieving revision 1.841
diff -u -p -r1.841 ChangeLog
--- doc/ChangeLog       5 May 2004 16:19:03 -0000       1.841
+++ doc/ChangeLog       5 May 2004 19:30:33 -0000
@@ -1,3 +1,9 @@
+2004-05-05  Bart Robinson  <lomew@pobox.com>
+
+       * cvs.texinfo (log): Updated since we display in local time now.
+       Also added some examples.
+       * cvs.1: Regenerated.
+       
 2004-05-04  Derek Price  <derek@ximbiot.com>
 
        * cvs.man.header, cvs.man.footer: Reference `info CVS' rather than
Index: doc/cvs.1
===================================================================
RCS file: /cvsroot/ccvs/doc/cvs.1,v
retrieving revision 1.7
diff -u -p -r1.7 cvs.1
--- doc/cvs.1   5 May 2004 16:19:03 -0000       1.7
+++ doc/cvs.1   5 May 2004 19:30:34 -0000
@@ -2852,10 +2852,12 @@ The output includes the location of the 
 the \fIhead\fP revision (the latest revision on the
 trunk), all symbolic names (tags) and some other
 things.  For each revision, the revision number, the
+date, the
 author, the number of lines added/deleted and the log
-message are printed.  All times are displayed in
-Coordinated Universal Time (UTC).  (Other parts of
-\fBcvs\fP print times in the local timezone).
+message are printed.  All dates are displayed in local
+time at the client.  This is typically specified in the
+\fB$TZ\fP environment variable, which can be set to
+govern how \fBlog\fP displays dates.
 .SP
 \fBNote: \fBlog\fP uses @samp{-R\fP in a way that conflicts
 with the normal use inside \fBcvs\fP (see node \`Common options\(aq in the CVS 
manual).}
@@ -3044,7 +3046,25 @@ selected by \fB-b\fP and \fB-r\fP.
 .SP
 \.SH "log examples"
 .SP
-Contributed examples are gratefully accepted.
+.IX "Timezone, in output"
+.IX "Zone, time, in output"
+Since \fBlog\fP shows dates in local time,
+you might want to see them in Coordinated Universal Time (UTC) or
+some other timezone.
+To do this you can set your \fB$TZ\fP environment
+variable before invoking \fBcvs\fP:
+.SP
+.PD 0
+.IP "" 2
+$ TZ=UTC cvs log foo.c
+.IP "" 2
+$ TZ=EST cvs log bar.c
+
+.PD
+.IP "" 0
+.SP
+(If you are using a \fBcsh\fP-style shell, like \fBtcsh\fP,
+you would need to prefix the examples above with \fBenv\fP.)
 .SP
 \.SH "ls & rls"
 .IX "ls (subcommand)"
Index: doc/cvs.texinfo
===================================================================
RCS file: /cvsroot/ccvs/doc/cvs.texinfo,v
retrieving revision 1.603
diff -u -p -r1.603 cvs.texinfo
--- doc/cvs.texinfo     30 Apr 2004 18:23:38 -0000      1.603
+++ doc/cvs.texinfo     5 May 2004 19:30:37 -0000
@@ -10489,27 +10489,16 @@ commands.
 
 @cindex Timezone, in output
 @cindex Zone, time, in output
-@c Kind of a funny place to document the timezone used
-@c in output from commands other than @code{log}.
-@c There is also more we need to say about this,
-@c including what happens in a client/server environment.
 The output includes the location of the @sc{rcs} file,
 the @dfn{head} revision (the latest revision on the
 trunk), all symbolic names (tags) and some other
 things.  For each revision, the revision number, the
+date, the
 author, the number of lines added/deleted and the log
-message are printed.  All times are displayed in
-Coordinated Universal Time (UTC).  (Other parts of
-@sc{cvs} print times in the local timezone).
-@c FIXCVS: need a better way to control the timezone
-@c used in output.  Previous/current versions of CVS did/do
-@c sometimes support -z in RCSINIT, and/or an
-@c undocumented (except by reference to 'rlog') -z option
-@c to cvs log, but this has not been a consistent,
-@c documented feature.  Perhaps a new global option,
-@c where LT means the client's timezone, which the
-@c client then communicates to the server, is the
-@c right solution.
+message are printed.  All dates are displayed in local
+time at the client.  This is typically specified in the
+@code{$TZ} environment variable, which can be set to
+govern how @code{log} displays dates.
 
 @strong{Note: @code{log} uses @samp{-R} in a way that conflicts
 with the normal use inside @sc{cvs} (@pxref{Common options}).}
@@ -10677,7 +10666,21 @@ selected by @samp{-b} and @samp{-r}.
 @node log examples
 @appendixsubsec log examples
 
-Contributed examples are gratefully accepted.
+@cindex Timezone, in output
+@cindex Zone, time, in output
+Since @code{log} shows dates in local time,
+you might want to see them in Coordinated Universal Time (UTC) or
+some other timezone.
+To do this you can set your @code{$TZ} environment
+variable before invoking @sc{cvs}:
+
+@example
+$ TZ=UTC cvs log foo.c
+$ TZ=EST cvs log bar.c
+@end example
+
+(If you are using a @code{csh}-style shell, like @code{tcsh},
+you would need to prefix the examples above with @code{env}.)
 
 @c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
 @node ls & rls
Index: src/ChangeLog
===================================================================
RCS file: /cvsroot/ccvs/src/ChangeLog,v
retrieving revision 1.2803
diff -u -p -r1.2803 ChangeLog
--- src/ChangeLog       5 May 2004 16:19:04 -0000       1.2803
+++ src/ChangeLog       5 May 2004 19:30:39 -0000
@@ -1,3 +1,11 @@
+2004-05-05  Bart Robinson  <lomew@pobox.com>
+
+       * client.c (handle_mt): Handle the new "date" MT response
+       * server.c (cvs_output_tagged): Likewise
+       * cvs.h: Proto for format_date_alloc
+       * main.c (format_date_alloc, tm_diff): Added.
+       * log.c (log_version): Use MT response to tag date output.
+       
 2004-05-05  Derek Price  <derek@ximbiot.com>
 
        * commit.c: Some gratuitous reformatting.
Index: src/client.c
===================================================================
RCS file: /cvsroot/ccvs/src/client.c,v
retrieving revision 1.371
diff -u -p -r1.371 client.c
--- src/client.c        28 Apr 2004 04:20:33 -0000      1.371
+++ src/client.c        5 May 2004 19:30:40 -0000
@@ -2735,6 +2735,12 @@ handle_mt( char *args, int len )
            }
            else if (strcmp (tag, "newline") == 0)
                printf ("\n");
+           else if (strcmp (tag, "date") == 0)
+           {
+               char *date = format_date_alloc (text);
+               printf ("%s", date);
+               free (date);
+           }
            else if (text != NULL)
                printf ("%s", text);
     }
Index: src/cvs.h
===================================================================
RCS file: /cvsroot/ccvs/src/cvs.h,v
retrieving revision 1.291
diff -u -p -r1.291 cvs.h
--- src/cvs.h   28 Apr 2004 04:20:33 -0000      1.291
+++ src/cvs.h   5 May 2004 19:30:40 -0000
@@ -431,6 +431,7 @@ char *date_from_time_t (time_t);
 void date_to_internet (char *, const char *);
 void date_to_tm (struct tm *, const char *);
 void tm_to_internet (char *, const struct tm *);
+char *format_date_alloc (const char *text);
 
 char *Name_Repository (const char *dir, const char *update_dir);
 const char *Short_Repository (const char *repository);
Index: src/log.c
===================================================================
RCS file: /cvsroot/ccvs/src/log.c,v
retrieving revision 1.94
diff -u -p -r1.94 log.c
--- src/log.c   2 Apr 2004 19:56:22 -0000       1.94
+++ src/log.c   5 May 2004 19:30:40 -0000
@@ -1566,22 +1566,23 @@ log_version (struct log_data *log_data, 
        cvs_output (p->data, 0);
        cvs_output (";", 1);
     }
+    cvs_output ("\n", 1);
 
-    cvs_output ("\ndate: ", 0);
+    cvs_output_tagged ("text", "date: ");
     (void)sscanf (ver->date, SDATEFORM, &year, &mon, &mday, &hour, &min,
                  &sec);
     if (year < 1900)
        year += 1900;
-    sprintf (buf, "%04d/%02d/%02d %02d:%02d:%02d", year, mon, mday,
+    sprintf (buf, "%04d-%02d-%02d %02d:%02d:%02d", year, mon, mday,
             hour, min, sec);
-    cvs_output (buf, 0);
+    cvs_output_tagged ("date", buf);
 
-    cvs_output (";  author: ", 0);
-    cvs_output (ver->author, 0);
+    cvs_output_tagged ("text", ";  author: ");
+    cvs_output_tagged ("text", ver->author);
 
-    cvs_output (";  state: ", 0);
-    cvs_output (ver->state, 0);
-    cvs_output (";", 1);
+    cvs_output_tagged ("text", ";  state: ");
+    cvs_output_tagged ("text", ver->state);
+    cvs_output_tagged ("text", ";");
 
     if (! trunk)
     {
@@ -1609,20 +1610,20 @@ log_version (struct log_data *log_data, 
 
     if (padd != NULL)
     {
-       cvs_output ("  lines: +", 0);
-       cvs_output (padd->data, 0);
-       cvs_output (" -", 2);
-       cvs_output (pdel->data, 0);
+       cvs_output_tagged ("text", "  lines: +");
+       cvs_output_tagged ("text", padd->data);
+       cvs_output_tagged ("text", " -");
+       cvs_output_tagged ("text", pdel->data);
     }
+    cvs_output_tagged ("newline", NULL);
 
     if (ver->branches != NULL)
     {
-       cvs_output ("\nbranches:", 0);
+       cvs_output ("branches:", 0);
        walklist (ver->branches, log_branch, NULL);
+       cvs_output ("\n", 1);
     }
 
-    cvs_output ("\n", 1);
-
     p = findnode (ver->other, "log");
     /* The p->date == NULL case is the normal one for an empty log
        message (rcs-14 in sanity.sh).  I don't think the case where
Index: src/main.c
===================================================================
RCS file: /cvsroot/ccvs/src/main.c,v
retrieving revision 1.208
diff -u -p -r1.208 main.c
--- src/main.c  28 Apr 2004 04:20:33 -0000      1.208
+++ src/main.c  5 May 2004 19:30:40 -0000
@@ -1190,6 +1190,88 @@ tm_to_internet (char *dest, const struct
             source->tm_year + 1900, source->tm_hour, source->tm_min, 
source->tm_sec);
 }
 
+/* Yield the difference between *A and *B,
+   measured in seconds, ignoring leap seconds.
+   The body of this function is taken directly from the GNU C Library;
+   see src/strftime.c.  */
+#ifndef TM_YEAR_BASE
+#define TM_YEAR_BASE 1900
+#endif
+static long int
+tm_diff (struct tm const *a, struct tm const *b)
+{
+  /* Compute intervening leap days correctly even if year is negative.
+     Take care to avoid int overflow in leap day calculations.  */
+  int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
+  int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
+  int a100 = a4 / 25 - (a4 % 25 < 0);
+  int b100 = b4 / 25 - (b4 % 25 < 0);
+  int a400 = a100 >> 2;
+  int b400 = b100 >> 2;
+  int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
+  long int ayear = a->tm_year;
+  long int years = ayear - b->tm_year;
+  long int days = (365 * years + intervening_leap_days
+                  + (a->tm_yday - b->tm_yday));
+  return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
+               + (a->tm_min - b->tm_min))
+         + (a->tm_sec - b->tm_sec));
+}
+
+/*
+ * Format a date for the current locale.
+ *
+ * Input looks like
+ *     2004-04-29 20:24:22
+ * Output looks the same (for GMT) or with +/-HHMM added to the end, like
+ *     2004-04-29 13:24:22-0700
+ */
+char *
+format_date_alloc (const char *datestr)
+{
+    struct timespec ts;
+    long gmtoff;
+    struct tm ltm, gtm;
+    char *buf;
+    size_t len = 0;
+
+    /*
+     * Get the date into a timespec so we can create struct tm's from it.
+     */
+    buf = asnprintf (NULL, &len, "%s GMT", datestr);
+    if (! get_date (&ts, buf, NULL))
+    {
+       free (buf);
+       goto as_is;
+    }
+    free (buf);
+    len = 0;
+
+    /*
+     * Convert to localtime and calculate the offset.
+     * The offset is used for printing the -HHMM part.
+     */
+    ltm = *(localtime (&ts.tv_sec));
+    gtm = *(gmtime (&ts.tv_sec));
+    gmtoff = tm_diff (&ltm, &gtm);
+
+    /*
+     * Format it and return.
+     */
+    if (gmtoff == 0)
+       goto as_is;                     /* don't add +0000 */
+    buf = asnprintf (NULL, &len, "%04d-%02d-%02d %02d:%02d:%02d%c%02d%02d",
+                    1900 + ltm.tm_year, ltm.tm_mon + 1, ltm.tm_mday,
+                    ltm.tm_hour, ltm.tm_min, ltm.tm_sec,
+                    (gmtoff < 0) ? '-' : '+',
+                    abs (gmtoff) / (60*60),
+                    (abs (gmtoff) % (60*60)) / 60);
+    return buf;
+
+ as_is:
+    return strdup (datestr);
+}
+
 void
 usage (register const char *const *cpp)
 {
Index: src/server.c
===================================================================
RCS file: /cvsroot/ccvs/src/server.c,v
retrieving revision 1.357
diff -u -p -r1.357 server.c
--- src/server.c        28 Apr 2004 04:20:33 -0000      1.357
+++ src/server.c        5 May 2004 19:30:41 -0000
@@ -6587,8 +6587,15 @@ cvs_output_tagged (const char *tag, cons
     else
 #endif
     {
+       /* No MT support or we are using a local repository. */
        if (strcmp (tag, "newline") == 0)
            cvs_output ("\n", 1);
+       else if (strcmp (tag, "date") == 0)
+       {
+           char *date = format_date_alloc (text);
+           cvs_output (date, 0);
+           free (date);
+       }
        else if (text != NULL)
            cvs_output (text, 0);
     }




reply via email to

[Prev in Thread] Current Thread [Next in Thread]