How are past transactions validated (when there have been softforks)? Let's say I run a bitcoin client for the first time. It downloads a copy of the blockchain from the very beginning and starts validating all the transactions included in all the blocks. 

Since there have been some softforks during Bitcoin's timelife, how does the client know which validation rules needs to apply to validate each transaction?

Even if there are some checkpoints so that there is no need to validate the whole blockchain, how does the client handle different rules for different transactions?

Are there different sets of rules included in the source code, together with block heights indicating when they should be used?
Four methods have been used to decide whether a softfork should apply:


The softfork applies to all blocks, past and future.
Example: The softfork to remove the integer overflow bug.
The softfork applies to all blocks with a timestamp after a flag day.
Example: The initial form of BIP30 was applied to all blocks with a timestamp later than 1331769600. (March 15, 2012, 00:00 UTC)
The softfork applies to all blocks except some grandfathered-in blocks.
Example: The current form of BIP30 is applied to all blocks, except two that violate it.
The softfork applies to all blocks created after a successful miner vote. A Bitcoin client can determine if a softfork applies purely by looking at the blockchain.
Example: BIP34, which required block height to be placed in the coinbase in all new blocks.