%N for Time#strftime

e$BA0ED$G$9!#e(B

2008/08/21 9:22 Shugo M. [email protected]:

e$B$J$k$[$I!"$G$O$=$NJ}8~$G=$@5$7$^$9!#e(B
e$B@h$[$Ie(Bcommite$B$7$^$7$?!#e(B

%Le$B$OGQ;_$7$?J}$,$$$$$G$9$+$M!#e(B

DateTime#strftimee$B$G%5%]!<%H$5$l$F$$$k$N$G!“;D$7$?J}$,$h$$$+$J$H;W$$$^$7$?!#e(B
e$B$”$H!"e(BDateTimee$B$G$be(B

p DateTime.now.strftime(“%3N”)

e$B$N$h$&$K=q$1$k$N$G$9$,!"$3$A$i$Oe(BPerle$B$N$H$O0UL#$,0c$C$F!“e(B9e$B$h$jBg$-$$CM$r;XDje(B
e$B$7$?;~$K!”;XDj$7$?7e?t$K$J$k$h$&$KA0$Ke(B0e$B$r5M$a$k5!G=$G!"e(BNe$B0J30$NJQ49;XDjJ8e(B
e$B;z$G$b;H$($k$h$&$G$9!#e(B

$ ~/ruby/1.8.7-p72/bin/ruby-1_8_7-p72 -v -r date -e ‘p
DateTime.now.strftime(“%4S.%12N”)’
ruby 1.8.7 (2008-08-11 patchlevel 72) [i686-linux]
“0011.000763301000”

Timee$B$He(BDateTimee$B$G;EMM$rB7$($?J}$,;H$$>!<j$,$h$$$H;W$&$N$G$9$,!"$I$&$9$ke(B
e$B$N$,$h$$$G$7$g$&$+!#e(B
e$B8D?ME*$K$Oe(B%Ne$B$K4X$7$F$Oe(BPerle$B$N;EMM$NJ}$,;H$$$d$9$$$h$&$K;W$$$^$9!#e(B

In article
[email protected],
“Shugo M.” [email protected] writes:

e$B$N$h$&$K=q$1$k$N$G$9$,!"$3$A$i$Oe(BPerle$B$N$H$O0UL#$,0c$C$F!“e(B9e$B$h$jBg$-$$CM$r;XDje(B
e$B$7$?;~$K!”;XDj$7$?7e?t$K$J$k$h$&$KA0$Ke(B0e$B$r5M$a$k5!G=$G!"e(BNe$B0J30$NJQ49;XDjJ8e(B
e$B;z$G$b;H$($k$h$&$G$9!#e(B

e$B$A$g$C$H;n$7$F$_$F;W$C$?$N$G$9$,!"e(B9 e$B$h$jBg$-$JCM$r;XDj$7$?;~e(B
e$B$Oe(B 0 e$B$r1&$K$D$1$k$Y$-$8$c$J$$$G$9$+$M!#e(B

% ./ruby -e ‘p Time.now.strftime(“%100N”)’
“297311763”

e$B$=$N$&$Ae(B Time e$B$NCf?H$,e(B nano second
e$B$h$j$b:Y$+$$CM$rI=8=$G$-e(B
e$B$k$h$&$K$J$k$+$b$7$l$^$;$s$7!#e(B

e$B$^$D$b$He(B e$B$f$-$R$m$G$9e(B

In message “Re: [ruby-dev:35910] Re: %N for Time#strftime”
on Fri, 22 Aug 2008 13:03:18 +0900, Nobuyoshi N.
[email protected] writes:

|At Fri, 22 Aug 2008 11:51:12 +0900,
|Tanaka A. wrote in [ruby-dev:35909]:
|> > e$B$N$h$&$K=q$1$k$N$G$9$,!"$3$A$i$Oe(BPerle$B$N$H$O0UL#$,0c$C$F!“e(B9e$B$h$jBg$-$$CM$r;XDje(B
|> > e$B$7$?;~$K!”;XDj$7$?7e?t$K$J$k$h$&$KA0$Ke(B0e$B$r5M$a$k5!G=$G!"e(BNe$B0J30$NJQ49;XDjJ8e(B
|> > e$B;z$G$b;H$($k$h$&$G$9!#e(B
|>
|> e$B$A$g$C$H;n$7$F$_$F;W$C$?$N$G$9$,!"e(B9 e$B$h$jBg$-$JCM$r;XDj$7$?;~e(B
|> e$B$Oe(B 0 e$B$r1&$K$D$1$k$Y$-$8$c$J$$$G$9$+$M!#e(B
|
|+1

e$B;d$b$=$&;W$$$^$9!#%3%%C%H!"%3%%C%H!#e(B

e$B:G6ae(B strftime e$BEv$?$j$K?'!9JQ99$5$l$^$7$?!#e(B
e$B$=$N$?$a$+$H;W$$$^$9$,!“2<5-$N%(%i!<$,e(B cygwin
e$B$GH/@8$7$^$9!#e(Bcygwin e$B$b99?7$7$^$7$?$,!”$=$N$^$^$G$9!#e(B
e$B%"%I%P%$%9$*4j$$$7$^$9!#e(B

e$B59$7$/$*4j$$$7$^$9!"e(B Martin.

duerst@Tanzawa /cygdrive/d/ruby
$ svn up
Enter passphrase for key ‘/home/duerst/.ssh/id_dsa’:
At revision 18774.

duerst@Tanzawa /cygdrive/d/ruby
$ make
gcc -O2 -g -Wall -Wno-parentheses -L. -Wl,–stack,0x00200000 main.o
dmydln.o dmyencoding.o miniprelude.o array.o bignum.o class.o compar.o
complex.o dir.o enum.o enumerator.o error.o eval.o load.o proc.o file.o
gc.o hash.o inits.o io.o marshal.o math.o numeric.o object.o pack.o
parse.o process.o prec.o random.o range.o rational.o re.o regcomp.o
regenc.o regerror.o regexec.o regparse.o regsyntax.o ruby.o signal.o
sprintf.o st.o strftime.o string.o struct.o time.o transcode.o util.o
variable.o version.o blockinlining.o compile.o debug.o iseq.o vm.o
vm_dump.o thread.o cont.o ascii.o us_ascii.o unicode.o utf_8.o dmyext.o
-lpthread -ldl -lcrypt -o miniruby.exe
/usr/lib/gcc/i686-pc-cygwin/3.4.4/…/…/…/…/i686-pc-cygwin/bin/ld:
warning: auto-importing has been activated without --enable-auto-import
specified on the command line.
This should work unless it involves constant data structures referencing
symbols from auto-imported DLLs.strftime.o: In function rb_strftime': /cygdrive/d/ruby/strftime.c:489: undefined reference to __imp____daylight’
/cygdrive/d/ruby/strftime.c:459: undefined reference to
`__imp____timezone’
Info: resolving __daylight by linking to __imp___daylight (auto-import)
collect2: ld returned 1 exit status
make: *** [miniruby.exe] Error 1

duerst@Tanzawa /cygdrive/d/ruby
$

#-#-# Martin J. Du"rst, Assoc. Professor, Aoyama Gakuin University
#-#-# http://www.sw.it.aoyama.ac.jp mailto:[email protected]

e$B$3$s$K$A$O!"$J$+$`$ie(B(e$B$&e(B)e$B$G$9!#e(B

In message “[ruby-dev:35913] cygwin e$B$Ge(B strftime
e$B4XO”$N%3%s%Q%$%kLdBje(B (was: Re: %N for Time#strftime)"
on Aug.22,2008 18:27:25, [email protected] wrote:

/cygdrive/d/ruby/strftime.c:489: undefined reference to __imp____daylight' /cygdrive/d/ruby/strftime.c:459: undefined reference to __imp____timezone’
Info: resolving __daylight by linking to __imp___daylight (auto-import)
collect2: ld returned 1 exit status
make: *** [miniruby.exe] Error 1

daylighte$B$*$h$Se(Btimezonee$B$X$N;2>H$Oe(Bconfiguree$B$G%A%'%C%/$7$F$k$N$G!"e(B
e$B<B:]$K;2>H$5$l$k$H$$$&$3$H$OB8:_$9$k$N$@$H;W$&$N$G$9$,e(B…

config.he$B$NCf$O$I$&$J$C$F$$$k$G$7$g$&$+e(B?

e$B$=$l$G$O!#e(B

e$B$J$+$@$G$9!#e(B

At Fri, 22 Aug 2008 11:51:12 +0900,
Tanaka A. wrote in [ruby-dev:35909]:

e$B$N$h$&$K=q$1$k$N$G$9$,!"$3$A$i$Oe(BPerle$B$N$H$O0UL#$,0c$C$F!“e(B9e$B$h$jBg$-$$CM$r;XDje(B
e$B$7$?;~$K!”;XDj$7$?7e?t$K$J$k$h$&$KA0$Ke(B0e$B$r5M$a$k5!G=$G!"e(BNe$B0J30$NJQ49;XDjJ8e(B
e$B;z$G$b;H$($k$h$&$G$9!#e(B

e$B$A$g$C$H;n$7$F$_$F;W$C$?$N$G$9$,!"e(B9 e$B$h$jBg$-$JCM$r;XDj$7$?;~e(B
e$B$Oe(B 0 e$B$r1&$K$D$1$k$Y$-$8$c$J$$$G$9$+$M!#e(B

+1

Index: strftime.c

— strftime.c (revision 18771)
+++ strftime.c (working copy)
@@ -1,2 +1,4 @@
+/* -- c-file-style: “linux” -- /
+
/

  • strftime.c
    @@ -177,4 +179,5 @@ rb_strftime(char *s, size_t maxsize, con
    char *endp = s + maxsize;
    char *start = s;
  • const char *sp, *tp;
    auto char tbuf[100];
    long off;
    @@ -195,25 +198,27 @@ rb_strftime(char s, size_t maxsize, con
    #endif /
    HAVE_TM_NAME /
    #endif /
    HAVE_TM_ZONE */
  • int precision = -1;
  • int precision, flags;

  • enum {LEFT, CHCASE, LOWER, UPPER, SPACE, ZERO};
    +#define BIT_OF(n) (1U<<(n))

    /* various tables, useful in North America */

  • static const char *days_a[] = {
  • static const char days_a[][4] = {
    “Sun”, “Mon”, “Tue”, “Wed”,
    “Thu”, “Fri”, “Sat”,
    };
  • static const char *days_l[] = {
  • static const char days_l[][10] = {
    “Sunday”, “Monday”, “Tuesday”, “Wednesday”,
    “Thursday”, “Friday”, “Saturday”,
    };
  • static const char *months_a[] = {
  • static const char months_a[][4] = {
    “Jan”, “Feb”, “Mar”, “Apr”, “May”, “Jun”,
    “Jul”, “Aug”, “Sep”, “Oct”, “Nov”, “Dec”,
    };
  • static const char *months_l[] = {
  • static const char months_l[][10] = {
    “January”, “February”, “March”, “April”,
    “May”, “June”, “July”, “August”, “September”,
    “October”, “November”, “December”,
    };
  • static const char *ampm[] = { “AM”, “PM”, };
  • static const char ampm[][3] = { “AM”, “PM”, };

    if (s == NULL || format == NULL || timeptr == NULL || maxsize == 0)
    @@ -222,4 +227,5 @@ rb_strftime(char s, size_t maxsize, con
    /
    quick check if we even need to bother */
    if (strchr(format, ‘%’) == NULL && strlen(format) + 1 >= maxsize) {

  • err:
    errno = ERANGE;
    return 0;
    @@ -262,10 +268,29 @@ rb_strftime(char *s, size_t maxsize, con

    for (; *format && s < endp - 1; format++) {

  • tbuf[0] = ‘\0’;
    +#define NEEDS(n) do if (s + (n) >= endp - 1) goto err; while (0)
    +#define FMT(fmt, def_prec, val) \
  • do { \
  •  int l; \
    
  •  if (precision == 0) break; \
    
  •  if (precision < 0) precision = (def_prec); \
    
  •  l = snprintf(s, endp - s, fmt, precision, val); \
    
  •  if (l < 0) goto err; \
    
  •  s += l; \
    
  • } while (0)
    +#define STRFTIME(fmt, tm) \
  • do { \
  •  i = strftime(s, endp - s, fmt, tm); \
    
  •  if (!i) return 0; \
    
  •  s += i; \
    
  • } while (0)
  • if (*format != ‘%’) {
    *s++ = *format;
    continue;
    }
  • tp = tbuf;
  • sp = format;
    precision = -1;
  • flags = 0;
    again:
    switch (*++format) {
    @@ -280,14 +305,14 @@ rb_strftime(char s, size_t maxsize, con
    case ‘a’: /
    abbreviated weekday name */
    if (timeptr->tm_wday < 0 || timeptr->tm_wday > 6)
  •    strcpy(tbuf, "?");
    
  •    tp = "?";
     else
    
  •    strcpy(tbuf, days_a[timeptr->tm_wday]);
    
  •    tp = days_a[timeptr->tm_wday];
     break;
    

    case ‘A’: /* full weekday name */
    if (timeptr->tm_wday < 0 || timeptr->tm_wday > 6)

  •    strcpy(tbuf, "?");
    
  •    tp = "?";
     else
    
  •    strcpy(tbuf, days_l[timeptr->tm_wday]);
    
  •    tp = days_l[timeptr->tm_wday];
     break;
    

@@ -297,29 +322,29 @@ rb_strftime(char s, size_t maxsize, con
case ‘b’: /
abbreviated month name */
if (timeptr->tm_mon < 0 || timeptr->tm_mon > 11)

  •    strcpy(tbuf, "?");
    
  •    tp = "?";
     else
    
  •    strcpy(tbuf, months_a[timeptr->tm_mon]);
    
  •    tp = months_a[timeptr->tm_mon];
     break;
    

    case ‘B’: /* full month name */
    if (timeptr->tm_mon < 0 || timeptr->tm_mon > 11)

  •    strcpy(tbuf, "?");
    
  •    tp = "?";
     else
    
  •    strcpy(tbuf, months_l[timeptr->tm_mon]);
    
  •    tp = months_l[timeptr->tm_mon];
     break;
    

    case ‘c’: /* appropriate date and time representation */

  •  strftime(tbuf, sizeof tbuf, "%a %b %e %H:%M:%S %Y", timeptr);
    
  •  break;
    
  •  STRFTIME("%a %b %e %H:%M:%S %Y", timeptr);
    
  •  continue;
    

    case ‘d’: /* day of the month, 01 - 31 */
    i = range(1, timeptr->tm_mday, 31);

  •  sprintf(tbuf, "%02d", i);
    
  •  break;
    
  •  FMT("%.*d", 2, i);
    
  •  continue;
    

    case ‘H’: /* hour, 24-hour clock, 00 - 23 */
    i = range(0, timeptr->tm_hour, 23);

  •  sprintf(tbuf, "%02d", i);
    
  •  break;
    
  •  FMT("%.*d", 2, i);
    
  •  continue;
    

    case ‘I’: /* hour, 12-hour clock, 01 - 12 */
    @@ -329,63 +354,67 @@ rb_strftime(char *s, size_t maxsize, con
    else if (i > 12)
    i -= 12;

  •  sprintf(tbuf, "%02d", i);
    
  •  break;
    
  •  FMT("%.*d", 2, i);
    
  •  continue;
    

    case ‘j’: /* day of the year, 001 - 366 */

  •  sprintf(tbuf, "%03d", timeptr->tm_yday + 1);
    
  •  break;
    
  •  FMT("%.*d", 3, timeptr->tm_yday + 1);
    
  •  continue;
    

    case ‘m’: /* month, 01 - 12 */
    i = range(0, timeptr->tm_mon, 11);

  •  sprintf(tbuf, "%02d", i + 1);
    
  •  break;
    
  •  FMT("%.*d", 2, i + 1);
    
  •  continue;
    

    case ‘M’: /* minute, 00 - 59 */
    i = range(0, timeptr->tm_min, 59);

  •  sprintf(tbuf, "%02d", i);
    
  •  break;
    
  •  FMT("%.*d", 2, i);
    
  •  continue;
    

    case ‘p’: /* am or pm based on 12-hour clock */

  •  if (flags & BIT_OF(CHCASE)) {
    
  •    flags &= ~(BIT_OF(UPPER)|BIT_OF(CHCASE));
    
  •    flags |= BIT_OF(LOWER);
    
  •  }
     i = range(0, timeptr->tm_hour, 23);
     if (i < 12)
    
  •    strcpy(tbuf, ampm[0]);
    
  •    tp = ampm[0];
     else
    
  •    strcpy(tbuf, ampm[1]);
    
  •    tp = ampm[1];
     break;
    

    case ‘S’: /* second, 00 - 60 */
    i = range(0, timeptr->tm_sec, 60);

  •  sprintf(tbuf, "%02d", i);
    
  •  break;
    
  •  FMT("%.*d", 2, i);
    
  •  continue;
    

    case ‘U’: /* week of year, Sunday is first day of week */

  •  sprintf(tbuf, "%02d", weeknumber(timeptr, 0));
    
  •  break;
    
  •  FMT("%.*d", 2, weeknumber(timeptr, 0));
    
  •  continue;
    

    case ‘w’: /* weekday, Sunday == 0, 0 - 6 */
    i = range(0, timeptr->tm_wday, 6);

  •  sprintf(tbuf, "%d", i);
    
  •  break;
    
  •  FMT("%.*d", 0, i);
    
  •  continue;
    

    case ‘W’: /* week of year, Monday is first day of week */

  •  sprintf(tbuf, "%02d", weeknumber(timeptr, 1));
    
  •  break;
    
  •  FMT("%.*d", 2, weeknumber(timeptr, 1));
    
  •  continue;
    

    case ‘x’: /* appropriate date representation */

  •  strftime(tbuf, sizeof tbuf, "%m/%d/%y", timeptr);
    
  •  break;
    
  •  STRFTIME("%m/%d/%y", timeptr);
    
  •  continue;
    

    case ‘X’: /* appropriate time representation */

  •  strftime(tbuf, sizeof tbuf, "%H:%M:%S", timeptr);
    
  •  break;
    
  •  STRFTIME("%H:%M:%S", timeptr);
    
  •  continue;
    

    case ‘y’: /* year without a century, 00 - 99 */
    i = timeptr->tm_year % 100;

  •  sprintf(tbuf, "%02d", i);
    
  •  break;
    
  •  FMT("%.*d", 2, i);
    
  •  continue;
    

    case ‘Y’: /* year with century */

  •  sprintf(tbuf, "%ld", 1900L + timeptr->tm_year);
    
  •  break;
    
  •  FMT("%.*ld", 0, 1900L + timeptr->tm_year);
    
  •  continue;
    

#ifdef MAILHEADER_EXT
@@ -407,6 +436,6 @@ rb_strftime(char s, size_t maxsize, con
case ‘z’: /
time zone offset east of GMT e.g. -0600 */
if (gmt) {

  •      strcpy(tbuf, "+0000");
    
  •      break;
    
  •    FMT("%+.*d", 4, 0);
    
  •    continue;
     }
    

#ifdef HAVE_TM_NAME
@@ -439,35 +468,38 @@ rb_strftime(char s, size_t maxsize, con
#endif /
!HAVE_TM_NAME */
if (off < 0) {

  •    tbuf[0] = '-';
       off = -off;
    
  •    off = -(off/60*100 + off%60);
     } else {
    
  •    tbuf[0] = '+';
    
  •    off = off/60*100 + off%60;
     }
    
  •  sprintf(tbuf+1, "%02u%02u", (unsigned)off/60, (unsigned)off%60);
    
  •  break;
    
  •  FMT("%+.*ld", 4, off);
    
  •  continue;
    

#endif /* MAILHEADER_EXT */

 case 'Z':  /* time zone name or abbrevation */
  •  if (flags & BIT_OF(CHCASE)) {
    
  •    flags &= ~(BIT_OF(UPPER)|BIT_OF(CHCASE));
    
  •    flags |= BIT_OF(LOWER);
    
  •  }
     if (gmt) {
    
  •      strcpy(tbuf, "UTC");
    
  •      break;
    
  •    tp = "UTC";
    
  •    break;
     }
    

#ifdef HAVE_TZNAME
i = (daylight && timeptr->tm_isdst > 0); /* 0 or 1 */

  •  strcpy(tbuf, tzname[i]);
    
  •  tp = tzname[i];
    

#else
#ifdef HAVE_TM_ZONE

  •  strcpy(tbuf, timeptr->tm_zone);
    
  •  tp = timeptr->tm_zone;
    

#else
#ifdef HAVE_TM_NAME

  •  strcpy(tbuf, timeptr->tm_name);
    
  •  tp = timeptr->tm_name;
    

#else
#ifdef HAVE_TIMEZONE
gettimeofday(& tv, & zone);
#ifdef TIMEZONE_VOID

  •  strcpy(tbuf, timezone());
    
  •  tp = timezone();
    

#else

  •  strcpy(tbuf, timezone(zone.tz_minuteswest,
    
  •        timeptr->tm_isdst > 0));
    
  •  tp = timezone(zone.tz_minuteswest, timeptr->tm_isdst > 0);
    

#endif /* TIMEZONE_VOID /
#endif /
HAVE_TIMEZONE */
@@ -479,38 +511,38 @@ rb_strftime(char s, size_t maxsize, con
#ifdef SYSV_EXT
case ‘n’: /
same as \n */

  •  tbuf[0] = '\n';
    
  •  tbuf[1] = '\0';
    
  •  break;
    
  •  NEEDS(1);
    
  •  *s++ = '\n';
    
  •  continue;
    

    case ‘t’: /* same as \t */

  •  tbuf[0] = '\t';
    
  •  tbuf[1] = '\0';
    
  •  break;
    
  •  NEEDS(1);
    
  •  *s++ = '\t';
    
  •  continue;
    

    case ‘D’: /* date as %m/%d/%y */

  •  strftime(tbuf, sizeof tbuf, "%m/%d/%y", timeptr);
    
  •  break;
    
  •  STRFTIME("%m/%d/%y", timeptr);
    
  •  continue;
    

    case ‘e’: /* day of month, blank padded */

  •  sprintf(tbuf, "%2d", range(1, timeptr->tm_mday, 31));
    
  •  break;
    
  •  FMT("%.*d", 2, range(1, timeptr->tm_mday, 31));
    
  •  continue;
    

    case ‘r’: /* time as %I:%M:%S %p */

  •  strftime(tbuf, sizeof tbuf, "%I:%M:%S %p", timeptr);
    
  •  break;
    
  •  STRFTIME("%I:%M:%S %p", timeptr);
    
  •  continue;
    

    case ‘R’: /* time as %H:%M */

  •  strftime(tbuf, sizeof tbuf, "%H:%M", timeptr);
    
  •  break;
    
  •  STRFTIME("%H:%M", timeptr);
    
  •  continue;
    

    case ‘T’: /* time as %H:%M:%S */

  •  strftime(tbuf, sizeof tbuf, "%H:%M:%S", timeptr);
    
  •  break;
    
  •  STRFTIME("%H:%M:%S", timeptr);
    
  •  continue;
    

#endif

#ifdef SUNOS_EXT
case ‘k’: /* hour, 24-hour clock, blank pad */

  •  sprintf(tbuf, "%2d", range(0, timeptr->tm_hour, 23));
    
  •  break;
    
  •  FMT("%*d", 2, range(0, timeptr->tm_hour, 23));
    
  •  continue;
    

    case ‘l’: /* hour, 12-hour clock, 1 - 12, blank pad */
    @@ -520,6 +552,6 @@ rb_strftime(char *s, size_t maxsize, con
    else if (i > 12)
    i -= 12;

  •  sprintf(tbuf, "%2d", i);
    
  •  break;
    
  •  FMT("%*d", 2, i);
    
  •  continue;
    

#endif

@@ -527,12 +559,14 @@ rb_strftime(char s, size_t maxsize, con
#ifdef VMS_EXT
case ‘v’: /
date as dd-bbb-YYYY */

  •  sprintf(tbuf, "%2d-%3.3s-%4ld",
    
  •    range(1, timeptr->tm_mday, 31),
    
  •    months_a[range(0, timeptr->tm_mon, 11)],
    
  •    timeptr->tm_year + 1900L);
    
  •  w = snprintf(s, endp - s, "%2d-%3.3s-%4ld",
    
  •         range(1, timeptr->tm_mday, 31),
    
  •         months_a[range(0, timeptr->tm_mon, 11)],
    
  •         timeptr->tm_year + 1900L);
    
  •  if (w < 0) goto err;
     for (i = 3; i < 6; i++)
    
  •    if (islower(tbuf[i]))
    
  •      tbuf[i] = toupper(tbuf[i]);
    
  •  break;
    
  •    if (islower(s[i]))
    
  •      s[i] = toupper(s[i]);
    
  •  s += w;
    
  •  continue;
    

#endif

@@ -540,6 +574,6 @@ rb_strftime(char *s, size_t maxsize, con
#ifdef POSIX2_DATE
case ‘C’:

  •  sprintf(tbuf, "%02ld", (timeptr->tm_year + 1900L) / 100);
    
  •  break;
    
  •  FMT("%.*ld", 2, (timeptr->tm_year + 1900L) / 100);
    
  •  continue;
    

@@ -550,12 +584,11 @@ rb_strftime(char *s, size_t maxsize, con

 case 'V':  /* week of year according ISO 8601 */
  •  sprintf(tbuf, "%02d", iso8601wknum(timeptr));
    
  •  break;
    
  •  FMT("%.*d", 2, iso8601wknum(timeptr));
    
  •  continue;
    

    case ‘u’:
    /* ISO 8601: Weekday as a decimal number [1 (Monday) - 7] */

  •  sprintf(tbuf, "%d", timeptr->tm_wday == 0 ? 7 :
    
  •      timeptr->tm_wday);
    
  •  break;
    
  •  FMT("%*d", 0, timeptr->tm_wday == 0 ? 7 : timeptr->tm_wday);
    
  •  continue;
    

#endif /* POSIX2_DATE */

@@ -581,13 +614,14 @@ rb_strftime(char *s, size_t maxsize, con

   if (*format == 'G')
  •    sprintf(tbuf, "%ld", y);
    
  •    FMT("%.*ld", 0, y);
     else
    
  •    sprintf(tbuf, "%02ld", y % 100);
    
  •  break;
    
  •    FMT("%.*ld", 2, y % 100);
    
  •  continue;
    

#endif /* ISO_DATE_EXT */

  • case ‘L’: /* millisecond, 000 - 999 */
  •  sprintf(tbuf, "%03ld", ts->tv_nsec / 1000000);
    
  •  break;
    
  • case ‘L’:

  •  w = 3;
    
  •  goto subsec;
    

    case ‘N’:
    @@ -600,17 +634,25 @@ rb_strftime(char *s, size_t maxsize, con
    * %9N nanosecond (9 digits)
    */

  •  w = 9;
    
  • subsec:
    {

  •    char fmt[10];
       long n = ts->tv_nsec;
    
  •    if (precision < 0 || precision > 9) {
    
  •        precision = 9;
    
  •    if (precision == 0) continue;
    
  •    if (precision < 0) {
    
  •        precision = w;
    
  •    }
    
  •    NEEDS(precision);
    
  •    if (precision < w) {
    
  •      snprintf(tbuf, w + 1, "%.*ld", w, n);
    
  •      memcpy(s, tbuf, precision);
       }
    
  •    if (precision == 0) break;
    
  •    n /= pow(10, 9 - precision);
    
  •    sprintf(fmt, "%%0%dld", precision);
    
  •    sprintf(tbuf, fmt, n);
    
  •    else {
    
  •      snprintf(s, endp - s, "%.*ld", w, n);
    
  •      memset(s + w, '0', precision - w);
    
  •    }
    
  •    s += precision;
     }
    
  •  break;
    
  •  continue;
    

    case ‘F’: /* Equivalent to %Y-%m-%d */
    @@ -619,39 +661,55 @@ rb_strftime(char *s, size_t maxsize, con
    mon = range(0, timeptr->tm_mon, 11) + 1;
    mday = range(1, timeptr->tm_mday, 31);

  •    sprintf(tbuf, "%ld-%02d-%02d",
    
  •      1900L + timeptr->tm_year, mon, mday);
    
  •    i = snprintf(s, endp - s, "%ld-%02d-%02d",
    
  •           1900L + timeptr->tm_year, mon, mday);
    
  •    if (i < 0)
    
  •      goto err;
    
  •    s += i;
     }
    
  •  break;
    
  •  continue;
    
  • default:
  •  if (isdigit(*format)) {
    
  •      const char *p = format;
    
  •      while (isdigit(*p)) p++;
    
  •      if (*p == 'N') {
    
  •    precision = atoi(format);
    
  •    format = p - 1;
    
  • case ‘-’:
  •  flags |= BIT_OF(LEFT);
    
  •  goto again;
    
  • case ‘^’:
  •  flags |= BIT_OF(UPPER);
    
  •  goto again;
    
  • case ‘#’:
  •  flags |= BIT_OF(CHCASE);
    
  •  goto again;
    
  • case ‘_’:
  •  flags |= BIT_OF(SPACE);
    
  •  goto again;
    
  • case ‘0’:
  •  flags |= BIT_OF(ZERO);
    
  • case ‘1’: case ‘2’: case ‘3’: case ‘4’:
  • case ‘5’: case ‘6’: case ‘7’: case ‘8’: case ‘9’:
  •  {
    
  •    char *e;
    
  •    precision = (int)strtoul(format, &e, 10);
    
  •    format = e - 1;
       goto again;
    
  •      }
     }
    
  •  tbuf[0] = '%';
    
  •  tbuf[1] = *format;
    
  •  tbuf[2] = '\0';
    
  •  break;
    
  • default:
  •  tp = sp;
    
  •  i = format - sp + 1;
    
  •  goto copy;
    
    }
  • i = strlen(tbuf);
  • i = strlen(tp);
  • copy:
    if (i) {
  •  if (s + i < endp - 1) {
    
  •    strcpy(s, tbuf);
    
  •    s += i;
    
  •  } else {
    
  •    errno = ERANGE;
    
  •    return 0;
    
  •  }
    
  •  NEEDS(i);
    
  •  memcpy(s, tp, i);
    
  •  s += i;
    
    }
    }
    out:
    if (s >= endp) {
  • errno = ERANGE;
  • return 0;
  • goto err;
    }
    if (*format == ‘\0’) {
    Index: test/ruby/test_time.rb
    ===================================================================
    — test/ruby/test_time.rb (revision 18771)
    +++ test/ruby/test_time.rb (working copy)
    @@ -382,15 +382,10 @@ class TestTime < Test::Unit::TestCase

    t = Time.at(946684800, 123456.789)

  • assert_equal(“123”, t.strftime("%L"))
  • assert_equal(“123456789”, t.strftime("%N"))
    assert_equal(“123”, t.strftime("%3N"))
    assert_equal(“123456”, t.strftime("%6N"))
    assert_equal(“123456789”, t.strftime("%9N"))
  • assert_equal(“123456789”, t.strftime("%10N"))
  • assert_equal(“123456789”, t.strftime("%1" + “0” * 100 + “N”))
  • assert_equal(“1234567890”, t.strftime("%10N"))
    assert_equal("", t.strftime("%0N"))
  • assert_equal("%3S", t.strftime("%3S"))
  • fmt = “%1” + “0” * 100 + “S”
  • assert_equal(fmt, t.strftime(fmt))
  • assert_equal(“000”, t.strftime("%3S"))

    t = Time.mktime(2001, 10, 1)
    Index: lib/date/format.rb
    ===================================================================
    — lib/date/format.rb (revision 18771)
    +++ lib/date/format.rb (working copy)
    @@ -154,6 +154,6 @@ class Date
    end

  • if f[:p] != ‘-’
  •  s = s.rjust(f[:w], f[:p])
    
  • if f[:w]
  •  s = f[:n] ? s.ljust(f[:w], f[:p]) : s.rjust(f[:w], f[:p])
    
    end

@@ -258,10 +258,16 @@ class Date
when ‘k’; emit_a(hour, 2, f)
when ‘L’

  • emit_n((sec_fraction / MILLISECONDS_IN_SECOND).floor, 3, f)
  •    f[:n] = true
    
  •    w = f[:w]
    
  • s = emit_n((sec_fraction / MILLISECONDS_IN_SECOND).floor, 3, f)
  •    w ? s[0, w] : s
     when 'l'; emit_a((hour % 12).nonzero? || 12, 2, f)
     when 'M', 'OM'; emit_n(min, 2, f)
     when 'm', 'Om'; emit_n(mon, 2, f)
     when 'N'
    
  • emit_n((sec_fraction / NANOSECONDS_IN_SECOND).floor, 9, f)
  •    f[:n] = true
    
  •    w = f[:w]
    
  • s = emit_n((sec_fraction / NANOSECONDS_IN_SECOND).floor, 9, f)
  •    w ? s[0, w] : s
     when 'n'; "\n"
     when 'P'; emit_ad(strftime('%p').downcase, 0, f)

Timee$B$He(BDateTimee$B$G;EMM$rB7$($?J}$,;H$$>!<j$,$h$$$H;W$&$N$G$9$,!"$I$&$9$ke(B
e$B$N$,$h$$$G$7$g$&$+!#e(B
e$B8D?ME*$K$Oe(B%Ne$B$K4X$7$F$Oe(BPerle$B$N;EMM$NJ}$,;H$$$d$9$$$h$&$K;W$$$^$9!#e(B

date e$B$N$[$&$O!"e(Bglibc e$B$N3HD%$K$[$=`5r$7$F$$$k$H;W$$$^$9e(B
(e$B;EMM$H<B:]$N?6e(B
e$BIq$$$rFI$_<h$C$F1h$&$h$&$K$7$F$^$9e(B)e$B!#<B:]$K$Oe(B GNU date(1)
e$B$N3HD%$K6a$$e(B
e$B$G$9!#>e5-3HD%$K$O!“HyL/$J$H$3$m$,$”$j$^$9$7!"e(B%N
e$B$N;H$$>!<j$K$D$$$F$O!"e(B
e$BF10U$G$-$=$&$G$9$,!“A4BN$H$7$F$I$&$9$k$N$+!”$H$$$&$3$H$,:#$N$H$3$m8+$(e(B
e$B$^$;$s!#e(B

e$B$?$H$($P!"e(Bdate e$B$@$1$G$J$/!"0JA0$Oe(B Time e$B$G$be(B “%-m”
e$B$N$h$&$J$b$N$,!"e(B
glibc e$B$,%j%s%/$5$l$F$$$l$PMxMQ2DG=$G$7$?!#e(B

e$B8=>u!"e(Bdate e$B$N$[$&$O!“A4BN$H$7$Fe(B glibc
e$B$K6a$$?6Iq$$$K$9$k$3$H$K$h$kMxE@e(B
e$B$r<h$C$F$$$^$9!#e(B%N
e$B$@$1$G$J$/!“A4BN$H$7$F!”$3$&$7$?$i$$$$!”$H$$$&$3$H$,$J$$$He(B
e$BD>$A$K$OH=CG$,=PMh$J$$$H;W$$$^$9!#e(B

e$B$J$+$@$G$9!#e(B

At Fri, 22 Aug 2008 13:31:07 +0900,
Yukihiro M. wrote in [ruby-dev:35911]:

|> > e$B$N$h$&$K=q$1$k$N$G$9$,!"$3$A$i$Oe(BPerle$B$N$H$O0UL#$,0c$C$F!“e(B9e$B$h$jBg$-$$CM$r;XDje(B
|> > e$B$7$?;~$K!”;XDj$7$?7e?t$K$J$k$h$&$KA0$Ke(B0e$B$r5M$a$k5!G=$G!"e(BNe$B0J30$NJQ49;XDjJ8e(B
|> > e$B;z$G$b;H$($k$h$&$G$9!#e(B
|>
|> e$B$A$g$C$H;n$7$F$_$F;W$C$?$N$G$9$,!"e(B9 e$B$h$jBg$-$JCM$r;XDj$7$?;~e(B
|> e$B$Oe(B 0 e$B$r1&$K$D$1$k$Y$-$8$c$J$$$G$9$+$M!#e(B
|
|+1

e$B;d$b$=$&;W$$$^$9!#%3%%C%H!"%3%%C%H!#e(B

date/format.rbe$B$He(Bstrftime.ce$B$GF1$8$h$&$J$3$H$r$d$C$F$$$k$H0l4S$5$;e(B
e$B$k$N$,$a$s$I$&$J$N$G!"e(BTimee$B$G$be(Btime_te$B$NHO0O$r1[$($kHO0O$rI=8=$G$-e(B
e$B$k$h$&$K$7$F!"e(BDateTimee$B$G$be(BTime#strftimee$B$r;H$&$H$$$&$N$O$I$&$G$7$ge(B
e$B$&$+!#e(B

e$B$H$j$"$($:e(Btime.ce$B$@$1!#e(B

Index: time.c

— time.c (revision 18772)
+++ time.c (working copy)
@@ -23,5 +23,6 @@

VALUE rb_cTime;
-static VALUE time_utc_offset _((VALUE));
+static VALUE time_utc_offset(VALUE);
+static time_t make_time_t(struct tm *, int);

static ID id_divmod, id_mul, id_submicro;
@@ -30,6 +31,8 @@ struct time_object {
struct timespec ts;
struct tm tm;

  • int gmt;
  • int tm_got;
  • union {
  • struct {int gmt:1, tm_got:1, ts_got:1;} bits;
  • int flags;
  • } as;
    };

@@ -43,4 +46,7 @@ time_free(void *tobj)
}

+#define IS_TIME(time) (TYPE(time) == T_DATA && RDATA(time)->dfree ==
time_free)
+
+
static VALUE
time_s_alloc(VALUE klass)
@@ -50,5 +56,5 @@ time_s_alloc(VALUE klass)

 obj = Data_Make_Struct(klass, struct time_object, 0, time_free, 

tobj);

  • tobj->tm_got=0;
  • tobj->as.flags = 0;
    tobj->ts.tv_sec = 0;
    tobj->ts.tv_nsec = 0;
    @@ -96,5 +102,5 @@ time_init(VALUE time)
    time_modify(time);
    GetTimeval(time, tobj);
  • tobj->tm_got=0;
  • tobj->as.flags = 0;
    tobj->ts.tv_sec = 0;
    tobj->ts.tv_nsec = 0;
    @@ -113,4 +119,5 @@ time_init(VALUE time)
    }
    #endif

  • tobj->as.bits.ts_got = 1;

    return time;
    @@ -160,4 +167,6 @@ time_new_internal(VALUE klass, time_t se
    tobj->ts.tv_sec = sec;
    tobj->ts.tv_nsec = nsec;

  • tobj->as.flags = 0;

  • tobj->as.bits.ts_got = 1;

    return time;
    @@ -270,7 +279,11 @@ rb_time_timeval(VALUE time)
    struct timeval t;

  • if (TYPE(time) == T_DATA && RDATA(time)->dfree == time_free) {
  • if (IS_TIME(time)) {
    GetTimeval(time, tobj);
  •    t.tv_sec = tobj->ts.tv_sec;
    
  • if (!tobj->as.bits.ts_got) {
  •  tobj->ts.tv_sec = make_time_t(&tobj->tm, tobj->as.bits.gmt);
    
  •  tobj->as.bits.ts_got = 1;
    
  • }
  • t.tv_sec = tobj->ts.tv_sec;
    t.tv_usec = tobj->ts.tv_nsec / 1000;
    return t;
    @@ -279,14 +292,22 @@ rb_time_timeval(VALUE time)
    }

+static struct timespec
+get_timespec(struct time_object *tobj)
+{

  • if (!tobj->as.bits.ts_got) {
  • tobj->ts.tv_sec = make_time_t(&tobj->tm, tobj->as.bits.gmt);
  • tobj->as.bits.ts_got = 1;
  • }
  • return tobj->ts;
    +}

struct timespec
rb_time_timespec(VALUE time)
{
struct time_object *tobj;

  • struct timespec t;

  • if (TYPE(time) == T_DATA && RDATA(time)->dfree == time_free) {

  • if (IS_TIME(time)) {
    GetTimeval(time, tobj);
  •    t = tobj->ts;
    
  • return t;
  • return get_timespec(tobj);
    }
    return time_timespec(time, Qfalse);
    @@ -328,10 +349,10 @@ time_s_at(int argc, VALUE *argv, VALUE k
    }
    t = time_new_internal(klass, ts.tv_sec, ts.tv_nsec);
  • if (TYPE(time) == T_DATA && RDATA(time)->dfree == time_free) {
  • if (IS_TIME(time)) {
    struct time_object *tobj, *tobj2;

GetTimeval(time, tobj);
GetTimeval(t, tobj2);

  • tobj2->gmt = tobj->gmt;
  • tobj2->as.bits.gmt = tobj->as.bits.gmt;
    }
    return t;
    @@ -589,5 +610,5 @@ typedef unsigned LONG_LONG unsigned_time

static time_t
-search_time_t(struct tm *tptr, int utc_p)
+search_time_t(struct tm *tptr, const int utc_p)
{
time_t guess, guess_lo, guess_hi;
@@ -897,10 +918,15 @@ time_utc_or_local(int argc, VALUE *argv,
struct tm tm;
VALUE time;

  • struct time_object *tobj;
    long nsec;

    time_arg(argc, argv, &tm, &nsec);

  • time = time_new_internal(klass, make_time_t(&tm, utc_p), nsec);
  • if (utc_p) return time_gmtime(time);
  • return time_localtime(time);
  • time = time_s_alloc(klass);
  • GetTimeval(time, tobj);
  • tobj->tm = tm;
  • tobj->ts.tv_nsec = nsec;
  • tobj->as.bits.tm_got = 1;
  • tobj->as.bits.gmt = utc_p != 0;
  • return time;
    }

@@ -993,4 +1019,5 @@ time_to_i(VALUE time)

 GetTimeval(time, tobj);
  • get_timespec(tobj);
    return LONG2NUM(tobj->ts.tv_sec);
    }
    @@ -1017,4 +1044,5 @@ time_to_f(VALUE time)

    GetTimeval(time, tobj);

  • get_timespec(tobj);
    return
    DOUBLE2NUM((double)tobj->ts.tv_sec+(double)tobj->ts.tv_nsec/1e9);
    }
    @@ -1038,4 +1066,5 @@ time_usec(VALUE time)

    GetTimeval(time, tobj);

  • get_timespec(tobj);
    return LONG2NUM(tobj->ts.tv_nsec/1000);
    }
    @@ -1064,4 +1093,5 @@ time_nsec(VALUE time)

    GetTimeval(time, tobj);

  • get_timespec(tobj);
    return LONG2NUM(tobj->ts.tv_nsec);
    }
    @@ -1093,6 +1123,8 @@ time_cmp(VALUE time1, VALUE time2)

    GetTimeval(time1, tobj1);

  • if (TYPE(time2) == T_DATA && RDATA(time2)->dfree == time_free) {
  • if (IS_TIME(time2)) {
    GetTimeval(time2, tobj2);

  • get_timespec(tobj1);

  • get_timespec(tobj2);
    if (tobj1->ts.tv_sec == tobj2->ts.tv_sec) {
    if (tobj1->ts.tv_nsec == tobj2->ts.tv_nsec) return INT2FIX(0);
    @@ -1132,6 +1164,8 @@ time_eql(VALUE time1, VALUE time2)

    GetTimeval(time1, tobj1);

  • if (TYPE(time2) == T_DATA && RDATA(time2)->dfree == time_free) {
  • if (IS_TIME(time2)) {
    GetTimeval(time2, tobj2);

  • get_timespec(tobj1);

  • get_timespec(tobj2);
    if (tobj1->ts.tv_sec == tobj2->ts.tv_sec) {
    if (tobj1->ts.tv_nsec == tobj2->ts.tv_nsec) return Qtrue;
    @@ -1166,5 +1200,5 @@ time_utc_p(VALUE time)

    GetTimeval(time, tobj);

  • if (tobj->gmt) return Qtrue;
  • if (tobj->as.bits.gmt) return Qtrue;
    return Qfalse;
    }
    @@ -1180,9 +1214,8 @@ static VALUE
    time_hash(VALUE time)
    {
  • struct time_object *tobj;
  • struct timespec ts = rb_time_timespec(time);
    long hash;
  • GetTimeval(time, tobj);
  • hash = tobj->ts.tv_sec ^ tobj->ts.tv_nsec;
  • hash = ts.tv_sec ^ ts.tv_nsec;
    return LONG2FIX(hash);
    }
    @@ -1196,5 +1229,5 @@ time_init_copy(VALUE copy, VALUE time)
    if (copy == time) return copy;
    time_modify(copy);
  • if (TYPE(time) != T_DATA || RDATA(time)->dfree != time_free) {
  • if (!IS_TIME(time)) {
    rb_raise(rb_eTypeError, “wrong argument type”);
    }
    @@ -1236,6 +1269,6 @@ time_localtime(VALUE time)

    GetTimeval(time, tobj);

  • if (!tobj->gmt) {
  • if (tobj->tm_got)
  • if (!tobj->as.bits.gmt) {
  • if (tobj->as.bits.tm_got)
    return time;
    }
    @@ -1243,11 +1276,11 @@ time_localtime(VALUE time)
    time_modify(time);
    }
  • t = tobj->ts.tv_sec;
  • t = get_timespec(tobj).tv_sec;
    tm_tmp = LOCALTIME(&t, result);
    if (!tm_tmp)
    rb_raise(rb_eArgError, “localtime error”);
    tobj->tm = *tm_tmp;
  • tobj->tm_got = 1;
  • tobj->gmt = 0;
  • tobj->as.bits.tm_got = 1;

  • tobj->as.bits.gmt = 0;
    return time;
    }
    @@ -1280,6 +1313,6 @@ time_gmtime(VALUE time)

    GetTimeval(time, tobj);

  • if (tobj->gmt) {
  • if (tobj->tm_got)
  • if (tobj->as.bits.gmt) {
  • if (tobj->as.bits.tm_got)
    return time;
    }
    @@ -1287,4 +1320,5 @@ time_gmtime(VALUE time)
    time_modify(time);
    }
  • get_timespec(tobj);
    t = tobj->ts.tv_sec;
    tm_tmp = GMTIME(&t, result);
    @@ -1292,6 +1326,6 @@ time_gmtime(VALUE time)
    rb_raise(rb_eArgError, “gmtime error”);
    tobj->tm = *tm_tmp;
  • tobj->tm_got = 1;
  • tobj->gmt = 1;
  • tobj->as.bits.tm_got = 1;

  • tobj->as.bits.gmt = 1;
    return time;
    }
    @@ -1363,6 +1397,6 @@ time_asctime(VALUE time)

    GetTimeval(time, tobj);

  • if (tobj->tm_got == 0) {
  • time_get_tm(time, tobj->gmt);
  • if (tobj->as.bits.tm_got == 0) {

  • time_get_tm(time, tobj->as.bits.gmt);
    }
    s = ASCTIME(&tobj->tm, buf);
    @@ -1400,14 +1434,14 @@ time_to_s(VALUE time)

    GetTimeval(time, tobj);

  • if (tobj->tm_got == 0) {
  • time_get_tm(time, tobj->gmt);
  • if (tobj->as.bits.tm_got == 0) {
  • time_get_tm(time, tobj->as.bits.gmt);
    }
  • if (tobj->gmt == 1) {
  • if (tobj->as.bits.gmt) {
    len = rb_strftime(buf, sizeof(buf), “%Y-%m-%d %H:%M:%S UTC”,
  •    &tobj->tm, &tobj->ts, tobj->gmt);
    
  •    &tobj->tm, &tobj->ts, tobj->as.bits.gmt);
    
    }
    else {
    len = rb_strftime(buf, sizeof(buf), “%Y-%m-%d %H:%M:%S %z”,
  •    &tobj->tm, &tobj->ts, tobj->gmt);
    
  •    &tobj->tm, &tobj->ts, tobj->as.bits.gmt);
    
    }
    return rb_str_new(buf, len);
    @@ -1428,4 +1462,5 @@ time_add(struct time_object *tobj, VALUE
    sign = -sign;
    }
  • get_timespec(tobj);
    d = modf(v, &f);
    sec_off = (unsigned_time_t)f;
    @@ -1448,7 +1483,7 @@ time_add(struct time_object *tobj, VALUE
    }
    result = rb_time_nano_new(sec, nsec);
  • if (tobj->gmt) {
  • if (tobj->as.bits.gmt) {
    GetTimeval(result, tobj);
  • tobj->gmt = 1;
  • tobj->as.bits.gmt = 1;
    }
    return result;
    @@ -1472,5 +1507,5 @@ time_plus(VALUE time1, VALUE time2)
    GetTimeval(time1, tobj);
  • if (TYPE(time2) == T_DATA && RDATA(time2)->dfree == time_free) {
  • if (IS_TIME(time2)) {
    rb_raise(rb_eTypeError, “time + time?”);
    }
    @@ -1499,9 +1534,11 @@ time_minus(VALUE time1, VALUE time2)

    GetTimeval(time1, tobj);

  • if (TYPE(time2) == T_DATA && RDATA(time2)->dfree == time_free) {
  • if (IS_TIME(time2)) {
    struct time_object *tobj2;
    double f;

GetTimeval(time2, tobj2);

  • get_timespec(tobj);

  • get_timespec(tobj2);
    if (tobj->ts.tv_sec < tobj2->ts.tv_sec)
    f = -(double)(unsigned_time_t)(tobj2->ts.tv_sec -
    tobj->ts.tv_sec);
    @@ -1532,8 +1569,9 @@ time_succ(VALUE time)

    GetTimeval(time, tobj);

  • gmt = tobj->gmt;
  • get_timespec(tobj);
  • gmt = tobj->as.bits.gmt;
    time = rb_time_nano_new(tobj->ts.tv_sec + 1, tobj->ts.tv_nsec);
    GetTimeval(time, tobj);
  • tobj->gmt = gmt;
  • tobj->as.bits.gmt = gmt;
    return time;
    }
    @@ -1564,6 +1602,6 @@ time_sec(VALUE time)

    GetTimeval(time, tobj);

  • if (tobj->tm_got == 0) {
  • time_get_tm(time, tobj->gmt);
  • if (!tobj->as.bits.tm_got) {

  • time_get_tm(time, tobj->as.bits.gmt);
    }
    return INT2FIX(tobj->tm.tm_sec);
    @@ -1586,6 +1624,6 @@ time_min(VALUE time)

    GetTimeval(time, tobj);

  • if (tobj->tm_got == 0) {
  • time_get_tm(time, tobj->gmt);
  • if (!tobj->as.bits.tm_got) {

  • time_get_tm(time, tobj->as.bits.gmt);
    }
    return INT2FIX(tobj->tm.tm_min);
    @@ -1608,6 +1646,6 @@ time_hour(VALUE time)

    GetTimeval(time, tobj);

  • if (tobj->tm_got == 0) {
  • time_get_tm(time, tobj->gmt);
  • if (!tobj->as.bits.tm_got) {

  • time_get_tm(time, tobj->as.bits.gmt);
    }
    return INT2FIX(tobj->tm.tm_hour);
    @@ -1632,6 +1670,6 @@ time_mday(VALUE time)

    GetTimeval(time, tobj);

  • if (tobj->tm_got == 0) {
  • time_get_tm(time, tobj->gmt);
  • if (!tobj->as.bits.tm_got) {

  • time_get_tm(time, tobj->as.bits.gmt);
    }
    return INT2FIX(tobj->tm.tm_mday);
    @@ -1656,6 +1694,6 @@ time_mon(VALUE time)

    GetTimeval(time, tobj);

  • if (tobj->tm_got == 0) {
  • time_get_tm(time, tobj->gmt);
  • if (!tobj->as.bits.tm_got) {

  • time_get_tm(time, tobj->as.bits.gmt);
    }
    return INT2FIX(tobj->tm.tm_mon+1);
    @@ -1678,6 +1716,6 @@ time_year(VALUE time)

    GetTimeval(time, tobj);

  • if (tobj->tm_got == 0) {
  • time_get_tm(time, tobj->gmt);
  • if (!tobj->as.bits.tm_got) {

  • time_get_tm(time, tobj->as.bits.gmt);
    }
    return LONG2NUM((long)tobj->tm.tm_year+1900);
    @@ -1708,6 +1746,6 @@ time_wday(VALUE time)

    GetTimeval(time, tobj);

  • if (tobj->tm_got == 0) {
  • time_get_tm(time, tobj->gmt);
  • if (!tobj->as.bits.tm_got) {
  • time_get_tm(time, tobj->as.bits.gmt);
    }
    return INT2FIX(tobj->tm.tm_wday);
    @@ -1717,6 +1755,6 @@ time_wday(VALUE time)
    struct time_object *tobj;
    GetTimeval(time, tobj);\
  • if (tobj->tm_got == 0) {\
  • time_get_tm(time, tobj->gmt);\
  • if (!tobj->as.bits.tm_got) {\

  • time_get_tm(time, tobj->as.bits.gmt);
    }
    return (tobj->tm.tm_wday == (n)) ? Qtrue : Qfalse;
    @@ -1851,6 +1889,6 @@ time_yday(VALUE time)

    GetTimeval(time, tobj);

  • if (tobj->tm_got == 0) {
  • time_get_tm(time, tobj->gmt);
  • if (!tobj->as.bits.tm_got) {

  • time_get_tm(time, tobj->as.bits.gmt);
    }
    return INT2FIX(tobj->tm.tm_yday+1);
    @@ -1888,6 +1926,6 @@ time_isdst(VALUE time)

    GetTimeval(time, tobj);

  • if (tobj->tm_got == 0) {
  • time_get_tm(time, tobj->gmt);
  • if (!tobj->as.bits.tm_got) {

  • time_get_tm(time, tobj->as.bits.gmt);
    }
    return tobj->tm.tm_isdst?Qtrue:Qfalse;
    @@ -1917,9 +1955,9 @@ time_zone(VALUE time)

    GetTimeval(time, tobj);

  • if (tobj->tm_got == 0) {
  • time_get_tm(time, tobj->gmt);
  • if (!tobj->as.bits.tm_got) {
  • time_get_tm(time, tobj->as.bits.gmt);
    }
  • if (tobj->gmt == 1) {
  • if (tobj->as.bits.gmt) {
    return rb_str_new2(“UTC”);
    }
    @@ -1930,5 +1968,5 @@ time_zone(VALUE time)
    #else
    len = rb_strftime(buf, sizeof(buf), “%Z”,
  •      &tobj->tm, &tobj->ts, tobj->gmt);
    
  •      &tobj->tm, &tobj->ts, tobj->as.bits.gmt);
    

    return rb_str_new(buf, len);
    #endif
    @@ -1956,9 +1994,9 @@ time_utc_offset(VALUE time)

    GetTimeval(time, tobj);

  • if (tobj->tm_got == 0) {
  • time_get_tm(time, tobj->gmt);
  • if (!tobj->as.bits.tm_got) {
  • time_get_tm(time, tobj->as.bits.gmt);
    }
  • if (tobj->gmt == 1) {
  • if (tobj->as.bits.gmt) {
    return INT2FIX(0);
    }
    @@ -1972,4 +2010,5 @@ time_utc_offset(VALUE time)
    IF_HAVE_GMTIME_R(struct tm result);
    l = &tobj->tm;

  • get_timespec(tobj);
    t = tobj->ts.tv_sec;
    u = GMTIME(&t, result);
    @@ -2013,6 +2052,6 @@ time_to_a(VALUE time)

    GetTimeval(time, tobj);

  • if (tobj->tm_got == 0) {
  • time_get_tm(time, tobj->gmt);
  • if (!tobj->as.bits.tm_got) {

  • time_get_tm(time, tobj->as.bits.gmt);
    }
    return rb_ary_new3(10,
    @@ -2119,6 +2158,6 @@ time_strftime(VALUE time, VALUE format)

    GetTimeval(time, tobj);

  • if (tobj->tm_got == 0) {
  • time_get_tm(time, tobj->gmt);
  • if (!tobj->as.bits.tm_got) {
  • time_get_tm(time, tobj->as.bits.gmt);
    }
    StringValue(format);
    @@ -2138,5 +2177,5 @@ time_strftime(VALUE time, VALUE format)
    str = rb_str_new(0, 0);
    while (p < pe) {
  •  len = rb_strftime_alloc(&buf, p, &tobj->tm, &tobj->ts, 
    

tobj->gmt);

  •  len = rb_strftime_alloc(&buf, p, &tobj->tm, &tobj->ts, 
    

tobj->as.bits.gmt);
rb_str_cat(str, buf, len);
p += strlen§;
@@ -2152,5 +2191,5 @@ time_strftime(VALUE time, VALUE format)
else {
len = rb_strftime_alloc(&buf, RSTRING_PTR(format),

  •           &tobj->tm, &tobj->ts, tobj->gmt);
    
  •           &tobj->tm, &tobj->ts, tobj->as.bits.gmt);
    
    }
    str = rb_str_new(buf, len);
    @@ -2174,4 +2213,5 @@ time_mdump(VALUE time)
    int nsec;
    int i;
  • int gmt;
    VALUE str;
    IF_HAVE_GMTIME_R(struct tm result);
    @@ -2179,12 +2219,18 @@ time_mdump(VALUE time)
    GetTimeval(time, tobj);
  • t = tobj->ts.tv_sec;
  • tm = GMTIME(&t, result);
  • if (tobj->as.bits.tm_got) {

  • tm = &tobj->tm;

  • }

  • else {

  • t = tobj->ts.tv_sec;

  • tm = GMTIME(&t, result);

  • }

    if ((tm->tm_year & 0xffff) != tm->tm_year)
    rb_raise(rb_eArgError, “year too big to marshal: %ld”,
    (long)tm->tm_year);

  • gmt = tobj->as.bits.gmt;
    p = 0x1UL << 31 | /* 1 */

  • tobj->gmt << 30 | /* 1 */
  • gmt << 30 | /* 1 /
    tm->tm_year << 14 | /
    16 /
    tm->tm_mon << 10 | /
    4 */
    @@ -2286,9 +2332,15 @@ time_mload(VALUE time, VALUE str)
    }

  • GetTimeval(time, tobj);
    if ((p & (1UL<<31)) == 0) {

  •    gmt = 0;
    
    sec = p;
    usec = s;
    nsec = usec * 1000;
  • time_overflow_p(&sec, &nsec);
  • tobj->as.bits.tm_got = 0;
  • tobj->as.bits.ts_got = 1;
  • tobj->as.bits.gmt = 0;
  • tobj->ts.tv_sec = sec;
  • tobj->ts.tv_nsec = nsec;
    }
    else {
    @@ -2303,5 +2355,4 @@ time_mload(VALUE time, VALUE str)
    tm.tm_isdst = 0;
  • sec = make_time_t(&tm, Qtrue);
    usec = (long)(s & 0xfffff);
    nsec = usec * 1000;
    @@ -2323,14 +2374,12 @@ time_mload(VALUE time, VALUE str)
    nsec += digit;
    }
    -end_submicro: ;
    }
  •  end_submicro:
    
  • tobj->as.bits.tm_got = 1;
  • tobj->as.bits.ts_got = 1;
  • tobj->as.bits.gmt = gmt;
  • tobj->tm = tm;
  • tobj->ts.tv_nsec = nsec;
    }
  • time_overflow_p(&sec, &nsec);

  • GetTimeval(time, tobj);

  • tobj->tm_got = 0;

  • tobj->gmt = gmt;

  • tobj->ts.tv_sec = sec;

  • tobj->ts.tv_nsec = nsec;

    return time;

e$BA0ED$G$9!#e(B

At Fri, 22 Aug 2008 22:26:32 +0900,
Tadayoshi F. [email protected] wrote:

e$B$r<h$C$F$$$^$9!#e(B%N e$B$@$1$G$J$/!“A4BN$H$7$F!”$3$&$7$?$i$$$$!"$H$$$&$3$H$,$J$$$He(B
e$BD>$A$K$OH=CG$,=PMh$J$$$H;W$$$^$9!#e(B

e$B0JA0$Ne(BTime#strftimee$B$O%W%i%C%H%U%)!<%$K$h$C$F5sF0$,0[$J$C$F$$$?$o$1$G$9e(B e$B$,!"e(BDateTime#strftimee$B$NJ}$O$I$N%W%i%C%H%U%)!<%$G$bF1$85sF0$N$O$:$J$N$G!"e(B
e$B8_49@-$N4QE@$+$i!“4pK\E*$K$Oe(BDateTimee$B$K9g$o$;$kJ}?K$,$h$$$N$G$O$J$$$+$He(B
e$B;W$$$^$9e(B(e$B<+J,$,$h$/;H$&$N$,e(Bglibce$B4D6-$H$$$&$3$H$b$”$j$^$9$,e(B)e$B!#e(B

e$B$?$@!“e(B%Ne$B$K$D$$$F$Oe(BPerle$B$N5sF0$NJ}$,K>$^$7$$$H;W$$$^$9$N$G!”$3$&$$$&%1!<e(B
e$B%9$K$D$$$F$O8DJL$K8!F$$9$k$H$$$&$3$H$G$I$&$G$7$g$&$+!#e(B

GNU
datee$B$b!"e(B9e$B$h$jBg$-$$?tCM$r;XDj$7$?>l9g$K:8$Ke(B0e$B$rIU$1$k$3$H$r=|$1$P!"e(B
Perle$B$HF1$85sF0$N$h$&$G$9$M!#e(B

$ date --version
date (GNU coreutils) 6.10
Copyright e$(D"me(B 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
http://gnu.org/licenses/gpl.html
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

e$B:n<Te(B David MacKenzie.
$ date ‘+%N’
777164791
$ date ‘+%3N’
526
$ date ‘+%6N’
534273
$ date ‘+%9N’
019151635
$ date ‘+%12N’
000712771290

e$BA0ED$G$9!#e(B

At Fri, 22 Aug 2008 11:51:12 +0900,
Tanaka A. [email protected] wrote:

e$B$N$h$&$K=q$1$k$N$G$9$,!"$3$A$i$Oe(BPerle$B$N$H$O0UL#$,0c$C$F!“e(B9e$B$h$jBg$-$$CM$r;XDje(B
e$B$7$?;~$K!”;XDj$7$?7e?t$K$J$k$h$&$KA0$Ke(B0e$B$r5M$a$k5!G=$G!"e(BNe$B0J30$NJQ49;XDjJ8e(B
e$B;z$G$b;H$($k$h$&$G$9!#e(B

e$B$A$g$C$H;n$7$F$_$F;W$C$?$N$G$9$,!"e(B9 e$B$h$jBg$-$JCM$r;XDj$7$?;~e(B
e$B$Oe(B 0 e$B$r1&$K$D$1$k$Y$-$8$c$J$$$G$9$+$M!#e(B

% ./ruby -e ‘p Time.now.strftime(“%100N”)’
“297311763”

e$B$3$NItJ,$Oe(BPerle$B$K9g$o$;$?$@$1$J$N$G!“$H$/$K?<$$9M$($O$”$j$^$;$s$G$7$?!#e(B

$ perl -e ‘use DateTime; print DateTime->now()->strftime(“%F
%H:%M:%S.%100N\n”);’
2008-08-22 15:56:55.000000000

date(1)e$B$N$h$&$K:8$KIU$1$k$h$j$O1&$KIU$1$kJ}$,;H$$>!<j$,$h$5$=$&$G$9$M!#e(B

e$BA0ED$G$9!#e(B

At Fri, 22 Aug 2008 14:27:09 +0900,
Nobuyoshi N. [email protected] wrote:

date/format.rbe$B$He(Bstrftime.ce$B$GF1$8$h$&$J$3$H$r$d$C$F$$$k$H0l4S$5$;e(B
e$B$k$N$,$a$s$I$&$J$N$G!"e(BTimee$B$G$be(Btime_te$B$NHO0O$r1[$($kHO0O$rI=8=$G$-e(B
e$B$k$h$&$K$7$F!"e(BDateTimee$B$G$be(BTime#strftimee$B$r;H$&$H$$$&$N$O$I$&$G$7$ge(B
e$B$&$+!#e(B

Timee$B$Ge(Btime_te$B$NHO0O$r1[$($kF|;~$r07$($k$h$&$K$9$k$N$O$h$$$H;W$&$N$G$9$,!"e(B
DateTimee$B$Ge(BTime#strftimee$B$r;H$&$h$&$K$9$k$N$O$b$&>/$78_49@-$r9b$a$F$+$i$Ne(B
e$BJ}$,$h$$$N$G$O$J$$$G$7$g$&$+!#e(B

e$B$?$@!“e(B%Ne$B$K$D$$$F$Oe(BPerle$B$N5sF0$NJ}$,K>$^$7$$$H;W$$$^$9$N$G!”$3$&$$$&%1!<e(B
e$B%9$K$D$$$F$O8DJL$K8!F$$9$k$H$$$&$3$H$G$I$&$G$7$g$&$+!#e(B

e$B$G$O!"$=$&$$$&$3$H$K$7$^$7$g$&!#B>$K$b$"$k$+$b$7$l$^$;$s!#<+J,$G$bHyL/e(B
e$B$@$J$H;W$$$J$,$i<BAu$7$F$?21$($,$"$k$N$G!#e(B

GNU datee$B$b!"e(B9e$B$h$jBg$-$$?tCM$r;XDj$7$?>l9g$K:8$Ke(B0e$B$rIU$1$k$3$H$r=|$1$P!"e(B
Perle$B$HF1$85sF0$N$h$&$G$9$M!#e(B

e$B$s!<!"0JA0$H>/$7JQ$C$F$$$k$N$G$9$M!#A0$O!"e(B%N
e$B$G$b7e$O8:$i$;$J$+$C$?$O$:$J$N$K!#e(B

e$B$H$j$"$($:!"$3$s$J46$8$G$h$5$=$&$J$iD>$7$F$*$-$^$9!#e(B

Index: lib/date/format.rb

— lib/date/format.rb (revision 18786)
+++ lib/date/format.rb (working copy)
@@ -257,12 +257,16 @@
when ‘j’; emit_n(yday, 3, f)
when ‘k’; emit_a(hour, 2, f)
when ‘L’

  • emit_n((sec_fraction / MILLISECONDS_IN_SECOND).floor, 3, f)
  • w = f[:w] || 3
  • u = 10**w
  • emit_n((sec_fraction * u).floor, w, f)
    when ‘l’; emit_a((hour % 12).nonzero? || 12, 2, f)
    when ‘M’, ‘OM’; emit_n(min, 2, f)
    when ‘m’, ‘Om’; emit_n(mon, 2, f)
    when ‘N’
  • emit_n((sec_fraction / NANOSECONDS_IN_SECOND).floor, 9, f)
  • w = f[:w] || 9
  • u = 10**w
  • emit_n((sec_fraction * u).floor, w, f)
    when ‘n’; “\n”
    when ‘P’; emit_ad(strftime(’%p’).downcase, 0, f)
    when ‘p’; emit_au(if hour < 12 then ‘AM’ else ‘PM’ end, 0, f)

e$BA0ED$G$9!#e(B

2008/08/23 13:20 Tadayoshi F. [email protected]:

GNU datee$B$b!"e(B9e$B$h$jBg$-$$?tCM$r;XDj$7$?>l9g$K:8$Ke(B0e$B$rIU$1$k$3$H$r=|$1$P!"e(B
Perle$B$HF1$85sF0$N$h$&$G$9$M!#e(B

e$B$s!<!"0JA0$H>/$7JQ$C$F$$$k$N$G$9$M!#A0$O!"e(B%N e$B$G$b7e$O8:$i$;$J$+$C$?$O$:$J$N$K!#e(B

e$B$H$j$“$($:!”$3$s$J46$8$G$h$5$=$&$J$iD>$7$F$*$-$^$9!#e(B

e$B$“$j$,$H$&$4$6$$$^$9!#;n$7$?$H$3$m4|BTDL$j$KF0:n$7$^$7$?!#e(B
commite$B$7$F$$$?$@$1$k$H$”$j$,$?$$$G$9!#e(B