Hello,

two weeks ago Hume Smith wrote in comp.lang.tcl a nice application
of the clock command:

> >I have a question of the clock's scan format.
> >How is the 2nd Monday in November expressed in Tcl?
> best i can do is
> % foreach i {90 91 92 93 94 95 96 97 98 99} {
> puts [clock format [clock scan monday -base [clock scan 11/8/$i]]]
> }

I tried this in Jacl, and I found two errors in one command!
First there was an overflow in the -base option, which leads to
dates around 1.1.1970. The second error was, that the handling
of daynames are completely wrong in ClockCmd.java. (It simply sets
the DAY_OF_MONTH to the value of the weekday - absolute nonsense).

I fixed both bugs and did some additional layout improvements.
See the patch below.

Since both errors are not tested by tcl/clock.test, I added some tests
for daynames and -base option. This patch is also attached below.
I will create a RFE of Tcl with this patch, too.

Greetings, Krischan
-- 
Christian Krone, SQL Datenbanksysteme GmbH
Mail mailto:[EMAIL PROTECTED]
*** ClockCmd.java.org   Mon Nov 22 10:16:07 1999
--- ClockCmd.java       Mon Nov 22 10:16:48 1999
***************
*** 3,9 ****
   *
   *    Implements the built-in "clock" Tcl command.
   *
!  * Copyright (c) 1998 Christian Krone.
   * Copyright (c) 1997 Cornell University.
   * Copyright (c) 1995-1997 Sun Microsystems, Inc.
   * Copyright (c) 1992-1995 Karl Lehenbauer and Mark Diekhans.
--- 3,9 ----
   *
   *    Implements the built-in "clock" Tcl command.
   *
!  * Copyright (c) 1998-1999 Christian Krone.
   * Copyright (c) 1997 Cornell University.
   * Copyright (c) 1995-1997 Sun Microsystems, Inc.
   * Copyright (c) 1992-1995 Karl Lehenbauer and Mark Diekhans.
***************
*** 101,107 ****
            if (argv.length != 2) {
                throw new TclNumArgsException(interp, 2, argv, null);
            }
-           //long millis = new java.util.Date().getTime();
            long millis = System.currentTimeMillis();
            int clicks = (int)(millis%Integer.MAX_VALUE);
            interp.setResult(clicks);
--- 101,106 ----
***************
*** 163,169 ****
                    "clockval ?-format string? ?-gmt boolean?");
            }
            if (baseObj != null) {
!               baseClock = new Date(TclInteger.get(interp, baseObj)*1000);
            } else {
                baseClock = new Date();
            }
--- 162,169 ----
                    "clockval ?-format string? ?-gmt boolean?");
            }
            if (baseObj != null) {
!               long seconds = TclInteger.get(interp, baseObj);
!               baseClock = new Date(seconds*1000);
            } else {
                baseClock = new Date();
            }
***************
*** 184,190 ****
            if (argv.length != 2) {
                throw new TclNumArgsException(interp, 2, argv, null);
            }
!           long millis = new java.util.Date().getTime();
            int seconds = (int)(millis/1000);
            interp.setResult(seconds);
            break;
--- 184,190 ----
            if (argv.length != 2) {
                throw new TclNumArgsException(interp, 2, argv, null);
            }
!           long millis = System.currentTimeMillis();
            int seconds = (int)(millis/1000);
            interp.setResult(seconds);
            break;
