Mercurial > hg > xemacs-beta
changeset 4203:0a63e5de7bdc
[xemacs-hg @ 2007-10-02 19:31:30 by aidan]
Synch up format-time-string % specifiers with Emacs 21.3.1, from Shyamal Prasad.
author | aidan |
---|---|
date | Tue, 02 Oct 2007 19:31:31 +0000 |
parents | a7c5de5b9880 |
children | 121918494c46 |
files | src/ChangeLog src/editfns.c src/strftime.c |
diffstat | 3 files changed, 164 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/src/ChangeLog Tue Oct 02 10:33:05 2007 +0000 +++ b/src/ChangeLog Tue Oct 02 19:31:31 2007 +0000 @@ -1,3 +1,16 @@ +2004-12-08 Shyamal Prasad <shyamal@member.fsf.org> + + * editfns.c: + * editfns.c (Fformat_time_string): + Added documentation for %z, %g, %G and %V specifiers. This synchs + up the set of % specifiers for format-time-string with Emacs + 21.3.1. Make copy of static buffer returned by localtime(). + + * strftime.c: + * strftime.c (strftime): + Implemented %z, %g, %G and %V in a style similar to existing + implementation of other specifiers. + 2007-09-30 Stephen J. Turnbull <stephen@xemacs.org> * search.c (Freplace_match): Improve range-checking on STRBUFFER.
--- a/src/editfns.c Tue Oct 02 10:33:05 2007 +0000 +++ b/src/editfns.c Tue Oct 02 19:31:31 2007 +0000 @@ -1015,6 +1015,8 @@ %d is replaced by the day of month, zero-padded. %D is a synonym for "%m/%d/%y". %e is replaced by the day of month, blank-padded. +%G is replaced by the year containing the ISO 8601 week +%g is replaced by the year of the ISO 8601 week within the century (00-99) %h is a synonym for "%b". %H is replaced by the hour (00-23). %I is replaced by the hour (00-12). @@ -1033,12 +1035,14 @@ %t is a synonym for "\\t". %T is a synonym for "%H:%M:%S". %U is replaced by the week of the year (00-53), first day of week is Sunday. +%V is replaced by the ISO 8601 week number %w is replaced by the day of week (0-6), Sunday is day 0. %W is replaced by the week of the year (00-53), first day of week is Monday. %x is a locale-specific synonym, which defaults to "%D" in the C locale. %X is a locale-specific synonym, which defaults to "%T" in the C locale. %y is replaced by the year without century (00-99). %Y is replaced by the year with century. +%z is replaced by the time zone as a numeric offset (e.g +0530, -0800 etc.) %Z is replaced by the time zone abbreviation. The number of options reflects the `strftime' function. @@ -1063,13 +1067,15 @@ { Extbyte *buf = alloca_extbytes (size); Extbyte *formext; + /* make a copy of the static buffer returned by localtime() */ + struct tm tm = * localtime(&value); + *buf = 1; /* !!#### this use of external here is not totally safe, and potentially data lossy. */ LISP_STRING_TO_EXTERNAL (format_string, formext, Qnative); - if (emacs_strftime (buf, size, formext, - localtime (&value)) + if (emacs_strftime (buf, size, formext, &tm) || !*buf) return build_ext_string (buf, Qnative); /* If buffer was too small, make it bigger. */
--- a/src/strftime.c Tue Oct 02 10:33:05 2007 +0000 +++ b/src/strftime.c Tue Oct 02 19:31:31 2007 +0000 @@ -58,6 +58,7 @@ %S second (00..61) %T time, 24-hour (hh:mm:ss) %X locale's time representation (%H:%M:%S) + %z time zone offset (e.g. +0530, -0800 etc) %Z time zone (EDT), or nothing if no time zone is determinable Date fields: @@ -70,10 +71,13 @@ %d day of month (01..31) %e day of month ( 1..31) %D date (mm/dd/yy) + %G year corresponding to the ISO 8601 week + %g Year of the ISO 8601 week within century (00 - 99) %h same as %b %j day of year (001..366) %m month (01..12) %U week number of year with Sunday as first day of week (00..53) + %V ISO 8601 week number (first week is the earliest one with Thu) %w day of week (0..6) %W week number of year with Monday as first day of week (00..53) %x locale's date representation (mm/dd/yy) @@ -235,6 +239,30 @@ return dl <= 0 ? 0 : dl / 7 + (dl % 7 != 0); } +#ifndef __isleap +/* Nonzero if YEAR is a leap year (every 4 years, + except every 100th isn't, and every 400th is). */ +# define __isleap(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) +#endif + +/* The number of days from the first day of the first ISO week of this + year to the year day YDAY with week day WDAY. ISO weeks start on + Monday; the first ISO week has the year's first Thursday. YDAY may + be as small as YDAY_MINIMUM. */ +#define ISO_WEEK_START_WDAY 1 /* Monday */ +#define ISO_WEEK1_WDAY 4 /* Thursday */ +#define YDAY_MINIMUM (-366) +static int +iso_week_days (int yday, int wday) +{ + /* Add enough to the first operand of % to make it nonnegative. */ + int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7; + return (yday + - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7 + + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY); +} + #if !defined(HAVE_TM_ZONE) && !defined(HAVE_TZNAME) char *zone_name (const struct tm *tp); char * @@ -362,10 +390,125 @@ length += strftime (&string[length], max - length, "%H:%M:%S", tm); break; + + case 'V': + case 'g': + case 'G': + { + int year = tm->tm_year + 1900; + int days = iso_week_days (tm->tm_yday, tm->tm_wday); + + if (days < 0) + { + /* This ISO week belongs to the previous year. */ + year--; + days = + iso_week_days (tm->tm_yday + (365 + __isleap (year)), + tm->tm_wday); + } + else + { + int d = + iso_week_days (tm->tm_yday - (365 + __isleap (year)), + tm->tm_wday); + if (0 <= d) + { + /* This ISO week belongs to the next year. */ + year++; + days = d; + } + } + + switch (*format) + { + /* + #### FIXME + We really can't assume 1000 <= year <= 9999 + once time_t gets beyond 32 bits, but it's true + of the rest of the code here so get with the + program + */ + case 'g': + length += + add_num2 (&string[length], year % 100, + max - length, pad); + break; + + case 'G': + add_char (year / 1000 + '0'); + length += add_num3 (&string[length], year % 1000, + max - length, zero); + break; + + default: + length += + add_num2 (&string[length], days / 7 + 1, + max - length, pad); + break; + } + } + break; case 'X': length += strftime (&string[length], max - length, "%H:%M:%S", tm); break; + case 'z': + { + /* + #### FIXME: could use tm->tm_gmtoff if present. Since + the other code in xemacs does not do so we follow the + leaders (and don't add a autoconf macro to detect + its presence). + */ + long int offset; + long int minutes; + struct tm lt, *ut; + time_t utc; + + lt = *tm; + utc = mktime(<); + ut = gmtime(&utc); + /* assume that tm is valid so the others will be too! */ + assert( utc != (time_t) -1 && ut != NULL ); + + /* tm diff code below is based on mktime.c, glibc 2.3.2 */ + { + int lt4, ut4, lt100, ut100, lt400, ut400; + int intervening_leap_days, years, days; + + lt4 = (lt.tm_year >> 2) + (1900 >> 2) - + ! (lt.tm_year & 3); + ut4 = (ut->tm_year >> 2) + (1900 >> 2) - + ! (ut->tm_year & 3); + lt100 = lt4 / 25 - (lt4 % 25 < 0); + ut100 = ut4 / 25 - (ut4 % 25 < 0); + lt400 = lt100 >> 2; + ut400 = ut100 >> 2; + intervening_leap_days = + (lt4 - ut4) - (lt100 - ut100) + (lt400 - ut400); + years = lt.tm_year - ut->tm_year; + days = (365 * years + intervening_leap_days + + (lt.tm_yday - ut->tm_yday)); + offset = (60 * (60 * (24 * days + (lt.tm_hour - ut->tm_hour)) + + (lt.tm_min - ut->tm_min)) + + (lt.tm_sec - ut->tm_sec)); + } + + minutes = offset / ( offset < 0 ? -60 : 60 ); + + add_char ((offset < 0 ? '-' : '+')); + + if ( minutes / 600 != 0 ) + add_char (minutes / 600 + '0'); + else if ( pad != none ) + add_char ((pad == zero ? '0' : ' ')); + + length += + add_num3 (&string[length], + ((minutes / 60 ) % 10) * 100 + (minutes % 60), + max - length, pad); + break; + } case 'Z': #ifdef HAVE_TM_ZONE length += add_str (&string[length], tm->tm_zone, max - length);