From the bitcoin wiki:
The stacks hold byte vectors. When used as numbers, byte vectors are interpreted as little-endian variable-length integers with the most significant bit determining the sign of the integer. Thus 0x81 represents -1. 0x80 is another representation of zero (so called negative 0). Positive 0 is represented by a null-length vector. Byte vectors are interpreted as Booleans where False is represented by any representation of zero, and True is represented by any representation of non-zero.
What this doesn't say is how more than one byte is combined into an integer. For example, to represent the integer 278, the stack would have:
And to represent the integer -278:
The most significant byte (0x01) was just XORed with (0x80) to change the sign to negative.
Now that we know how script integers are encoded, we just have to understand how they are interpreted. This is shown in the BIP65 code:
// There are two types of nLockTime: lock-by-blockheight
// and lock-by-blocktime, distinguished by whether
// nLockTime < LOCKTIME_THRESHOLD.
// We want to compare apples to apples, so fail the script
// unless the type of nLockTime being tested is the same as
// the nLockTime in the transaction.
(txTo.nLockTime < LOCKTIME_THRESHOLD && nLockTime < LOCKTIME_THRESHOLD) ||
(txTo.nLockTime >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD)
LOCKTIME_THRESHOLD is the UTC time:
LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC
So, basically, you can set the time that OP_CLTV will verify against in the scriptPubKey. If it is below
LOCKTIME_THRESHOLD, then it is compared based on block number of the block containing the transaction. If it is above
LOCKTIME_THRESHOLD, then it is compared based on block time of the block containing the transaction. Note that this relies on the consensus rule that transactions cannot be included into a block with a lock-time (
nLockTime) in the future.