emacs-diffs
[Top][All Lists]
Advanced

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

[Emacs-diffs] master fdb1ba1: Support OFFSET and (OFFSET ABBR) time zone


From: Paul Eggert
Subject: [Emacs-diffs] master fdb1ba1: Support OFFSET and (OFFSET ABBR) time zone rules
Date: Tue, 12 Apr 2016 16:19:42 +0000

branch: master
commit fdb1ba144ca61185e6457f092f38f59dd9bbe6a0
Author: Paul Eggert <address@hidden>
Commit: Paul Eggert <address@hidden>

    Support OFFSET and (OFFSET ABBR) time zone rules
    
    This simplifies Gnus and VC time zone support, by letting them
    feed the output of ‘current-time-zone’ and ‘decode time’ to
    primitives that accept time zone arguments.
    * doc/lispref/os.texi (Time Zone Rules, Time Conversion):
    * etc/NEWS:
    * lisp/gnus/message.el (message-insert-formatted-citation-line):
    * lisp/org/org.el (org-timestamp-format):
    * src/editfns.c (Fformat_time_string, Fdecode_time):
    (Fcurrent_time_string, Fcurrent_time_zone, Fset_time_zone_rule):
    Document new behavior.
    * lisp/gnus/gmm-utils.el (gmm-format-time-string):
    * lisp/vc/add-log.el (add-log-iso8601-time-zone):
    Mark as obsolete, as it is now just an alias or narrow wrapper
    around format-time-string.
    * src/editfns.c (tzlookup): Also support integer OFFSET and
    list (OFFSET ABBR) as time zone rules.
    (Fencode_time): No longer need a special case for a cons ZONE.
    (Fcurrent_time_zone): If the time zone string is missing, compute
    it the same way the other new code does.
---
 doc/lispref/os.texi    |   11 +++--
 etc/NEWS               |    8 ++++
 lisp/gnus/gmm-utils.el |   33 +--------------
 lisp/gnus/message.el   |    9 +++-
 lisp/org/org.el        |    6 ++-
 lisp/vc/add-log.el     |   19 ++-------
 src/editfns.c          |  104 +++++++++++++++++++++++++++++++++++------------
 7 files changed, 108 insertions(+), 82 deletions(-)

diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi
index 6e0edec..becb691 100644
--- a/doc/lispref/os.texi
+++ b/doc/lispref/os.texi
@@ -1325,7 +1325,12 @@ omitted or @code{nil}, the conversion uses Emacs's 
default time zone.
 If it is @code{t}, the conversion uses Universal Time.  If it is
 @code{wall}, the conversion uses the system wall clock time.  If it is
 a string, the conversion uses the time zone rule equivalent to setting
address@hidden to that string.
address@hidden to that string.  If it is an integer @var{offset}, the
+conversion uses a fixed time zone with the given offset and a numeric
+abbreviation.  If it is a list (@var{offset} @var{abbr}), where
address@hidden is an integer number of seconds east of Universal Time
+and @var{abbr} is a string, the conversion uses a fixed time zone with
+the given offset and abbreviation.
 
 @defun current-time-zone &optional time zone
 @cindex time zone, current
@@ -1423,10 +1428,6 @@ yourself before you call @code{encode-time}.
 
 The optional argument @var{zone} defaults to the current time zone rule.
 @xref{Time Zone Rules}.
-In addition to the usual time zone rule values, it can also be a list
-(as you would get from @code{current-time-zone}) or an integer (as
-from @code{decode-time}), applied without any further alteration for
-daylight saving time.
 
 If you pass more than seven arguments to @code{encode-time}, the first
 six are used as @var{seconds} through @var{year}, the last argument is
diff --git a/etc/NEWS b/etc/NEWS
index 00f5aad..5ebff62 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -228,6 +228,14 @@ two objects are 'eq' ('eql'), then the result of 
'sxhash-eq'
 consistency with the new functions.  For compatibility, 'sxhash'
 remains as an alias to 'sxhash-equal'.
 
++++
+** Time conversion functions that accept a time zone rule argument now
+allow it to be OFFSET or a list (OFFSET ABBR), where the integer
+OFFSET is a count of seconds east of Universal Time, and the string
+ABBR is a time zone abbreviation.  The affected functions are
+'current-time-string', 'current-time-zone', 'decode-time',
+'format-time-string', and 'set-time-zone-rule'.
+
 
 * Changes in Emacs 25.2 on Non-Free Operating Systems
 
