diff options
| author | Paul Eggert | 2016-04-12 09:19:11 -0700 |
|---|---|---|
| committer | Paul Eggert | 2016-04-12 09:19:38 -0700 |
| commit | fdb1ba144ca61185e6457f092f38f59dd9bbe6a0 (patch) | |
| tree | 5048d1fbb946faf0b6059e4d4375bb514b3bfa74 /src | |
| parent | 7c2c2196fd4be0b656bdf0e0b68f3d7c4a5eca08 (diff) | |
| download | emacs-fdb1ba144ca61185e6457f092f38f59dd9bbe6a0.tar.gz emacs-fdb1ba144ca61185e6457f092f38f59dd9bbe6a0.zip | |
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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/editfns.c | 104 |
1 files changed, 77 insertions, 27 deletions
diff --git a/src/editfns.c b/src/editfns.c index 70285e6d5db..48f2a8de126 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -146,8 +146,6 @@ xtzfree (timezone_t tz) | |||
| 146 | static timezone_t | 146 | static timezone_t |
| 147 | tzlookup (Lisp_Object zone, bool settz) | 147 | tzlookup (Lisp_Object zone, bool settz) |
| 148 | { | 148 | { |
| 149 | static char const tzbuf_format[] = "XXX%s%"pI"d:%02d:%02d"; | ||
| 150 | char tzbuf[sizeof tzbuf_format + INT_STRLEN_BOUND (EMACS_INT)]; | ||
| 151 | char const *zone_string; | 149 | char const *zone_string; |
| 152 | timezone_t new_tz; | 150 | timezone_t new_tz; |
| 153 | 151 | ||
| @@ -160,16 +158,53 @@ tzlookup (Lisp_Object zone, bool settz) | |||
| 160 | } | 158 | } |
| 161 | else | 159 | else |
| 162 | { | 160 | { |
| 161 | static char const tzbuf_format[] = "<%+.*"pI"d>%s%"pI"d:%02d:%02d"; | ||
| 162 | char const *trailing_tzbuf_format = tzbuf_format + sizeof "<%+.*"pI"d" - 1; | ||
| 163 | char tzbuf[sizeof tzbuf_format + 2 * INT_STRLEN_BOUND (EMACS_INT)]; | ||
| 164 | bool plain_integer = INTEGERP (zone); | ||
| 165 | |||
| 163 | if (EQ (zone, Qwall)) | 166 | if (EQ (zone, Qwall)) |
| 164 | zone_string = 0; | 167 | zone_string = 0; |
| 165 | else if (STRINGP (zone)) | 168 | else if (STRINGP (zone)) |
| 166 | zone_string = SSDATA (zone); | 169 | zone_string = SSDATA (ENCODE_SYSTEM (zone)); |
| 167 | else if (INTEGERP (zone)) | 170 | else if (plain_integer || (CONSP (zone) && INTEGERP (XCAR (zone)) |
| 171 | && CONSP (XCDR (zone)))) | ||
| 168 | { | 172 | { |
| 173 | Lisp_Object abbr; | ||
| 174 | if (!plain_integer) | ||
| 175 | { | ||
| 176 | abbr = XCAR (XCDR (zone)); | ||
| 177 | zone = XCAR (zone); | ||
| 178 | } | ||
| 179 | |||
| 169 | EMACS_INT abszone = eabs (XINT (zone)), hour = abszone / (60 * 60); | 180 | EMACS_INT abszone = eabs (XINT (zone)), hour = abszone / (60 * 60); |
| 170 | int min = (abszone / 60) % 60, sec = abszone % 60; | 181 | int hour_remainder = abszone % (60 * 60); |
| 171 | sprintf (tzbuf, tzbuf_format, &"-"[XINT (zone) < 0], hour, min, sec); | 182 | int min = hour_remainder / 60, sec = hour_remainder % 60; |
| 172 | zone_string = tzbuf; | 183 | |
| 184 | if (plain_integer) | ||
| 185 | { | ||
| 186 | int prec = 2; | ||
| 187 | EMACS_INT numzone = hour; | ||
| 188 | if (hour_remainder != 0) | ||
| 189 | { | ||
| 190 | prec += 2, numzone = 100 * numzone + min; | ||
| 191 | if (sec != 0) | ||
| 192 | prec += 2, numzone = 100 * numzone + sec; | ||
| 193 | } | ||
| 194 | sprintf (tzbuf, tzbuf_format, prec, numzone, | ||
| 195 | &"-"[XINT (zone) < 0], hour, min, sec); | ||
| 196 | zone_string = tzbuf; | ||
| 197 | } | ||
| 198 | else | ||
| 199 | { | ||
| 200 | AUTO_STRING (leading, "<"); | ||
| 201 | AUTO_STRING_WITH_LEN (trailing, tzbuf, | ||
| 202 | sprintf (tzbuf, trailing_tzbuf_format, | ||
| 203 | &"-"[XINT (zone) < 0], | ||
| 204 | hour, min, sec)); | ||
| 205 | zone_string = SSDATA (concat3 (leading, ENCODE_SYSTEM (abbr), | ||
| 206 | trailing)); | ||
| 207 | } | ||
| 173 | } | 208 | } |
| 174 | else | 209 | else |
| 175 | xsignal2 (Qerror, build_string ("Invalid time zone specification"), | 210 | 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, | |||
| 1969 | doc: /* Use FORMAT-STRING to format the time TIME, or now if omitted. | 2004 | doc: /* Use FORMAT-STRING to format the time TIME, or now if omitted. |
| 1970 | TIME is specified as (HIGH LOW USEC PSEC), as returned by | 2005 | TIME is specified as (HIGH LOW USEC PSEC), as returned by |
| 1971 | `current-time' or `file-attributes'. The obsolete form (HIGH . LOW) | 2006 | `current-time' or `file-attributes'. The obsolete form (HIGH . LOW) |
| 1972 | is also still accepted. The optional ZONE is omitted or nil for Emacs | 2007 | is also still accepted. |
| 1973 | local time, t for Universal Time, `wall' for system wall clock time, | 2008 | |
| 1974 | or a string as in the TZ environment variable. | 2009 | The optional ZONE is omitted or nil for Emacs local time, t for |
| 2010 | Universal Time, `wall' for system wall clock time, or a string as in | ||
| 2011 | the TZ environment variable. It can also be a list (as from | ||
| 2012 | `current-time-zone') or an integer (as from `decode-time') applied | ||
| 2013 | without consideration for daylight saving time. | ||
| 1975 | 2014 | ||
| 1976 | The value is a copy of FORMAT-STRING, but with certain constructs replaced | 2015 | The value is a copy of FORMAT-STRING, but with certain constructs replaced |
| 1977 | by text that describes the specified date and time in TIME: | 2016 | 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, | |||
| 2085 | The optional SPECIFIED-TIME should be a list of (HIGH LOW . IGNORED), | 2124 | The optional SPECIFIED-TIME should be a list of (HIGH LOW . IGNORED), |
| 2086 | as from `current-time' and `file-attributes', or nil to use the | 2125 | as from `current-time' and `file-attributes', or nil to use the |
| 2087 | current time. The obsolete form (HIGH . LOW) is also still accepted. | 2126 | current time. The obsolete form (HIGH . LOW) is also still accepted. |
| 2127 | |||
| 2088 | The optional ZONE is omitted or nil for Emacs local time, t for | 2128 | The optional ZONE is omitted or nil for Emacs local time, t for |
| 2089 | Universal Time, `wall' for system wall clock time, or a string as in | 2129 | Universal Time, `wall' for system wall clock time, or a string as in |
| 2090 | the TZ environment variable. | 2130 | the TZ environment variable. It can also be a list (as from |
| 2131 | `current-time-zone') or an integer (as from `decode-time') applied | ||
| 2132 | without consideration for daylight saving time. | ||
| 2091 | 2133 | ||
| 2092 | The list has the following nine members: SEC is an integer between 0 | 2134 | The list has the following nine members: SEC is an integer between 0 |
| 2093 | and 60; SEC is 60 for a leap second, which only some operating systems | 2135 | 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) | |||
| 2150 | DEFUN ("encode-time", Fencode_time, Sencode_time, 6, MANY, 0, | 2192 | DEFUN ("encode-time", Fencode_time, Sencode_time, 6, MANY, 0, |
| 2151 | doc: /* Convert SECOND, MINUTE, HOUR, DAY, MONTH, YEAR and ZONE to internal time. | 2193 | doc: /* Convert SECOND, MINUTE, HOUR, DAY, MONTH, YEAR and ZONE to internal time. |
| 2152 | This is the reverse operation of `decode-time', which see. | 2194 | This is the reverse operation of `decode-time', which see. |
| 2195 | |||
| 2153 | The optional ZONE is omitted or nil for Emacs local time, t for | 2196 | The optional ZONE is omitted or nil for Emacs local time, t for |
| 2154 | Universal Time, `wall' for system wall clock time, or a string as in | 2197 | Universal Time, `wall' for system wall clock time, or a string as in |
| 2155 | the TZ environment variable. It can also be a list (as from | 2198 | 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) */) | |||
| 2184 | tm.tm_year = check_tm_member (args[5], TM_YEAR_BASE); | 2227 | tm.tm_year = check_tm_member (args[5], TM_YEAR_BASE); |
| 2185 | tm.tm_isdst = -1; | 2228 | tm.tm_isdst = -1; |
| 2186 | 2229 | ||
| 2187 | if (CONSP (zone)) | ||
| 2188 | zone = XCAR (zone); | ||
| 2189 | timezone_t tz = tzlookup (zone, false); | 2230 | timezone_t tz = tzlookup (zone, false); |
| 2190 | value = emacs_mktime_z (tz, &tm); | 2231 | value = emacs_mktime_z (tz, &tm); |
| 2191 | xtzfree (tz); | 2232 | xtzfree (tz); |
| @@ -2214,7 +2255,9 @@ but this is considered obsolete. | |||
| 2214 | 2255 | ||
| 2215 | The optional ZONE is omitted or nil for Emacs local time, t for | 2256 | The optional ZONE is omitted or nil for Emacs local time, t for |
| 2216 | Universal Time, `wall' for system wall clock time, or a string as in | 2257 | Universal Time, `wall' for system wall clock time, or a string as in |
| 2217 | the TZ environment variable. */) | 2258 | the TZ environment variable. It can also be a list (as from |
| 2259 | `current-time-zone') or an integer (as from `decode-time') applied | ||
| 2260 | without consideration for daylight saving time. */) | ||
| 2218 | (Lisp_Object specified_time, Lisp_Object zone) | 2261 | (Lisp_Object specified_time, Lisp_Object zone) |
| 2219 | { | 2262 | { |
| 2220 | time_t value = lisp_seconds_argument (specified_time); | 2263 | time_t value = lisp_seconds_argument (specified_time); |
| @@ -2290,8 +2333,12 @@ instead of using the current time. The argument should have the form | |||
| 2290 | \(HIGH LOW . IGNORED). Thus, you can use times obtained from | 2333 | \(HIGH LOW . IGNORED). Thus, you can use times obtained from |
| 2291 | `current-time' and from `file-attributes'. SPECIFIED-TIME can also | 2334 | `current-time' and from `file-attributes'. SPECIFIED-TIME can also |
| 2292 | have the form (HIGH . LOW), but this is considered obsolete. | 2335 | have the form (HIGH . LOW), but this is considered obsolete. |
| 2293 | Optional second arg ZONE is omitted or nil for the local time zone, or | 2336 | |
| 2294 | a string as in the TZ environment variable. | 2337 | The optional ZONE is omitted or nil for Emacs local time, t for |
| 2338 | Universal Time, `wall' for system wall clock time, or a string as in | ||
| 2339 | the TZ environment variable. It can also be a list (as from | ||
| 2340 | `current-time-zone') or an integer (as from `decode-time') applied | ||
| 2341 | without consideration for daylight saving time. | ||
| 2295 | 2342 | ||
| 2296 | Some operating systems cannot provide all this information to Emacs; | 2343 | Some operating systems cannot provide all this information to Emacs; |
| 2297 | in this case, `current-time-zone' returns a list containing nil for | 2344 | in this case, `current-time-zone' returns a list containing nil for |
| @@ -2315,15 +2362,18 @@ the data it can't find. */) | |||
| 2315 | zone_offset = make_number (offset); | 2362 | zone_offset = make_number (offset); |
| 2316 | if (SCHARS (zone_name) == 0) | 2363 | if (SCHARS (zone_name) == 0) |
| 2317 | { | 2364 | { |
| 2318 | /* No local time zone name is available; use "+-NNNN" instead. */ | 2365 | /* No local time zone name is available; use numeric zone instead. */ |
| 2319 | long int m = offset / 60; | 2366 | long int hour = offset / 3600; |
| 2320 | long int am = offset < 0 ? - m : m; | 2367 | int min_sec = offset % 3600; |
| 2321 | long int hour = am / 60; | 2368 | int amin_sec = min_sec < 0 ? - min_sec : min_sec; |
| 2322 | int min = am % 60; | 2369 | int min = amin_sec / 60; |
| 2323 | char buf[sizeof "+00" + INT_STRLEN_BOUND (long int)]; | 2370 | int sec = amin_sec % 60; |
| 2324 | zone_name = make_formatted_string (buf, "%c%02ld%02d", | 2371 | int min_prec = min_sec ? 2 : 0; |
| 2372 | int sec_prec = sec ? 2 : 0; | ||
| 2373 | char buf[sizeof "+0000" + INT_STRLEN_BOUND (long int)]; | ||
| 2374 | zone_name = make_formatted_string (buf, "%c%.2ld%.*d%.*d", | ||
| 2325 | (offset < 0 ? '-' : '+'), | 2375 | (offset < 0 ? '-' : '+'), |
| 2326 | hour, min); | 2376 | hour, min_prec, min, sec_prec, sec); |
| 2327 | } | 2377 | } |
| 2328 | } | 2378 | } |
| 2329 | 2379 | ||
| @@ -2332,11 +2382,11 @@ the data it can't find. */) | |||
| 2332 | 2382 | ||
| 2333 | DEFUN ("set-time-zone-rule", Fset_time_zone_rule, Sset_time_zone_rule, 1, 1, 0, | 2383 | DEFUN ("set-time-zone-rule", Fset_time_zone_rule, Sset_time_zone_rule, 1, 1, 0, |
| 2334 | doc: /* Set the Emacs local time zone using TZ, a string specifying a time zone rule. | 2384 | doc: /* Set the Emacs local time zone using TZ, a string specifying a time zone rule. |
| 2335 | |||
| 2336 | If TZ is nil or `wall', use system wall clock time; this differs from | 2385 | If TZ is nil or `wall', use system wall clock time; this differs from |
| 2337 | the usual Emacs convention where nil means current local time. If TZ | 2386 | the usual Emacs convention where nil means current local time. If TZ |
| 2338 | is t, use Universal Time. If TZ is an integer, treat it as in | 2387 | is t, use Universal Time. If TZ is a list (as from |
| 2339 | `encode-time'. | 2388 | `current-time-zone') or an integer (as from `decode-time'), use the |
| 2389 | specified time zone without consideration for daylight saving time. | ||
| 2340 | 2390 | ||
| 2341 | Instead of calling this function, you typically want something else. | 2391 | Instead of calling this function, you typically want something else. |
| 2342 | To temporarily use a different time zone rule for just one invocation | 2392 | To temporarily use a different time zone rule for just one invocation |