Tcl Source Code

Artifact [df51b2a505]
Login

Artifact df51b2a5055c2e2f7b9d8e647c1a6625bcf17ab8:

Attachment "clock-weekdays.diff" to ticket [5f71353740] added by gahr 2013-11-20 14:25:03. (unpublished)
Index: doc/clock.n
==================================================================
--- doc/clock.n
+++ doc/clock.n
@@ -87,14 +87,13 @@
 back in sync with UTC; its data model does not represent minutes that
 have 59 or 61 seconds.
 .TP
 \fIunit\fR
 One of the words, \fBseconds\fR, \fBminutes\fR, \fBhours\fR,
-\fBdays\fR, \fBweeks\fR, \fBmonths\fR, or \fByears\fR, or
-any unique prefix of such a word. Used in conjunction with \fIcount\fR
-to identify an interval of time, for example, \fI3 seconds\fR or
-\fI1 year\fR.
+\fBdays\fR, \fBweekdays\fR, \fBweeks\fR, \fBmonths\fR, or \fByears\fR.
+Used in conjunction with \fIcount\fR to identify an interval of time,
+for example, \fI3 seconds\fR or \fI1 year\fR.
 .SS "OPTIONS"
 .TP
 \fB\-base\fR time
 Specifies that any relative times present in a \fBclock scan\fR command
 are to be given relative to \fItime\fR.  \fItime\fR must be expressed as
@@ -173,12 +172,11 @@
 (expressed as nominal seconds from the epoch time of 1 January 1970, 00:00 UTC)
 given as its first argument.  The remaining arguments (other than the
 possible \fB\-timezone\fR, \fB\-locale\fR and \fB\-gmt\fR options)
 are integers and keywords in alternation, where the keywords are chosen
 from \fBseconds\fR, \fBminutes\fR, \fBhours\fR,
-\fBdays\fR, \fBweeks\fR, \fBmonths\fR, or \fByears\fR, or
-any unique prefix of such a word.
+\fBdays\fR, \fBweekdays\fR, \fBweeks\fR, \fBmonths\fR, or \fByears\fR.
 .PP
 Addition of seconds, minutes and hours is fairly straightforward;
 the given time increment (times sixty for minutes, or 3600 for hours)
 is simply added to the \fItimeVal\fR given
 to the \fBclock add\fR command.  The result is interpreted as
@@ -211,11 +209,12 @@
 Adding and subtracting days and weeks is accomplished by converting
 the given time to a calendar day and time of day in the appropriate
 time zone and locale.  The requisite number of days (weeks are converted
 to days by multiplying by seven) is added to the calendar day, and
 the date and time are then converted back to a count of seconds from
-the epoch time.
+the epoch time.  The \fBweekdays\fR keyword is similar to \fBdays\fR,
+with the only difference that weekends are skipped.
 .PP
 Adding and subtracting a given number of days across the point that
 the time changes at the start or end of summer time (Daylight Saving Time)
 results in the \fIsame local time\fR on the day in question.  For
 instance, the following code sets the value of \fBx\fR to \fB05:00:00\fR.

Index: library/clock.tcl
==================================================================
--- library/clock.tcl
+++ library/clock.tcl
@@ -4269,11 +4269,11 @@
 	    "wrong \# args: should be\
              \"$cmdName clockval ?number units?...\
              ?-gmt boolean? ?-locale LOCALE? ?-timezone ZONE?\""
     }
     if { [catch { expr {wide($clockval)} } result] } {
-	return -code error $result
+	return -code error "expected integer but got \"$clockval\""
     }
 
     set offsets {}
     set gmt 0
     set locale c
@@ -4308,13 +4308,10 @@
     if { [info exists saw(-gmt)] && [info exists saw(-timezone)] } {
 	return -code error \
 	    -errorcode [list CLOCK gmtWithTimezone] \
 	    "cannot use -gmt and -timezone in same call"
     }
-    if { [catch { expr { wide($clockval) } } result] } {
-	return -code error "expected integer but got \"$clockval\""
-    }
     if { ![string is boolean -strict $gmt] } {
 	return -code error "expected boolean value but got \"$gmt\""
     } elseif { $gmt } {
 	set timezone :GMT
     }
@@ -4346,10 +4343,15 @@
 		}
 		days - day {
 		    set clockval [AddDays $quantity $clockval $timezone \
 			    $changeover]
 		}
+
+		weekdays - weekday {
+		    set clockval [AddWeekDays $quantity $clockval $timezone \
+			    $changeover]
+		}
 
 		hours - hour {
 		    set clockval [expr { 3600 * $quantity + $clockval }]
 		}
 		minutes - minute {
@@ -4448,10 +4450,47 @@
     set date [ConvertLocalToUTC $date[set date {}] $TZData($timezone) \
 		 $changeover]
 
     return [dict get $date seconds]
 }
+
+#----------------------------------------------------------------------
+#
+# AddWeekDays --
+#
+#	Add a given number of week days (skipping Saturdays and Sundays)
+#	to a given clock value in a given time zone.
+#
+# Parameters:
+#	days - Number of days to add (may be negative)
+#	clockval - Seconds since the epoch before the operation
+#	timezone - Time zone in which the operation is to be performed
+#	changeover - Julian Day on which the Gregorian calendar was adopted
+#		     in the target locale.
+#
+# Results:
+#	Returns the new clock value as a number of seconds since the epoch.
+#
+# Side effects:
+#	None.
+#
+#----------------------------------------------------------------------
+proc ::tcl::clock::AddWeekDays { days clockval timezone changeover } {
+
+    set day [format $clockval -format %u]
+
+    set weeks  [expr {$days / 5}]
+    set rdays  [expr {$days % 5}]
+    set toAdd  [expr {7 * $weeks + $rdays}]
+    set resDay [expr {$day + ($toAdd % 7)}]
+    if {$resDay > 5} {
+        incr toAdd 2
+    }
+
+    AddDays $toAdd $clockval $timezone $changeover
+}
+
 
 #----------------------------------------------------------------------
 #
 # AddDays --
 #

Index: tests/clock.test
==================================================================
--- tests/clock.test
+++ tests/clock.test
@@ -34990,10 +34990,14 @@
         -gmt true -locale en_US_roman \
         -format {%J %Ol:%OM:%OS %P}
 } 86399
 # END testcases29
 
+
+# BEGIN testcases30
+
+# Test [clock add]
 test clock-30.1 {clock add years} {
     set t [clock scan 2000-01-01 -format %Y-%m-%d -timezone :UTC]
     set f [clock add $t 1 year -timezone :UTC]
     clock format $f -format %Y-%m-%d -timezone :UTC
 } {2001-01-01}
@@ -35216,10 +35220,17 @@
 	       -timezone EST05:00EDT04:00,M4.1.0/02:00,M10.5.0/02:00]
     set f1 [clock add $t 3600 seconds -timezone EST05:00EDT04:00,M4.1.0/02:00,M10.5.0/02:00]
     set x1 [clock format $f1 -format {%Y-%m-%d %H:%M:%S %z} \
 		-timezone EST05:00EDT04:00,M4.1.0/02:00,M10.5.0/02:00]
 } {2004-10-31 01:00:00 -0500}
+test clock-30.26 {clock add weekdays} {
+    set t [clock scan {2013-11-20}] ;# it's a Wednesday
+    set f1 [clock add $t 3 weekdays]
+    set x1 [clock format $f1 -format {%Y-%m-%d}]
+} {2013-11-6}
+# END testcases30
+
 
 test clock-31.1 {system locale} \
     -constraints win \
     -setup { 
 	namespace eval ::tcl::clock {