The issue here seems to be that the behavior of tzdata (correctly) changes over time. Can all this complexity be avoided by storing the tzdata version in the timestamp itself so it can decoded with the same rules?
I've been thinking about it for a while though - a time zone conversion library that also accepts an additional "tzdata_version" argument.