Here's a falsehood I've seen a bunch of times: the idea that Unix timestamps need to be converted to your local timezone. Unix timestamps are the number of seconds since a specific date in a specific timezone (UTC)! If a user gives you a Unix timestamp and you know they're in the PDT timezone, you should not add or subtract 7 hours of seconds to "convert" the timestamp to UTC! It already is. Similarly, if your client receives a Unix timestamp from your server, you shouldn't modify the Unix timestamp to "convert" it to your user's local timezone. Unix timestamps are always UTC. Your platform's date handling APIs should already offer a way to display a Unix timestamp in the user's timezone or an arbitrary one, and maybe even have a class that represents a Unix timestamp paired up with a specific timezone. At no point should you be doing arithmetic on the Unix timestamp portion to convert it between timezones.
Unix timestamps have no inherent time zone at all.
They are a quantity of seconds (ignoring leap seconds & relativity) since a specific instant. That instant in time happens to conveniently line up with 1970-01-01T00:00 when described in UTC to make things easy for us. But it is equivalently defined as 1969-12-31T16:00-08:00 when described in another time zone. The elapsed quantity of seconds since that instant does not vary depending on how you describe the instant itself.
I think that's a better way of putting it. The main lesson is that there's no operation called "changing the timezone of a Unix timestamp", and any code trying to do that is wrong. A date string is a function of a Unix timestamp and a timezone, and if you need to change the timezone, you need to pass a different timezone parameter, not try to do something to the Unix timestamp part.
I meant that a datetime string is generated from the combination of a Unix timestamp and a timezone together, not that it lossily retains both of those inputs. For example, if I want to show the time of day of an event like "3:12 AM" to the user, then I need both the Unix timestamp of the event (for example, 1558050450579) and their timezone (could be as a UTC offset, like -7) in order to produce "4:47 PM". That's true whenever I'm trying to make a string from a Unix timestamp, regardless of whether the final date/time string explicitly says its timezone.
Alice and Bob both live in England and have planned a conference call at 15:00 on 4-jan.
Now Alice happens to travel, and she is in American on 4-jan. What should here calendar do?
Moreover, Alice also has a recurring event "Workout" every friday at 9:00, what should that shift to? Finally, it turns out Bob is also in America, what time should the conference call be at now?
Finally, for some reason England or America decides to change the DST changeover will now happen on 3-jan.
There is no universal semantics of time that will deal with every case. Certainly 'store UTC and convert to the users's time-zone' is not universal, nor is 'store every timestamp with a time-zone'. The way people perceive of 'do this thing at this time' is very hard to capture. Moreover I'd wager no users would actually fill out time with sufficient detail to deal with this. "What do you mean UTC, time-zone, or local-time" I just wanna work out at 9:00 every day, and meet with Alice at 15:00 in a few days. I thought computers were meant to make things easy".
In your case, you're not doing the specific thing I prohibited. I only meant you should never do arithmetic on a timestamp to try to "convert" it to an equivalent representation of the same instant (as Java 8 defines it) in another timezone. However you're specifically doing arithmetic on the timestamp to calculate a new different instant, which is fine. (Your case isn't that different than the user pressing a "shift this event time by N hours" button.)
However, I saw a good tip once that you should only store timestamps of past events and events that happen at a fixed instant regardless of calendars and wall clocks as Unix timestamps. Timestamps for things like future calendar appointments (that may be affected by future changes in regions' timezone definitions) should be stored as a date and wall clock time and regional timezone, and only converted to a Unix timestamp when it happens. This makes it possible to see the timezone the user intended, let it be changed, and works well even if timezones themselves change before the event happens.
> you should only store timestamps of past events and events that happen at a fixed instant regardless of calendars and wall clocks as Unix timestamps
I think this works more often than not, but it's hardly foolproof or without repercussions. Say, you can imagine Google Calendar having a list of holidays for the US. Say it's New Year's day. You're saying you'd replicate that into 6 epoch timestamps (one per time zone in the US) per year in the past, instead of just storing it as "January 1, 00:00:00, recurring every year"?
This is a trick question - for whole-day events, the best way to handle them is to record the calendar day you want them to happen on, not the timestamps of the start and end of the day in some particular timezone. See what iCal does with DATE versus DATE-TIME (which must be UTC or include TZ): https://tools.ietf.org/html/rfc5545#section-3.3.4
It's not "a bit silly", it's ridiculous. It's one uniform holiday in the entire country, recurring at a particular time on a particular calendar day. That's how it's defined, so that's how you record it. If it gets moved one day then you change the recurrence rule from that point forward. The rule you wan't isn't "turn past timestamps into epoch time", it's "record timestamps with their correct semantics for the situation".
I really agree, especially with "There is no universal semantics that will deal with every case." When I enter a time for an appointment, then travel to a different TZ, but know I'll be home when the meeting occurs, I have to tolerate the Macintosh calendar converting my meeting to the local TZ, then back to my local TZ, which ends up being odd at least, and confusing and annoying when it first happened.
I think it's a common misunderstanding worth bringing up here that probably affects more people than the falsehoods listed in the article. On roughly 3 out of the 4 times I've had a coworker run into a timezone issue (different person each time), their first impulse was to do something like what I described. (I stopped them early most of the times, so maybe they would have figured out it was the wrong way to go about it.)
Unix times show up in a lot of APIs and aren't always explicitly called "Unix times". People just see that at some point there's an integer value representing a timestamp, and the time string displayed to the user is some number of hours off, so they think they need to change that integer.
I've argued this and the issue comes when you try to Target another timezone from your own.
So for example if you're in EST(-5) and need to Target CST(+8) you can't give the Unix time for the other timezone because that value is relative to yours talking about another timezone.