Arithmetic operations

Learn how to perform arithmetic operations in CQL.

CQL offers a range of arithmetic operations for manipulating numeric and temporal values. These include simple operations like addition and subtraction and more complex operations involving dates and times.

In this reference, we explore the available operations, showcase practical examples, and provide a comprehensive guide to the syntax and semantics of each operation.

Operations

This is the summary of the available arithmetic operators for quick reference:

OperationDescriptionOperator
MinusNegates a numeric value.-
PlusSignifies a positive number.+
PercentConverts a percentage to a decimal number.%
AdditionAdds two numeric or temporal values together.+ plus
SubtractionSubtracts a numeric or temporal value from another.- minus
MultiplicationMultiplies two numeric values together.* times
DivisionDivides a numeric value by another./ divided by
ModuloCalculates the modulus of a divisionmod modulo
ExponentiationRaises a number to a power.** to power of

In the following sections, we visit each of these operations in detail, including their syntax, semantics, and practical examples.

Minus

The minus operation negates a numeric value. You can use it in scenarios where you need to change the sign of a number from positive to negative or vice versa.

You can use the minus operator by placing a - sign before a numeric value:

-/*<operand>*/
Try in Playground

Here is a practical example:

Plus

The plus operation indicates that a numeric value is positive. You can use it when you want to specify the sign of a number explicitly or convert a value implicitly to a numeric type.

You can use the plus operator by placing a + sign before a numeric value:

+/*<operand>*/
Try in Playground

Here is a practical example:

Note that, since it was already a number, the operation had no effect except to indicate the number's sign.

Percent

The percent operation converts a number from percentage to decimal format by dividing it by 100.

To use the percent operator, place a % sign after a number, variable, or expression:

/*<operand>*/%
Try in Playground

Here is a practical example:

Addition

The addition operation adds two operands together, either numeric or temporal values, and returns the sum.

To use the addition operation, place a + sign between two numeric values:

/*<operand>*/ + /*<operand>*/
Try in Playground

Alternatively, for a more natural language feel, you can write it as follows:

/*<operand>*/ plus /*<operand>*/
Try in Playground

Here is a practical example:

For temporal values, the addition operation allows you to perform calculations involving dates, times, and durations:

today + 1 day
Try in Playground

The example above adds one day to the current date, resulting in the date of tomorrow. And you can also chain multiple operations together to perform more complex calculations:

today + 1 month + 1 week
Try in Playground

Because the addition operation is commutative, the order of the operands does not matter. This is confirmed by the expression below:

1 day + today is equal to today + 1 day
Try in Playground

Note that the addition operation does not automatically convert temporal values. Be sure to use the cast modifier to convert a value to a date or time before adding it to another value, as shown below:

"2021-01-01" as date + 1 day
Try in Playground

Subtraction

The subtraction operation calculates the difference between two numeric or temporal operands and returns the difference.

To use the subtraction operation, place a - sign between two numeric values:

/*<operand>*/ - /*<operand>*/
Try in Playground

Alternatively, for a more natural language feel, you can write it as follows:

/*<operand>*/ minus /*<operand>*/
Try in Playground

Here is a practical example:

For temporal values, the subtraction operation allows you to perform calculations involving dates, times, and durations:

today - 1 day
Try in Playground

The above example subtracts one day from the current date, resulting in the date of yesterday. You can chain multiple operations together to perform more complex calculations:

today - 1 month - 1 week
Try in Playground

In contrast to addition, subtraction is not commutative. This means that you cannot subtract a date from a period of time, but you can subtract a period of time from a date. For example, today - 1 day works, but not 1 day - today.

Finally, note that the subtraction operation does not perform any automatic conversions for temporal values. Be sure to use the cast modifier to convert a value to a date or time before subtracting it from another value, as shown below:

"2021-01-01" as date - 1 day
Try in Playground

Multiplication

The multiplication operation multiplies two numeric values and returns the product.

To use the multiplication operator, place a * sign between two numeric values:

/*<operand>*/ * /*<operand>*/
Try in Playground

For a more natural reading, you can alternatively write:

/*<operand>*/ times /*<operand>*/
Try in Playground

Here is a practical example:

Because the multiplication operation is commutative, the order of the operands does not matter. This is confirmed by the expression below:

2 * 3 is equal to 3 * 2
Try in Playground

Note that multiplication has higher precedence than addition and subtraction. This means that multiplication is performed before those operations, as shown below:

2 + 3 * 4 // 14, not 20
Try in Playground

Division

The division operation divides one numeric value by another and returns the quotient.

To use the division operator, place a / sign between two numeric values:

/*<operand>*/ / /*<operand>*/
Try in Playground

For a more natural reading, you can alternatively write:

/*<operand>*/ divided by /*<operand>*/
Try in Playground

Here is a practical example:

Note that division has the same precedence as multiplication, which is higher than addition and subtraction. This means that division is performed before those operations, as shown below:

2 + 6 / 2 // 5, not 4
Try in Playground

Modulo

The modulo operation calculates the modulus of a division, which is the rest of the division that cannot be expressed as an exact multiple of the divisor.

To use the modulo operator, place the mod keyword between two numeric values:

