aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2016-04-12 09:19:11 -0700
committerPaul Eggert2016-04-12 09:19:38 -0700
commitfdb1ba144ca61185e6457f092f38f59dd9bbe6a0 (patch)
tree5048d1fbb946faf0b6059e4d4375bb514b3bfa74 /src
parent7c2c2196fd4be0b656bdf0e0b68f3d7c4a5eca08 (diff)
downloademacs-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.c104
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)
146static timezone_t 146static timezone_t
147tzlookup (Lisp_Object zone, bool settz) 147tzlookup (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.
1970TIME is specified as (HIGH LOW USEC PSEC), as returned by 2005TIME 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)
1972is also still accepted. The optional ZONE is omitted or nil for Emacs 2007is also still accepted.
1973local time, t for Universal Time, `wall' for system wall clock time, 2008
1974or a string as in the TZ environment variable. 2009The optional ZONE is omitted or nil for Emacs local time, t for
2010Universal Time, `wall' for system wall clock time, or a string as in
2011the TZ environment variable. It can also be a list (as from
2012`current-time-zone') or an integer (as from `decode-time') applied
2013without consideration for daylight saving time.
1975 2014
1976The value is a copy of FORMAT-STRING, but with certain constructs replaced 2015The value is a copy of FORMAT-STRING, but with certain constructs replaced
1977by text that describes the specified date and time in TIME: 2016by text that describes the specified date and time in TIME:
@@ -2085,9 +2124,12 @@ DEFUN ("decode-time", Fdecode_time, Sdecode_time, 0, 2, 0,
2085The optional SPECIFIED-TIME should be a list of (HIGH LOW . IGNORED), 2124The optional SPECIFIED-TIME should be a list of (HIGH LOW . IGNORED),
2086as from `current-time' and `file-attributes', or nil to use the 2125as from `current-time' and `file-attributes', or nil to use the
2087current time. The obsolete form (HIGH . LOW) is also still accepted. 2126current time. The obsolete form (HIGH . LOW) is also still accepted.
2127
2088The optional ZONE is omitted or nil for Emacs local time, t for 2128The optional ZONE is omitted or nil for Emacs local time, t for
2089Universal Time, `wall' for system wall clock time, or a string as in 2129Universal Time, `wall' for system wall clock time, or a string as in
2090the TZ environment variable. 2130the TZ environment variable. It can also be a list (as from
2131`current-time-zone') or an integer (as from `decode-time') applied
2132without consideration for daylight saving time.
2091 2133
2092The list has the following nine members: SEC is an integer between 0 2134The list has the following nine members: SEC is an integer between 0
2093and 60; SEC is 60 for a leap second, which only some operating systems 2135and 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)
2150DEFUN ("encode-time", Fencode_time, Sencode_time, 6, MANY, 0, 2192DEFUN ("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.
2152This is the reverse operation of `decode-time', which see. 2194This is the reverse operation of `decode-time', which see.
2195
2153The optional ZONE is omitted or nil for Emacs local time, t for 2196The optional ZONE is omitted or nil for Emacs local time, t for
2154Universal Time, `wall' for system wall clock time, or a string as in 2197Universal Time, `wall' for system wall clock time, or a string as in
2155the TZ environment variable. It can also be a list (as from 2198the 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
2215The optional ZONE is omitted or nil for Emacs local time, t for 2256The optional ZONE is omitted or nil for Emacs local time, t for
2216Universal Time, `wall' for system wall clock time, or a string as in 2257Universal Time, `wall' for system wall clock time, or a string as in
2217the TZ environment variable. */) 2258the TZ environment variable. It can also be a list (as from
2259`current-time-zone') or an integer (as from `decode-time') applied
2260without 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
2292have the form (HIGH . LOW), but this is considered obsolete. 2335have the form (HIGH . LOW), but this is considered obsolete.
2293Optional second arg ZONE is omitted or nil for the local time zone, or 2336
2294a string as in the TZ environment variable. 2337The optional ZONE is omitted or nil for Emacs local time, t for
2338Universal Time, `wall' for system wall clock time, or a string as in
2339the TZ environment variable. It can also be a list (as from
2340`current-time-zone') or an integer (as from `decode-time') applied
2341without consideration for daylight saving time.
2295 2342
2296Some operating systems cannot provide all this information to Emacs; 2343Some operating systems cannot provide all this information to Emacs;
2297in this case, `current-time-zone' returns a list containing nil for 2344in 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
2333DEFUN ("set-time-zone-rule", Fset_time_zone_rule, Sset_time_zone_rule, 1, 1, 0, 2383DEFUN ("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
2336If TZ is nil or `wall', use system wall clock time; this differs from 2385If TZ is nil or `wall', use system wall clock time; this differs from
2337the usual Emacs convention where nil means current local time. If TZ 2386the usual Emacs convention where nil means current local time. If TZ
2338is t, use Universal Time. If TZ is an integer, treat it as in 2387is 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
2389specified time zone without consideration for daylight saving time.
2340 2390
2341Instead of calling this function, you typically want something else. 2391Instead of calling this function, you typically want something else.
2342To temporarily use a different time zone rule for just one invocation 2392To temporarily use a different time zone rule for just one invocation