** Summary ** '''expr''' - Evaluate an expression ** Synopsis ** '''expr''' ''arg'' ?''arg arg ...''? [http://www.tcl.tk/man/tcl/TclCmd/expr.htm%|%officieal reference]: [http://www.tcl.tk/man/tcl/TclCmd/expr.htm%|%man page, 8.4]: [http://www.tcl.tk/man/tcl/TclCmd/mathfunc.htm%|%mathfunc man page]: [http://www.tcl.tk/man/tcl/TclCmd/mathop.htm%|%mathop man page]: [tcl_precision]: `expr` [concat%|%concatentates] its arguments, evaluates this result as a Tcl `[[expr]` implements a mini language that has a syntax separate from the Tcl syntax. It supports some of the same constructs as Tcl, such as variable substitution, command substitution, and braces. It adds additional syntax for mathematical operators and functions, and unlike Tcl, does not accept character strings that are not enclosed in double quotes or brackets. `expr` implements a [little language] that has a syntax separate from [Tcl]. `[[expr]` conditions (e.g. `[[[if]]` or `[[[while]]`) take 0 to mean false and all other numbers to mean true. In addition, the following string constants can be used: A value recognized as boolean by `[string is] boolean...` can be used directly, * true, on, yes * false, off, no Functions take the form, Any of these values may be abbreviated, and upper-case spellings are also acceptable. See the [http://www.tcl.tk/man/tcl/TclLib/GetInt.htm%|%Tcl_GetBoolean man page] : ''name''`(`''argument?'') Beware that if you need code to run in Tcl releases as old as 8.3, you have to quote these if you use them directly as constants, as [Donald Porter] noted: ''[[expr]] tries to interpret "bare" strings as function names, such as cos($x). You must quote the string "true". Then it behaves as you expect in 8.3.3.'' : ''name''`(`''argument''`,`''argument ...'')` Refer to the Operands section of the [http://www.tcl.tk/man/tcl8.4/TclCmd/expr.htm#M5%|%expr man page%|%] for the syntax rules. ====== '''expr''' [concat]enates each ''arg'' (adding separator spaces between them), evaluates the result as a [Tcl] expression, and returns the value. The operators permitted in Tcl expressions include most of the operators permitted in [C] expressions and a few aditional ones, and they have the same meaning and precedence as the corresponding C operators. Expressions almost always yield numeric results (integer or floating-point values). For example, the expression: set val1 8.2 set val2 6 expr {$val1 + $val2} expr {$val1} + ${val2} evaluates to 14.2. ====== This is an equivalent way of writing the previous [[expr]] command: In most cases, it's best to [Brace your Expr-essions%|%brace] or otherwise expr {$val1+$val2} ====== This allows `expr` to do the interpretation, rather than having Tcl interpret Any argument that can be interpreted in some way, e.g., variable or a command expansion, should be enclosed in brackets. This allows the [[expr]] command to do the interpretation, rather than having the caller interpret the arguments before handing them off to [[expr]]. See below for more details. `expr` expressions differ from [C] expressions in the way that operands are [Tcl] expressions differ from C expressions in the way that operands are specified. They also include some non-numeric operators for strings (comparison) and lists (membership). Since Tcl 8.5, many operators have command-equivalents in the In spite of the name '''mathop''', some of the operators are string-oriented, rather Note that many operators have command-equivalents in the [namespace] '''::[tcl::mathop]''' from Tcl 8.5 onwards. The following is a chart of operators, in order of precedence (tightest-binding [[The term '''mathop''' is a misnomer, since some of the operators included in this namespace are string, rather than math, oriented...]] &| [-] [+] [~] [!] | Unary operators; specifically a negation operation, a non-negation operation, a bit-wise NOT operation (every bit in the input value gets replaced by its inverse) and a logical NOT operation (non-zero maps to zero, and zero maps to one). |& The '''expr''' operators, in order of precedence (tightest-binding to least-tight binding), are: &| [-] [+] [~] [!] | Unary operators; specifically a negation operation, a non-negation operation (I see little point in this one), a bit-wise NOT operation (every bit in the input value gets replaced by its inverse) and a logical NOT operation (non-zero maps to zero, and zero maps to one.) |& &| [+] [-] | Addition and subtraction. |& &| [<<] [>>] | Left and right shift. Equivalent to multiplying or dividing by a suitable power of two, and then reducing the result to the range representable in an integer on the host platform. |& &| [<] [>] [<=] [>=] | Ordering relations: less than, greater than, less than or equal, greater than or equal. These operations work on strings as well as numbers, but where string comparison is intended, it is advisable to use the dedicated string comparison operators or [string compare] or [string equal] instead, as those are more predictable in the case of a string that looks like a number. For example, [string equal] considers "6" and "06" to be different strings, but the `expr`' operator `==` considers them to be equivalent numbers.|& &| [<] [>] [<=] [>=] | Ordering relations (less than, greater than, less than or equal, greater than or equal.) Note that these operations work on strings as well as numbers, but you are probably better off testing the result of [string compare] instead as that is more predictable in the case of a string that looks like a number. |& &| [==] [!=] | Equality and inequality. Note that these operations work on strings as well as numbers, but you are probably better off testing the result of [string equal] instead as that is more predictable in the case of a string that looks like a number. For example, [string equal] considers "6" and "06" to be different strings, but expr's == considers them to be equivalent numbers. |& &| [eq] [ne] | (2004-07-08 added): From Tcl 8.4 on. The same as before, but arguments only strings. Will find "6" and "06" (as well as 1 and 1.0) to be different. |& &| [**] | exponential. From Tcl 8.5 on |& &| [in] [ni] | Item (argument 1) in/not in list (argument 2). New in Tcl 8.5 |& &| [^] | Bit-wise exclusive OR. A bit is set in the result when the corresponding bit is set in ''precisely one'' of the arguments. |& &| [<>] | Bit-wise OR. A bit is set in the result when the corresponding bit is set in either of the arguments. |& &| [&&] | Logical AND. The result is `1` when both of the arguments true. and `0` otherwise. This operation is a ''short-circuiting'' operation, and will only evaluate its second argument when the first argument is non-zero. This includes the expansion of Tcl commands in square brackets. Where Tcl seems not to be behaving as describe here, see [double substitution]. |& &| [&&] | Logical AND. The result is a one (true) when both of the arguments are non-zero (true), and zero (false) otherwise. Note that this operation is a ''short-circuiting'' operation, and will only evaluate its second argument when the first argument is non-zero. This includes the expansion of Tcl commands in square brackets, but this delay in evaluation only occurs if the whole expression is enclosed in curly braces. |& &| [<><>] | Logical OR. The result is a zero (false) when both of the arguments are zero (false), and one (true) otherwise. Note that this operation is a ''short-circuiting'' operation, and will only evaluate its second argument when the first argument is zero. This includes the expansion of Tcl commands in square brackets, but this delay in evaluation only occurs if the whole expression is enclosed in curly braces. |& &| x'''?'''y''':'''z | If-then-else, as in C (where x,y,z are expressions). If the value x is non-zero (true) then the expression y is evaluated to produce the result, and otherwise the expression z is evaluated to produce the result. Note that this operation is a ''short-circuiting'' operation, and will not evaluate expression y if x is zero (false) and will not evaluate expression z if x is non-zero (true). This includes the expansion of Tcl commands in square brackets, but this delay in evaluation only occurs if the whole expression is enclosed in curly braces. It is usually clearer and easier to maintain (and no slower - the generated bytecode is identical) to use the Tcl [if] command instead of this. |& See the [http://www.tcl.tk/man/tcl/TclCmd/mathfunc.htm%|%mathfunc man page]. See the mathfunc man page, listed above, for the Tcl 8.5 man page information on '''expr''' builtin functions. The following is a list of builtin functions: *** BUILTIN FUNCTIONS *** '''[abs]'''(x): Absolute value (negate if negative). '''[abs]'''(x): Absolute value (negate if negative.) '''[acos]'''(x): Inverse cosine (result in radians.) '''[asin]'''(x): Inverse sine (result in radians.) '''[atan]'''(x): Inverse tangent (result in radians.) '''[atan2]'''(y,x): Inverse tangent. Can handle cases which plain atan() can't (due to division by zero) and has a larger output range (result in radians.) '''[bool]'''(x): Accept any numeric value or string (acceptable to [string] is boolean), and return the corresponding boolean value 0 or 1 '''[cos]'''(x): Cosine (input in radians.) '''[cosh]'''(x): Hyperbolic cosine. '''[entier]'''(x): Take any numeric value and return the integer part of the argument, as an unlimited value string '''[exp]'''(x): Exponential function. Returns e**inputValue (using the FORTRAN-style notation) where e is the base of natural logarithms. '''[floor]'''(x): Floor (defined over floating point numbers.) If the input value is not a whole number, return the next ''smaller'' whole number. '''Surprise''': The return value is a float, not an integer. '''[fmod]'''(x, y): Floating point remainder of x divided by y. '''[hypot]'''(x,y): Hypotenuse calculator. If the projection of a straight line segment onto the X axis is x units long, and the projection of that line segment onto the Y axis is y units long, then the line segment is hypot(x,y) units long (assuming boring old Euclidean geometry.) Equivalent to sqrt(x*x+y*y). '''[int]'''(x): Convert number to integer by truncation. '''[isqrt]'''(x): Compute the integer part of the square root of x. '''[max]'''(x,...): Return the one argument with the greatest value '''[min]'''(x,...): Return the one argument with the least value '''[pow]'''(x,y): Power function. In FORTRAN notation, x[**]y. '''[sin]'''(x): Sine (input in radians.) '''[sqrt]'''(x): Square root (well, the positive square root only. And Tcl doesn't do complex math, so the input had better be positive...) ** Mathematical Expressions ** Simple addition: ====== set a [expr {1 + 2}] ====== mathematical functions ====== set a [expr {sqrt(4)}] ====== [martin Lemburg]: The following returns `1` because `" 2 "` will be interpreted [martin Lemburg]: The following returns 1 because [[expr]] " 2 " will be converted to 2: ====== set a [expr {" 2 " == [string trim " 2 "]}] ====== To ensure that expression evaluates to a floating point number, use `double()` To ensure that expression evaluates to a floating point number, use an [[expr]] like ''double()'': ====== set a 1 set b 2 expr {double($a)/$b} ====== or, to get an integer: ====== expr {entier($a/$b)} ====== `int()` would also have worked, but `entier()` is more general ** Order of Precedence ** The following returns returns 4, rather than -4 as some might expect: ====== set a [expr {-2**2}] ====== The following returns `1` because `2==2` is evaluated first: returns 1 because 2==2 is evaluated first set a [expr {5&2==2}] ====== [AMG]: The order of bitwise operations (`|`, `&`, and `^`) may seem totally bogus, but it's inherited from [C], which in turn inherited it from an early prototype version of C which lacked separate logical operators (`&&` and `||`) [http://cm.bell-labs.com/who/dmr/chist.html]. I wouldn't cry if a new language (not Tcl) decided to break compatibility with C in this respect. ** String Operands ** `[[[expr]]` tries to interpret operands as numeric values, but it does not try to recognize complete numeric epressons in individual values, so a value "2*3" will be interpreted as a string: ====== set y 2*3; expr {$y} ;# ==> 2*3 set y 2*3; puts [expr {$y}] ;# ==> 2*3 set y 2*3; puts [expr {$y+0}] ;# ==> can't use non-numeric string as operand of "+" To pass a complete expression stored in a variable, omit the braces so that Tcl ====== `expr` implements a little language distinct from the language described in [dodekalogue%|%the rules of Tcl]. One `[[[expr]]` implements a little language distinct from standard Tcl. One difference is that `[[[expr]]` requires strings to be quoted: ======none % if {joe eq mike} {puts wow} syntax error in expression "joe eq mike": variable references require preceding $ % if {"joe" eq "mike"} {puts wow} % if {"joe" eq "mike"} {puts "wow"} % if {{joe} eq {mike}} {puts {wow}} % To insert a literal value when templating an expression, use an [identity If `[[[expr]]` syntax was the same as Tcl syntax, a Tcl ''bareword'' string would be accepted, but it is not. ====== % puts wow wow % set a abc abc % ====== If you prefer consistency, then always quote strings, but note that at some point `[[[expr]]` may grow the feature of accepting bareword strings. If the return value of `expr` is numeric, it is transformed into a canonical If the value of an `[[[expr]]` is numeric, it will transformed into a canonical ====== set val 0x10 puts $val ;# 0x10 set val [expr {$val}] puts $val ;# 16 ====== ====== puts [expr {[join {0 x 1 0} {}]}] ;# 16 ====== In other words, `expr` may mutate strings that can be interpreted as In other words, `[[[expr]]` may mutate strings that can be interpreted as numbers, which is a potential gotcha for the programmer using string functions of `[[[expr]]` while not considering that they may have a numeric `expr` uses floating point arithmetic, so strings representing decimal `[[[expr]]` uses floating point arithmetic, so strings representing decimal to a close-enough representation. In the following example, `36.37` gets a to a close-enough floating-point representation. In the following example, "36.37" gets a floating-point representation that approaches 36.37: ====== expr {int(36.37*100)} ====== If that value is subsequently used as a string, it becomes necessary to somehow convert it. Over the years, the default string conversion has varied. For Tcl version 8.5.13, it looks like ======none 3636.9999999999995 ====== [RS] points out that version 8.4.9 provided the following results, and that that braced or not, `expr` returns the same (string rep of) double as well that braced or not, `[[[expr]]` returns the same (string rep of) double as well issue of floating-point to string conversion. ======none % expr 36.37*100 3637.0 ;#-- good enough... % expr {36.37*100} 3637.0 ;#-- the same % expr {int(36.37*100)} 3636 ;#-- Hmm % expr int(36.37*100) 3636 ;#-- the same % info pa 8.4.9 ====== One way to get `3637` would be to use `round()`: One way to get "3637" would be to use `round()`: ====== expr {round(36.37*100)} ====== `[format]` can also be useful, but the main point is to remain The `[[[format]]` command can also be useful, but the main point is to remain [LV]: My response on [comp.lang.tcl] was that I thought it was a shame that `expr` (or perhaps it is Tcl) didn't use the same mechanism for that `[[[expr]]` (or perhaps it is Tcl) didn't use the same mechanism for be consistent. Even if they were consistently '''wrong''', one would be able to at least to live within the ''law of least surprise''. As it is, until one experiments, one won't know which way that Tcl is going to ''round'' results. [EPSJ]: This may be a side effect of the IEEE floating point standard. This is done in hardware to guarantee the convergence in the case of a series of math algorithms. The rule is that the mantissa of a floating point number must be rounded to the nearest even number. As 36.37 cannot be represented exactly in float point it ends up being a small fraction below the intended number. On the other side 36.38 moves on the other direction. Look the following result: ======none () 60 % expr int(36.380*100) 3638 () 61 % expr int(36.370*100) 3636 ====== x86 floating point hardware allows this to be configurable to nearest even, nearest odd, and a few more options. But usually nearest even is the default. The result may seem inconsistent, but it is intentional. ** pow() vs ** ** pow() vs ** ** [LES] 2005-07-23: ======none % expr pow(5,6) 15625.0 % expr 5**6 15625 ====== Two syntaxes, two slightly different results. Is that intentional? [RS]: Yes. While `pow()` always goes for double logarithms, `**` tries to do integer exponentiation where possible. ** Precision ** [davou]: What is the precision of functions in `expr`, and how can it be [davou]: What is the precision of expr's functions, and how can it be expanded upon? [Lars H]: That's generally determined by the [C] library functions that implement them. It depends on where (and against what) Tcl is compiled. For implement them. It depends on where (and against what) Tcl is compiled. For "real" numbers that means '''double'''s, which are floating-point numbers of typically about 17 decimal digits precision (but how many of these are correct varies between functions and platforms). For integers Tcl has traditionally used '''long'''s, which in most cases means 32-bit two's complement integers ($tcl_platform(wordSize) tells you the actual number of bytes), but as of Tcl 8.5 it supports (almost) arbitrarily large integers ([googol magnitude] is no problem anymore, whereas googolplex magnitude wouldn't fit in the computer memory anyway). As for extending what the core provides, [tcllib] provides math::bignum and [math::bigfloat]. ** [Nan] and [Inf] ** At least as of Tcl 8.5, [NaN] and [Inf] are potential values returning from `expr`. expr. [Philip Smolen] I've never seen expr return NaN. I wish it would! ====== ** Interactions with [locale] ** ** Interactions with `[locale]` ** `[[[expr]]`'s parsing of decimals may be hampered by [locale] - you might get `expr` concatenates its arguments into an expression. Consider the following `[[[expr]]` resolves variables in the context of its caller, and each variable value becomes exactly one operand in the expression. Consider the following: ====== expr 5 > {} ;# -> missing operand at _@_ set color2 green expr {$color1} eq {$color2} ;# 1 Concatenated, the arguments form the script, `green eq green`, in which the two But if the arguments are not bracketed, there is an error in the expression syntax: Another example illustrating the same point: ====== #wrong expr $color1 eq $color2 ====== ======none invalid bareword "green" in expression "green eq green"; should be "$green" or "{green}" or "green(...)" or ... ====== This is because in `[[[expr]]` syntax, strings should be quoted or bracketed ====== ======none set a "abc" expr $a in $b # invalid bareword "abc" # in expression "abc in 123 abcd xyz lmnop"; # should be "$abc" or "{abc}" or "abc(...)" or ... expr {$a in $b} ;#-> 0 expr {$a in $b} # 0 expr {$a ni $b} ;#-> 1 expr {$a ni $b} # 1 ====== % expr $a == "foo" ? true : false % expr {$a eq "foo" ? true : false} % expr {$a == "foo" ? true : false} ====== When exactly one unconcatenated value is passed to `expr`, the argument can be In addition, `[[[expr]]` is usually much more performant when its non-literal arguments are braced, since this allows byte-compilation. '''Fast:''' ====== [AMG]: The security problems of unbraced `expr`essions are very similar to [AMG]: The security problems of unbraced [expr] expressions are very similar to [SQL] injection attacks. Notice how [sqlite]'s [Tcl] binding does its own this problem as well because the default is to apply multiple passes of interpretation. See also [double substitution]. input: ====== #DON'T EXECUTE THIS SCRIPT!!! set x {[exec format C:\\]} set j {[puts Sucker!]} #C:\ get formatted in the next command set k [expr $x / $j.] ====== On the other hand, ====== set k [expr { $x / double($j) }] ====== gives a much more reasonable result: ======none argument to math function didn't have numeric value while executing "expr { $x / double($y) }" invoked from within "set k [expr { $x / double($y) }] " (file "foo.tcl" line 3) ====== ** The "Dot" Trick for Unbraced Expressions ** Unless you know exactly what you are doing, unbraced expressions are not recommended. Nevertheles... With unbraced expressions, `.` (`\x2e`) can be appended to a variable to get `expr` With unbraced expressions, a "." can be appended to a variable to get [[expr]] to interpret the value as a float, but the ''double()'' function is a better alternative: ====== set x 1; set j 2 # works (but don't do this) expr $x/$j. #an accepted way to do it expr {double($x)/$j} # error: syntax error in expression "$x/$j." (expr parser) expr {$x/$j.} ====== It's faster, too: ====== set script1 { set x 1 set j 2 set k [expr $x / $j.] } set script2 { set x 1 set j 2 set k [expr { $x / double($j) }] } foreach v {script1 script2} { foreach v { script1 script2 } { } #script1: 38 microseconds per iteration #script2: 9 microseconds per iteration #[pyk] 2012-11-28: what a difference a few years makes (an "old" 3.06Ghz Intel Core 2 Duo): #script1: 4.4767364 microseconds per iteration #script2: 0.7374299 microseconds per iteration ====== ---- [RS]: This was just to demonstrate the differences between the regular Tcl parser and the parser for `expr`', not recommended practice. Another example is parser and ''expr'''s parser, not recommended practice. Another example is ====== set op + set op "+" 9 expr {4 $op 5} syntax error in expression "4 $op 5" ====== See the [for] page on a case where that helped. See the `[for]` page on a case where that helped. ** Bytecode compilation and performance ** In [http://groups.google.com/group/comp.lang.tcl/browse_thread/thread/f873d6fab9f0e304%|%Embedded vs. separate commands], 1992-12-38, [JO] published the voting results 37:8 in favor of embedded functions() vs. separate [[commands]] On 1992-12-28 [JO] published the voting results 37 : 8 in favor of embedded functions() vs. separate [[commands]] - [http://groups.google.com/groups?q=group:comp.lang.tcl+author:ousterhout&start=900&hl=de&lr=&newwindow=1&scoring=d&selm=1hn9tvINNqod%40agate.berkeley.edu&rnum=922] ** (Tcl 8.4 and older) 32-bit integer limitations ** ** Dustbin ** Addition '''(Outdated) Expr [Gotchas]''' ======none % expr (1<<31)-1 2147483647 % expr 2147483647 + 2147483647 -2 ====== Multiplication ======none % expr sqrt((1<<31)-1) 46340.9500011 expr 46341*46341 -2147479015 ====== These are results of Tcl 8.4 and older versions using a 32-bit representation for integers. for integers. Check out [http://www.tcl.tk/cgi-bin/tct/tip/237.html%|%TIP #237] , an implemented [TIP] describing arbitrary-precision Integers for Tcl. This is available in Tcl 8.5. Tcl 8.5 features abritrary-precision integers. See ** See Also ** [A little math language]: adds features & sugar to expr [A real problem]: [Additional math functions]: [Arbitrary precision math procedures]: [Brace your expr-essions]: [compute]: more sugar for expr [Converting numbers from arbitrary bases]: [DebuggingExprCalls]: [rwm] sometimes it is difficult to debug expr calls where the operands are variables. [DebuggingExprCalls] explains how to wrap expr to help with these cases. [double substitution]: [expr problems with int]: limits of number representation (both integer and float) inherited from C [for]: [How can I do math in Tcl]: [if]: [Importing expr functions]: use expr's functions without explicitly calling that, see [Importing expr functions]. [Math function help]: [Modeling COND with expr]: Braced expressions can span several lines [Numerical Analysis in Tcl]: [Sample Math Programs]: extremely simple math examples [Tcl help]: TIP #123 [http://tip.tcl.tk/123]: Adding an Exponentiation Operator to the expr Command TIP #174 [http://tip.tcl.tk/174]: [Math Operators as Commands] TIP #182 [http://tip.tcl.tk/182]: Add 'expr bool' Math Function TIP #201 [http://tip.tcl.tk/201]: Add 'in' Operator to expr TIP #232 [http://tip.tcl.tk/232]: Creating New Math Functions for the 'expr' Command ([tcl::mathfunc]) TIP #237 [http://tip.tcl.tk/237]: Arbitrary-Precision Integers for Tcl [while]: ** Half-Bakery ** [RS] suggests expr's arguments could be reparsed so that full mathematical [RS] 2003-04-24: Here's a tiny wrapper for friends of infix assignment: ======none proc let {var = args} { uplevel 1 set $var \[expr $args\] } ;#RS ====== ======none % let i = 1 1 % let j = $i + 1 2 % let k = {$i + $j} 3 ====== ====== set y 2*3; puts [expr $y+0] ;# ==> 6 ====== [AM]: The problem with variables whose values are actually expressions is that they change the whole expression in which they are used. The performance gain for caching the parsed expression will then be lost. [AMG]: This reopens the door to all the security, performance, and correctness problems solved by bracing one's expressions. ** Discussion ** [Wookie]: I had some trouble recently using `expr` to calculate time [Wookie]: I had some trouble recently using expr to calculate time offsets. I had 2 time stamps in the form hh:mm So I had 4 variables h1, m1, h2, m2 and one of my `expr` functions was So I had 4 variables h1, m1, h2, m2 and one of my expr functions was ====== set result [expr {$m1 + $m2}] ====== As many of you may be thinking, you fool! what about 08 and 09, which will get treated as invalid octal. So after some grumbling I thought okay so I have to trimleft them. Bit verbose but who cares: ====== set m1 [string trimleft $m1 0] set m2 [string trimleft $m2 0] set result [expr ($m1 + $m2)] ====== Now what could possibly go wrong with that... well obviously 00 becomes the empty string, which causes unexpected closed parameter in the `expr`ession. empty string, which causes unexpected closed parameter in the expr. So now I have to check for the empty string. So... ====== set m1 [string trimleft $m1 0] if {$m1=={}} {set m1 0} set m2 [string trimleft $m2 0] if {$m2=={}} {set m2 0} set result [expr {$m1 + $m2}] ====== ... and then repeat it for the hours. It all seemed very clumsy. So I came up with this, which may solve many of the conversion issues in this section. ====== scan "$h1:$m1 $h2:$m2" "%d:%d %d:%d" h1 m1 h2 m2 set result [expr {$m1 + $m2}] ====== All the conversions to int have been done and leading 0's have been stripped and returns 0 if the value is all 0s. This works for float and probably double (though I've not tried). Can anyone see any problems with this approach? [glennj]: No, `[scan]` is definitely the way to parse numbers out of dates [glennj]: No, [scan] is definitely the way to parse numbers out of dates and times. However, for date arithmetic, nothing beats [clock]. ====== # adding a delta to a time set h1 12; set m1 45 set h2 3; set m2 30 clock format [clock add [clock scan "$h1:$m1" -format "%H:%M"] $h2 hours $m2 minutes] -format %T ;# ==> 16:15:00 ====== What are you trying to do with your two times?