/*<operand>*/ mod /*<operand>*/
Try in Playground

You can also use the full name of the operation if you prefer:

/*<operand>*/ modulo /*<operand>*/
Try in Playground

Here is a practical example:

7 mod 3 // 1
Try in Playground

In the above example, the number 7 cannot be completely divided by 3, and there is a remainder of 1.

It is important to emphasize that modulo calculates the modulus and not the remainder. Although they may appear to be the same in many cases, there is a difference when dealing with negative numbers.

Imagine a scenario where you are dividing -7 by 3:

  • The remainder would be -1, as this is the difference between -7 and -6, which is the nearest multiple of 3 that is less than -7.
  • The modulus would be 2, as this is the difference between -7 and -9, which is the nearest multiple of 3 that is greater than -7.

Since CQL uses the modulus definition, the result of the above operation is 2.

Exponentiation

The exponentiation operation raises a number to a power and returns the result.

To use the exponentiation operator, place a ** sign between two numeric values:

/*<operand>*/ ** /*<operand>*/
Try in Playground

For a more natural reading, you can alternatively write:

/*<operand>*/ to power of /*<operand>*/
Try in Playground

Here is a practical example:

Note that exponentiation has higher precedence than multiplication, division, addition, and subtraction. This means that exponentiation is performed before those operations, as shown below:

2 + 3 ** 2 // 11, not 25
Try in Playground

Also, note that exponentiation has different associativity than the other arithmetic operations. This means that exponentiation is performed from right to left, as shown below:

2 ** 3 ** 2 // 512, not 64
Try in Playground

General aspects

This section delves into the general aspects of arithmetic operations in CQL, highlighting the subtle differences in their behavior across various scenarios.

Numeric arithmetic

The following sections discuss the behavior of arithmetic operations when working with numeric values.

Numeric conversion

For your convenience, all numeric operations automatically convert non-numeric values to numbers whenever possible.

For example, consider the following operation:

Without type conversion, you would have to handle this case manually, which would make your queries more verbose and less readable.

Note that automatic conversions are only applied in a limited number of cases. This is one of the reasons why there is no such thing as a not-a-number value (NaN) in CQL. Whenever a value cannot be converted to a number, the operation simply fails.

For more information, see number conversion.

Type generalization

For operations involving multiple numeric operands, CQL automatically converts the values to a common type before performing the calculation. This process is called generalization, and consists of converting all operands to the most specific type that can represent them all.

Here is how generalization works in a nutshell:

  • If some of the operands are floats, the result is a float.
  • If some of the operands are decimals, the result is a decimal.
  • If all the operands are integers, the result is an integer.

Therefore, if you add a float and a decimal, the result is a float. This is because floats can represent all decimals but not vice versa. Similarly, if you add an integer and a decimal, the result is a decimal.

Overflow handling

Arithmetic operations can sometimes result in a value that exceeds the maximum or minimum representable value. This is called an overflow.

Float and decimal values have no upper or lower limits but maximum precision. This means that the result of an operation may not be accurate enough to represent the exact value, but the operation will not fail.

However, when working with integers, the behavior is slightly different. If the result is outside the valid range, it is approximated to the nearest float. This is a compromise to ensure that you still get a result, even if it is less accurate.

Temporal arithmetic

The following sections discuss the behavior of arithmetic operations when working with temporal values.

Operation chaining

When performing arithmetic operations on temporal values, you can add multiple time spans sequentially, as long as the left side of the operation is a date-time value.

This works because addition and subtraction operations are left-associative, which means that the leftmost operand is evaluated first, and then the result is used as the left operand for the next operation, and so on.

For example, the following expression is perfectly valid:

today + 2 days + 1 month
Try in Playground

The leftmost sub-expression today + 2 days is evaluated first, resulting in a new date. Finally, the second sub-expression + 1 month is evaluated, yielding the final result. As you can see, the time spans are never combined.

It becomes clearer when we add parentheses to the expression:

(today + 2 days) + 1 month
Try in Playground

In contrast, the following expression is invalid:

2 days + 1 month + today // 🚨 Invalid
Try in Playground

If this expression were allowed, it would first add the time spans together, resulting in a combined period that is then added to the date. However, this could be misleading because it may not produce the same result as the previous example.

To see how this can lead to unexpected results, consider the following example:

today + 1 month + 2 days
Try in Playground

The number of days per month varies, and daylight saving time can also affect the calculation of dates. As a result, the final date may differ depending on the order in which you add days and months.

For example, let's say today is August 30. If you add a month to this date first, you will end up with September 30. If you then add two more days, the date becomes October 2.

However, if you switch the order and first add two days to August 30, you will get September 1. Then, if you add a month to that date, you get October 1.

So, when chaining units together, make sure to consider the order in which they are combined and how this may affect the result.

Overflow handling

Temporal values, such as dates and times, have upper and lower limits that define the range of possible values.

The following table shows the valid range for each temporal type:

TypeMinimum valueMaximum value
Time00:00:0023:59:59
Date-999999999-01-01999999999-12-31
Date time-999999999-01-01T00:00:00999999999-12-31T23:59:59

It is unlikely that you will ever need to worry about these limits. However, be aware that any operation that results in a value outside this range will fail.