diff --git a/lisp/gnus/gmm-utils.el b/lisp/gnus/gmm-utils.el
index f6455cf..7aa5279 100644
--- a/lisp/gnus/gmm-utils.el
+++ b/lisp/gnus/gmm-utils.el
@@ -256,37 +256,8 @@ If mode is nil, use `major-mode' of the current buffer."
                 (string-match "^\\(.+\\)-mode$" mode)
                 (match-string 1 mode))))))
 
-(defun gmm-format-time-string (format-string &optional time tz)
-  "Use FORMAT-STRING to format the time TIME, or now if omitted.
-The optional TZ specifies the time zone in a number of seconds; any
-other non-nil value will be treated as 0.  Note that both the format
-specifiers `%Z' and `%z' will be replaced with a numeric form. "
-;; FIXME: is there a smart way to replace %Z with a time zone name?
-  (if (and (numberp tz) (not (zerop tz)))
-      (let ((st 0)
-           (case-fold-search t)
-           ls nd rest)
-       (setq time (if time
-                      (copy-sequence time)
-                    (current-time)))
-       (if (>= (setq ls (- (cadr time) (car (current-time-zone)) (- tz))) 0)
-           (setcar (cdr time) ls)
-         (setcar (cdr time) (+ ls 65536))
-         (setcar time (1- (car time))))
-       (setq tz (format "%s%02d%02d"
-                        (if (>= tz 0) "+" "-")
-                        (/ (abs tz) 3600)
-                        (/ (% (abs tz) 3600) 60)))
-       (while (string-match "%+z" format-string st)
-         (if (zerop (% (- (setq nd (match-end 0)) (match-beginning 0)) 2))
-             (progn
-               (push (substring format-string st (- nd 2)) rest)
-               (push tz rest))
-           (push (substring format-string st nd) rest))
-         (setq st nd))
-       (push (substring format-string st) rest)
-       (format-time-string (apply 'concat (nreverse rest)) time))
-    (format-time-string format-string time t)))
+(define-obsolete-function-alias 'gmm-format-time-string 'format-time-string
+  "25.2")
 
 (provide 'gmm-utils)
 
diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el
index 14d8d30..32d740b 100644
--- a/lisp/gnus/message.el
+++ b/lisp/gnus/message.el
@@ -3879,8 +3879,13 @@ This function uses `mail-citation-hook' if that is 
non-nil."
 (defun message-insert-formatted-citation-line (&optional from date tz)
   "Function that inserts a formatted citation line.
 The optional FROM, and DATE are strings containing the contents of
-the From header and the Date header respectively.  The optional TZ
-is a number of seconds, overrides the time zone of DATE.
+the From header and the Date header respectively.
+
+The optional TZ is omitted or nil for Emacs local time, t for
+Universal Time, `wall' for system wall clock time, or a string as
+in the TZ environment variable.  It can also be a list (as from
+`current-time-zone') or an integer (as from `decode-time')
+applied without consideration for daylight saving time.
 
 See `message-citation-line-format'."
   ;; The optional args are for testing/debugging.  They will disappear later.
diff --git a/lisp/org/org.el b/lisp/org/org.el
index 231daa9..3abf627 100644
--- a/lisp/org/org.el
+++ b/lisp/org/org.el
@@ -22673,8 +22673,10 @@ When optional argument END is non-nil, use end of 
date-range or
 time-range, if possible.
 
 The optional ZONE is omitted or nil for Emacs local time, t for
-Universal Time, `wall' for system wall clock time, or a string as in
-the TZ environment variable."
+Universal Time, `wall' for system wall clock time, or a string as
+in the TZ environment variable.  It can also be a list (as from
+`current-time-zone') or an integer (as from `decode-time')
+applied without consideration for daylight saving time."
   (format-time-string
    format
    (apply 'encode-time
diff --git a/lisp/vc/add-log.el b/lisp/vc/add-log.el
index 58a4e77..9076d83 100644
--- a/lisp/vc/add-log.el
+++ b/lisp/vc/add-log.el
@@ -590,25 +590,14 @@ If a string, interpret as the ZONE argument of 
`format-time-string'.")
      (lambda (x) (or (booleanp x) (stringp x))))
 
 (defun add-log-iso8601-time-zone (&optional time zone)
-  (let* ((utc-offset (or (car (current-time-zone time zone)) 0))
-        (sign (if (< utc-offset 0) ?- ?+))
-        (sec (abs utc-offset))
-        (ss (% sec 60))
-        (min (/ sec 60))
-        (mm (% min 60))
-        (hh (/ min 60)))
-    (format (cond ((not (zerop ss)) "%c%02d:%02d:%02d")
-                 ((not (zerop mm)) "%c%02d:%02d")
-                 (t "%c%02d"))
-           sign hh mm ss)))
+  (declare (obsolete nil "25.2"))
+  (format-time-string "%:::z" time zone))
 
 (defvar add-log-iso8601-with-time-zone nil)
 
 (defun add-log-iso8601-time-string (&optional time zone)
-  (let ((date (format-time-string "%Y-%m-%d" time zone)))
-    (if add-log-iso8601-with-time-zone
-        (concat date " " (add-log-iso8601-time-zone time zone))
-      date)))
+  (format-time-string
+   (if add-log-iso8601-with-time-zone "%Y-%m-%d %:::z" "%Y-%m-%d") time zone))
 
 (defun change-log-name ()
   "Return (system-dependent) default name for a change log file."
diff --git a/src/editfns.c b/src/editfns.c
index 70285e6..48f2a8d 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -146,8 +146,6 @@ xtzfree (timezone_t tz)
 static timezone_t
 tzlookup (Lisp_Object zone, bool settz)
 {
-  static char const tzbuf_format[] = "XXX%s%"pI"d:%02d:%02d";
-  char tzbuf[sizeof tzbuf_format + INT_STRLEN_BOUND (EMACS_INT)];
   char const *zone_string;
   timezone_t new_tz;
 
@@ -160,16 +158,53 @@ tzlookup (Lisp_Object zone, bool settz)
     }
   else
     {
+      static char const tzbuf_format[] = "<%+.*"pI"d>%s%"pI"d:%02d:%02d";
+      char const *trailing_tzbuf_format = tzbuf_format + sizeof "<%+.*"pI"d" - 
1;
+      char tzbuf[sizeof tzbuf_format + 2 * INT_STRLEN_BOUND (EMACS_INT)];
+      bool plain_integer = INTEGERP (zone);
+
       if (EQ (zone, Qwall))
        zone_string = 0;
       else if (STRINGP (zone))
-       zone_string = SSDATA (zone);
-      else if (INTEGERP (zone))
+       zone_string = SSDATA (ENCODE_SYSTEM (zone));
+      else if (plain_integer || (CONSP (zone) && INTEGERP (XCAR (zone))
+                                && CONSP (XCDR (zone))))
        {
+         Lisp_Object abbr;
+         if (!plain_integer)
+           {
+             abbr = XCAR (XCDR (zone));
+             zone = XCAR (zone);
+           }
+
          EMACS_INT abszone = eabs (XINT (zone)), hour = abszone / (60 * 60);
-         int min = (abszone / 60) % 60, sec = abszone % 60;
-         sprintf (tzbuf, tzbuf_format, &"-"[XINT (zone) < 0], hour, min, sec);
-         zone_string = tzbuf;
+         int hour_remainder = abszone % (60 * 60);
+         int min = hour_remainder / 60, sec = hour_remainder % 60;
+
+         if (plain_integer)
+           {
+             int prec = 2;
+             EMACS_INT numzone = hour;
+             if (hour_remainder != 0)
+               {
+                 prec += 2, numzone = 100 * numzone + min;
+                 if (sec != 0)
+                   prec += 2, numzone = 100 * numzone + sec;
+               }
+             sprintf (tzbuf, tzbuf_format, prec, numzone,
+                      &"-"[XINT (zone) < 0], hour, min, sec);
+             zone_string = tzbuf;
+           }
+         else
+           {
+             AUTO_STRING (leading, "<");
+             AUTO_STRING_WITH_LEN (trailing, tzbuf,
+                                   sprintf (tzbuf, trailing_tzbuf_format,
+                                            &"-"[XINT (zone) < 0],
+                                            hour, min, sec));
+             zone_string = SSDATA (concat3 (leading, ENCODE_SYSTEM (abbr),
+                                            trailing));
+           }
        }
       else
        xsignal2 (Qerror, build_string ("Invalid time zone specification"),
@@ -1969,9 +2004,13 @@ DEFUN ("format-time-string", Fformat_time_string, 
Sformat_time_string, 1, 3, 0,
        doc: /* Use FORMAT-STRING to format the time TIME, or now if omitted.
 TIME is specified as (HIGH LOW USEC PSEC), as returned by
 `current-time' or `file-attributes'.  The obsolete form (HIGH . LOW)
-is also still accepted.  The optional ZONE is omitted or nil for Emacs
-local time, t for Universal Time, `wall' for system wall clock time,
-or a string as in the TZ environment variable.
+is also still accepted.
+
+The optional ZONE is omitted or nil for Emacs local time, t for
+Universal Time, `wall' for system wall clock time, or a string as in
+the TZ environment variable.  It can also be a list (as from
+`current-time-zone') or an integer (as from `decode-time') applied
+without consideration for daylight saving time.
 
 The value is a copy of FORMAT-STRING, but with certain constructs replaced
 by text that describes the specified date and time in TIME:
@@ -2085,9 +2124,12 @@ DEFUN ("decode-time", Fdecode_time, Sdecode_time, 0, 2, 
0,
 The optional SPECIFIED-TIME should be a list of (HIGH LOW . IGNORED),
 as from `current-time' and `file-attributes', or nil to use the
 current time.  The obsolete form (HIGH . LOW) is also still accepted.
+
 The optional ZONE is omitted or nil for Emacs local time, t for
 Universal Time, `wall' for system wall clock time, or a string as in
-the TZ environment variable.
+the TZ environment variable.  It can also be a list (as from
+`current-time-zone') or an integer (as from `decode-time') applied
+without consideration for daylight saving time.
 
 The list has the following nine members: SEC is an integer between 0
 and 60; SEC is 60 for a leap second, which only some operating systems
@@ -2150,6 +2192,7 @@ check_tm_member (Lisp_Object obj, int offset)
 DEFUN ("encode-time", Fencode_time, Sencode_time, 6, MANY, 0,
        doc: /* Convert SECOND, MINUTE, HOUR, DAY, MONTH, YEAR and ZONE to 
internal time.
 This is the reverse operation of `decode-time', which see.
+
 The optional ZONE is omitted or nil for Emacs local time, t for
 Universal Time, `wall' for system wall clock time, or a string as in
 the TZ environment variable.  It can also be a list (as from
@@ -2184,8 +2227,6 @@ usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR 
&optional ZONE)  */)
   tm.tm_year = check_tm_member (args[5], TM_YEAR_BASE);
   tm.tm_isdst = -1;
 
-  if (CONSP (zone))
-    zone = XCAR (zone);
   timezone_t tz = tzlookup (zone, false);
   value = emacs_mktime_z (tz, &tm);
   xtzfree (tz);
@@ -2214,7 +2255,9 @@ but this is considered obsolete.
 
 The optional ZONE is omitted or nil for Emacs local time, t for
 Universal Time, `wall' for system wall clock time, or a string as in
-the TZ environment variable.  */)
+the TZ environment variable.  It can also be a list (as from
+`current-time-zone') or an integer (as from `decode-time') applied
+without consideration for daylight saving time.  */)
   (Lisp_Object specified_time, Lisp_Object zone)
 {
   time_t value = lisp_seconds_argument (specified_time);
@@ -2290,8 +2333,12 @@ instead of using the current time.  The argument should 
have the form
 \(HIGH LOW . IGNORED).  Thus, you can use times obtained from
 `current-time' and from `file-attributes'.  SPECIFIED-TIME can also
 have the form (HIGH . LOW), but this is considered obsolete.
-Optional second arg ZONE is omitted or nil for the local time zone, or
-a string as in the TZ environment variable.
+
+The optional ZONE is omitted or nil for Emacs local time, t for
+Universal Time, `wall' for system wall clock time, or a string as in
+the TZ environment variable.  It can also be a list (as from
+`current-time-zone') or an integer (as from `decode-time') applied
+without consideration for daylight saving time.
 
 Some operating systems cannot provide all this information to Emacs;
 in this case, `current-time-zone' returns a list containing nil for
@@ -2315,15 +2362,18 @@ the data it can't find.  */)
       zone_offset = make_number (offset);
       if (SCHARS (zone_name) == 0)
        {
-         /* No local time zone name is available; use "+-NNNN" instead.  */
-         long int m = offset / 60;
-         long int am = offset < 0 ? - m : m;
-         long int hour = am / 60;
-         int min = am % 60;
-         char buf[sizeof "+00" + INT_STRLEN_BOUND (long int)];
-         zone_name = make_formatted_string (buf, "%c%02ld%02d",
+         /* No local time zone name is available; use numeric zone instead.  */
+         long int hour = offset / 3600;
+         int min_sec = offset % 3600;
+         int amin_sec = min_sec < 0 ? - min_sec : min_sec;
+         int min = amin_sec / 60;
+         int sec = amin_sec % 60;
+         int min_prec = min_sec ? 2 : 0;
+         int sec_prec = sec ? 2 : 0;
+         char buf[sizeof "+0000" + INT_STRLEN_BOUND (long int)];
+         zone_name = make_formatted_string (buf, "%c%.2ld%.*d%.*d",
                                             (offset < 0 ? '-' : '+'),
-                                            hour, min);
+                                            hour, min_prec, min, sec_prec, 
sec);
        }
     }
 
@@ -2332,11 +2382,11 @@ the data it can't find.  */)
 
 DEFUN ("set-time-zone-rule", Fset_time_zone_rule, Sset_time_zone_rule, 1, 1, 0,
        doc: /* Set the Emacs local time zone using TZ, a string specifying a 
time zone rule.
-
 If TZ is nil or `wall', use system wall clock time; this differs from
 the usual Emacs convention where nil means current local time.  If TZ
-is t, use Universal Time.  If TZ is an integer, treat it as in
-`encode-time'.
+is t, use Universal Time.  If TZ is a list (as from
+`current-time-zone') or an integer (as from `decode-time'), use the
+specified time zone without consideration for daylight saving time.
 
 Instead of calling this function, you typically want something else.
 To temporarily use a different time zone rule for just one invocation



reply via email to

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