We could guarantee that a transaction stays valid even if it's moved to a later block; how about instead of OP_BLOCKTIME and OP_UNIXTIME, make OP_BLOCKTIME_CHECK and OP_UNIXTIME_CHECK, fusing pushing the time and failing if it's too early together? They could still be skipped over by conditionals, so you can do the complicated realistic stuff, but you couldn't write a script that ever transitioned from valid to invalid with those opcodes.
But I actually think keeping the transaction associated with its block, and determining its validity that way, is better. You could make a receiving address with rules like "may be claimed by A within 72 hours; goes to B otherwise".