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]'.