***************
*** 427,434 ****
  GetWeek(
      Calendar calendar,                // Calendar containing Date.
      int firstDayOfWeek,               // this day starts a week (MONDAY/SUNDAY).
!     boolean iso                       // evaluate according to ISO?
! )
  {
      if (iso) {
          firstDayOfWeek = Calendar.MONDAY;
--- 427,433 ----
  GetWeek(
      Calendar calendar,                // Calendar containing Date.
      int firstDayOfWeek,               // this day starts a week (MONDAY/SUNDAY).
!     boolean iso)              // evaluate according to ISO?
  {
      if (iso) {
          firstDayOfWeek = Calendar.MONDAY;
***************
*** 459,464 ****
--- 458,497 ----
  /**
   *-----------------------------------------------------------------------------
   *
+  * SetWeekday --
+  *
+  *      The date of the given calendar will be incremented, so that it will
+  *    match the weekday in the diff object. If dayOrdinal is bigger than 1,
+  *    additional weeks will be added.
+  *
+  * Results:
+  *      None.
+  *
+  * Side effects:
+  *      Modifies the given calendar.
+  *
+  *-----------------------------------------------------------------------------
+  */
+ 
+ private void
+ SetWeekday(
+     Calendar calendar,                // Calendar containing Date.
+     ClockRelTimespan diff)    // time difference to evaluate
+ {
+     int weekday = diff.getWeekday();
+     int dayOrdinal = diff.getDayOrdinal();
+ 
+     while (calendar.get(Calendar.DAY_OF_WEEK) != weekday) {
+       calendar.add(Calendar.DATE, 1);
+     }
+     if (dayOrdinal > 1) {
+       calendar.add(Calendar.DATE, 7*(dayOrdinal-1));
+     }
+ }
+ 
+ /**
+  *-----------------------------------------------------------------------------
+  *
   * GetDate --
   *
   *      Scan a human readable date string and construct a Date.
***************
*** 504,510 ****
            hasZone++;
        } else if (ParseDate(dt, parsePos, calendar)) {
            hasDate++;
!       } else if (ParseDay(dt, parsePos, calendar)) {
            hasDay++;
        } else if (ParseRel(dt, parsePos, diff)) {
            hasRel++;
--- 537,543 ----
            hasZone++;
        } else if (ParseDate(dt, parsePos, calendar)) {
            hasDate++;
!       } else if (ParseDay(dt, parsePos, diff)) {
            hasDay++;
        } else if (ParseRel(dt, parsePos, diff)) {
            hasRel++;
***************
*** 547,552 ****
--- 580,589 ----
        calendar.add(Calendar.MONTH, diff.getMonths());
      }
  
+     if (hasDay > 0 && hasDate == 0) {
+       SetWeekday(calendar, diff);
+     }
+ 
      return calendar.getTime();
  }
  
***************
*** 578,585 ****
  ParseTime (
      ClockToken[] dt,          // Input as scanned array of tokens
      ParsePosition parsePos,   // Current position in input
!     Calendar calendar         // calendar object to set
! )
  {
      int pos = parsePos.getIndex();
  
--- 615,621 ----
  ParseTime (
      ClockToken[] dt,          // Input as scanned array of tokens
      ParsePosition parsePos,   // Current position in input
!     Calendar calendar)                // calendar object to set
  {
      int pos = parsePos.getIndex();
  
***************
*** 663,670 ****
  ParseZone (
      ClockToken[] dt,          // Input as scanned array of tokens
      ParsePosition parsePos,   // Current position in input
!     Calendar calendar         // calendar object to set
! )
  {
      int pos = parsePos.getIndex();
  
--- 699,705 ----
  ParseZone (
      ClockToken[] dt,          // Input as scanned array of tokens
      ParsePosition parsePos,   // Current position in input
!     Calendar calendar)                // calendar object to set
  {
      int pos = parsePos.getIndex();
  
***************
*** 703,710 ****
   *            ;
   *
   * Results:
!  *      True, if a day was read (parsePos was incremented and calendar
!  *    was set according to the read day); false otherwise.
   *
   * Side effects:
   *      None.
--- 738,745 ----
   *            ;
   *
   * Results:
!  *    True, if a day was read (parsePos was incremented and the time
!  *    difference was set according to the read day); false otherwise.
   *
   * Side effects:
   *      None.
***************
*** 716,745 ****
  ParseDay (
      ClockToken[] dt,          // Input as scanned array of tokens
      ParsePosition parsePos,   // Current position in input
!     Calendar calendar         // calendar object to set
! )
  {
      int pos = parsePos.getIndex();
  
      if (pos+1 < dt.length &&
        dt[pos].is(ClockToken.DAY) &&
        dt[pos+1].is(',')) {
!       calendar.set(Calendar.DAY_OF_MONTH, dt[pos].getInt());
!         parsePos.setIndex(pos+2);
!         return true;
      }
      if (pos+1 < dt.length &&
        dt[pos].isUNumber() &&
        dt[pos+1].is(ClockToken.DAY)) {
!       calendar.set(Calendar.DAY_OF_MONTH, dt[pos+1].getInt());
!         parsePos.setIndex(pos+2);
!         return true;
      }
      if (pos < dt.length &&
        dt[pos].is(ClockToken.DAY)) {
!       calendar.set(Calendar.DAY_OF_MONTH, dt[pos].getInt());
!         parsePos.setIndex(pos+1);
!         return true;
      }
      return false;
  }
--- 751,779 ----
  ParseDay (
      ClockToken[] dt,          // Input as scanned array of tokens
      ParsePosition parsePos,   // Current position in input
!     ClockRelTimespan diff)    // time difference to evaluate
  {
      int pos = parsePos.getIndex();
  
      if (pos+1 < dt.length &&
        dt[pos].is(ClockToken.DAY) &&
        dt[pos+1].is(',')) {
!       diff.setWeekday(dt[pos].getInt());
!       parsePos.setIndex(pos+2);
!       return true;
      }
      if (pos+1 < dt.length &&
        dt[pos].isUNumber() &&
        dt[pos+1].is(ClockToken.DAY)) {
!       diff.setWeekday(dt[pos+1].getInt(), dt[pos].getInt());
!       parsePos.setIndex(pos+2);
!       return true;
      }
      if (pos < dt.length &&
        dt[pos].is(ClockToken.DAY)) {
!       diff.setWeekday(dt[pos].getInt());
!       parsePos.setIndex(pos+1);
!       return true;
      }
      return false;
  }
***************
*** 774,781 ****
  ParseDate (
      ClockToken[] dt,          // Input as scanned array of tokens
      ParsePosition parsePos,   // Current position in input
!     Calendar calendar         // calendar object to set
! )
  {
      int pos = parsePos.getIndex();
  
--- 808,814 ----
  ParseDate (
      ClockToken[] dt,          // Input as scanned array of tokens
      ParsePosition parsePos,   // Current position in input
!     Calendar calendar)                // calendar object to set
  {
      int pos = parsePos.getIndex();
  
***************
*** 872,879 ****
      ClockToken[] dt,          // Input as scanned array of tokens
      ParsePosition parsePos,   // Current position in input
      Calendar calendar,                // calendar object to set
!     boolean mayBeYear         // number is considered to be year?
! )
  {
      int pos = parsePos.getIndex();
  
--- 905,911 ----
      ClockToken[] dt,          // Input as scanned array of tokens
      ParsePosition parsePos,   // Current position in input
      Calendar calendar,                // calendar object to set
!     boolean mayBeYear)                // number is considered to be year?
  {
      int pos = parsePos.getIndex();
  
***************
*** 919,926 ****
  ParseRel (
      ClockToken[] dt,          // Input as scanned array of tokens
      ParsePosition parsePos,   // Current position in input
!     ClockRelTimespan diff     // time difference to evaluate
! )
  {
      if (ParseRelUnit(dt, parsePos, diff)) {
          int pos = parsePos.getIndex();
--- 951,957 ----
  ParseRel (
      ClockToken[] dt,          // Input as scanned array of tokens
      ParsePosition parsePos,   // Current position in input
!     ClockRelTimespan diff)    // time difference to evaluate
  {
      if (ParseRelUnit(dt, parsePos, diff)) {
          int pos = parsePos.getIndex();
***************
*** 968,975 ****
  ParseRelUnit (
      ClockToken[] dt,          // Input as scanned array of tokens
      ParsePosition parsePos,   // Current position in input
!     ClockRelTimespan diff     // time difference to evaluate
! )
  {
      int pos = parsePos.getIndex();
  
--- 999,1005 ----
  ParseRelUnit (
      ClockToken[] dt,          // Input as scanned array of tokens
      ParsePosition parsePos,   // Current position in input
!     ClockRelTimespan diff)    // time difference to evaluate
  {
      int pos = parsePos.getIndex();
  
***************
*** 1036,1043 ****
      ClockToken[] dt,          // Input as scanned array of tokens
      ParsePosition parsePos,   // Current position in input
      Calendar calendar,                // calendar object to set
!     int hour                  // hour value (1-12 or 0-23) to set.
! )
  {
      int pos = parsePos.getIndex();
      int hourField;
--- 1066,1072 ----
      ClockToken[] dt,          // Input as scanned array of tokens
      ParsePosition parsePos,   // Current position in input
      Calendar calendar,                // calendar object to set
!     int hour)                 // hour value (1-12 or 0-23) to set.
  {
      int pos = parsePos.getIndex();
      int hourField;
***************
*** 1076,1083 ****
  private ClockToken[]
  GetTokens (
      String in,                // String to parse
!     boolean debug     // Send the generated token list to stderr?
! )
  {
      ParsePosition parsePos = new ParsePosition(0);
      ClockToken dt;
--- 1105,1111 ----
  private ClockToken[]
  GetTokens (
      String in,                // String to parse
!     boolean debug)    // Send the generated token list to stderr?
  {
      ParsePosition parsePos = new ParsePosition(0);
      ClockToken dt;
***************
*** 1124,1131 ****
  private ClockToken
  GetNextToken (
      String in,                        // String to parse
!     ParsePosition parsePos    // Current position in input
! )
  {
      int pos = parsePos.getIndex();
      int sign;
--- 1152,1158 ----
  private ClockToken
  GetNextToken (
      String in,                        // String to parse
!     ParsePosition parsePos)   // Current position in input
  {
      int pos = parsePos.getIndex();
      int sign;
***************
*** 1196,1203 ****
   */
  
  private ClockToken LookupWord(
!     String word                       // word to lookup
! )
  {
      int ix;
      String[] names;
--- 1223,1229 ----
   */
  
  private ClockToken LookupWord(
!     String word)              // word to lookup
  {
      int ix;
      String[] names;
***************
*** 1329,1335 ****
   *
   * CLASS ClockToken --
   *
!  *      An object of this class represents a lexical unit of the human
   *    readable date string. It can be one of the following variants:
   *
   *    - signed number,
--- 1355,1361 ----
   *
   * CLASS ClockToken --
   *
!  *    An object of this class represents a lexical unit of the human
   *    readable date string. It can be one of the following variants:
   *
   *    - signed number,
***************
*** 1433,1444 ****
   *
   * CLASS ClockRelTimespan --
   *
!  *      An object of this class can be used to track the time difference during
   *    the analysis of a relative time specification.
   *
!  *    It has two read only properties 'seconds' and 'months', which are set
!  *    to 0 during initialization and which can be modified by means of the
!  *    addSeconds(), addMonths() and negate() methods.
   *
   *-----------------------------------------------------------------------------
   */
--- 1459,1470 ----
   *
   * CLASS ClockRelTimespan --
   *
!  *    An object of this class can be used to track the time difference during
   *    the analysis of a relative time specification.
   *
!  *    It has four read only properties seconds, months, weekday and dayOrdinal,
!  *    which are set to 0 during initialization and which can be modified by
!  *    means of the addSeconds(), addMonths(), setWeekday() and negate() methods.
   *
   *-----------------------------------------------------------------------------
   */
***************
*** 1447,1452 ****
--- 1473,1480 ----
      ClockRelTimespan() {
          seconds = 0;
        months = 0;
+       weekday = 0;
+       dayOrdinal = 0;
      }
      void addSeconds(int s) {
          seconds += s;
***************
*** 1454,1459 ****
--- 1482,1494 ----
      void addMonths(int m) {
          months += m;
      }
+     void setWeekday(int w, int ord) {
+       weekday = w;
+       dayOrdinal = ord;
+     }
+     void setWeekday(int w) {
+       setWeekday(w, 1);
+     }
      void negate() {
          seconds = -seconds;
          months = -months;
***************
*** 1464,1469 ****
--- 1499,1512 ----
      int getMonths() {
          return months;
      }
+     int getWeekday() {
+         return weekday;
+     }
+     int getDayOrdinal() {
+         return dayOrdinal;
+     }
      private int seconds;
      private int months;
+     private int weekday;
+     private int dayOrdinal;
  }
*** clock.test.org      Mon Nov 22 10:18:35 1999
--- clock.test  Mon Nov 22 10:34:38 1999
***************
*** 173,175 ****
--- 173,202 ----
      set time [clock scan "March 1, 2001" -gmt true]
      clock format $time -format %j -gmt true
  } {060}
+ test clock-7.1 {weekday specification: 2nd monday in november} {
+     set res {}
+     foreach i {91 92 93 94 95 96} {
+       set nov8th [clock scan 11/8/$i -gmt true]
+       set monday [clock scan monday -base $nov8th -gmt true]
+       lappend res [clock format $monday -format %Y-%m-%d -gmt true]
+     }
+     set res
+ } {1991-11-11 1992-11-09 1993-11-08 1994-11-14 1995-11-13 1996-11-11}
+ test clock-7.2 {day specification: 2nd monday in november (2nd try)} {
+     set res {}
+     foreach i {91 92 93 94 95 96} {
+       set nov1th [clock scan 11/1/$i -gmt true]
+       set monday [clock scan "2 monday" -base $nov1th -gmt true]
+       lappend res [clock format $monday -format %Y-%m-%d -gmt true]
+     }
+     set res
+ } {1991-11-11 1992-11-09 1993-11-08 1994-11-14 1995-11-13 1996-11-11}
+ test clock-7.3 {day specification: last monday in november} {
+     set res {}
+     foreach i {91 92 93 94 95 96} {
+       set dec1th [clock scan 12/1/$i -gmt true]
+       set monday [clock scan "monday 1 week ago" -base $dec1th -gmt true]
+       lappend res [clock format $monday -format %Y-%m-%d -gmt true]
+     }
+     set res
+ } {1991-11-25 1992-11-30 1993-11-29 1994-11-28 1995-11-27 1996-11-25}

----------------------------------------------------------------
The TclJava mailing list is sponsored by Scriptics Corporation.
To subscribe:    send mail to [EMAIL PROTECTED]  
                 with the word SUBSCRIBE as the subject.
To unsubscribe:  send mail to [EMAIL PROTECTED] 
                 with the word UNSUBSCRIBE as the subject.
To send to the list, send email to '[EMAIL PROTECTED]'. 

Reply via email to