It's time :clock10: for us to finally add proper timezone support to Ghost. The original main issue for this (with a great deal of discussion) is here: https://github.com/TryGhost/Ghost/issues/1265.
Other related issues which may or may not be helpful:
The problem we face with timezones revolves almost entirely around published dates.
Take the following scenario:
This gets more confusing when post scheduling comes into play. Take the example of a San Fran startup blog. They like to publish posts at lunchtime for their readership which is mostly also in San Fran. They hire a writer in Singapore, who is in UTC+8.
There are two underlying problems here:
1) There's no way to tell Ghost what timezone to use when outputting a date in your theme (other than using localisation in the theme), or anywhere else that a date might be output.
2) When you set a date in the PSM, there's no way to know whether that's using your timezone, the server's timezone, or the blog's timezone (which doesn't exist yet). It actually uses your own timezone, but then stores UTC, which makes things work sort of correctly, but is confusing.
We're going to solve this the same way that Twitter, Tumblr, WP, Slack etc all do. Add a setting to the general settings, and use this to output all dates everywhere, including when setting the published at date.
The timezone setting itself will take the form of a dropdown list, exactly the same as you see in Tumblr or Slack.
Tumblr:

(UTC<offset>) List, Of, Cities just like TumblrIn the post settings menu, the date picker needs to be updated to use the new global blog timezone instead of the user's timezone.
That means, if I'm in UTC+2, and I login to my blog which is set to GMT, when I create a new draft the PSM should show me the time in GMT, not in UTC+2. Equally if I set a post to publish at 2pm, this should be 2pm GMT not 2pm UTC+2 i.e.12pm GMT.
There are actually 2 date helpers in Ghost:
Both of the Date helpers need to be updated to take the timezone into account. As a result, the date output should always be correct according to the blog's timezone.
this is going to be rad.
Hi @AileenCGN, @ErisDS!
This is a really great improvement, as a longtime Ghost user from Hungary I'm looking forward to finally set my blog to my local timezone.
May I point to a possible shortcoming of your current implementation? I've checked the commit (7d20553651e7263ea5fde4017cbe97695d9d8a89), and if I'm not mistaken, utcOffset is used to calculate the local time, which, I understand, is incorrect.
The thing is that the UTC offset is not fixed, but affected by the daylight saving time, e.g. currently in the UK the offset is 0, but after 27th of March it will be 60.
To make things worse, the start of daylight saving time depends on the Country/region, e.g. in the US it starts on 10th March, or if I'm correct there is no daylight saving time in Egypt at all.
The best thing to do in my opinion is to use moment-timezone, which can handle this.
Here is an example:
var m = moment('2016-03-20T10:22');
console.log(m.utcOffset(-300).isDST()); // false
console.log(m.tz("US/Eastern").isDST()); // true
console.log(m.tz("Europe/Dublin").isDST()); // false
Not handling the DST properly can lead to several issues, including misleading information for the users and incorrect post scheduling.
Not to mention the sort of an edge case, when a user from the UK sets the publishedAt property to March 27th 2:30, which is kind of non-existing because at 2:00 the time is shifted to 3:00, will the post be published or not?
Hey @szelpe, this kind of constructive feedback is incredibly helpful, thanks for taking the time, much appreciated :+1:
Another thing to consider (if it hasn't been already) is users who chose to have the date of posting in their URL's.
Take for instance my migration to GhostPro from a server running in UTC+10 (AEST). Several of my posts ended up being back a day so the old URL now returned a 404.
ie http://example.com/2016/02/01/somepost/ -> http://example.com/2016/01/31/somepost/
So, when timezones get enabled in blogs, what is going to happen to posts that _might_ have their URL's changed in this scenario? Are they just going to return 404's? Is it going to be possible to add remaps or something?
_This was going to be a quick comment and then I did some more testing (so bear with me)_
In response to @Mooash:
On master (w/o the changes from #6421 added), I set a post's published date to yesterday at 11pm (I'm in GMT-6 timezone), and published it. With date included in my post permalinks, it showed up as /2016/03/17/post-name/).
I then added the changes from #6421 on top of master. The permalink _didn't change_; however, the shown published date inside the post-settings-menu did (it changed to today at 4am -> the time difference between GMT-6 and the default timezone of GMT - daylight savings time adjusted.). Also, when viewing the list of posts in the frontend or the actual post itself, the "date published" shows that it was published today.
I then went into settings/general and set the timezone of my blog back to GMT-6, and then all of the dates in the places returned to what they were before I added the changes from the PR.
tl;dr - The timezone PR doesn't change permalinks/urls of _published_ posts that were published before the code changes occured
I then tested to see if a new post with the PR changes was affected by the timezone setting. It wasn't actually. With a timezone of GMT, I set the post's published date to 2AM today. The permalink showed up as yesterday, in line with the current server timezone. This might _actually_ be an issue b/c if the server is hosted in a timezone different from that of the client, then permalinks would not reflect any timezone changes, which might be confusing.
So....while the original question won't happen, it might cause other errors....
If dates are included in permalinks, then handle them based on the timezone set in settings. As a stopgap to prevent 404's on previous posts, possibly do a 301 redirect based on the server's timezone to the actual timezone.
Pros with this behavior:
Cons:
any timezone changes will be reflected in the permalinks
Does it make sense, to allow permalinks being changed afterwards? I think it would make more sense, to always reflect the server UTC time in the permalinks. When they are used as a link somewhere and the user changes his timezone, the link should still be the same. What do you think?
I guess that does make sense, yeah. And honestly it would only make a difference in the url for just the people that use dates in the permalinks. As long as it doesn't break existing links (which it doesn't) it should be fine
Could you find any further issues with the permalinks? I tested it as well, and the dated permalinks always show the UTC server time. Of course, this could be confusing, if the user is not aware of that, but at least it should prevent the permalinks from breaking if a user changes his timezone. As I couldn't find any further issues with that, I think it's working fine now and there's no need for a 'fix'. Is that ok for you, @acburdine?
@aileen that sounds good to me, but I'll defer to @erisds 's judgement before merging the PR :smile:
Sorry, I know this is waiting for a comment from me, I've been mulling it over. Although it's not a bug, per se, it seems to be a big missing piece of the timezones puzzle and it doesn't appear to have an easy solution.
Up until now, we haven't had a concept of timezone setting, we've always used the server, so permalinks using the server timezone was OK. Now that we have a timezone setting, it seems to me that it would be the user's expectation that their post URL would reflect their timezone setting.
E.g. if in January I write a post just after midnight to say 'Happy New Year' and I'm in Spain and have set my timezone to UTC+1, I wouldn't expect my happy new year post to have a url of 2016/12/31/happy-new-year/.
Therefore, although it's not changing permalinks, and is not a bug, it still breaks user expectations. Therefore I'd rather not merge the timezones PR in until we have a clear idea how to do this extra piece. Otherwise one will definitely go out without the other and it could get harder to reconcile the behaviour.
There are two possible ways I see of fixing this:
One is implementing 301 redirects from server time to the blog-setting time as suggested by @acburdine. The major downside to this is that it only accounts for a single timezone change.
The second is to store a reference to which timezone was set when the post was published. My first idea here is to have a published_tz field added to posts which defaults to the server timezone (so all existing posts would have it set to the server timezone). And then any future posts get whatever the timezone setting is on the blog at the time the post is published. The downside here is storing additional data which means complexity & also having to figure out what to do with imports/exports.
I think this calls for a bit of research into how these things are handled elsewhere. If anyone has any ideas or suggestions or examples of handling of timezones in other platforms, please chime in!
Found some discussions about dated permalinks regarding the timezones issue:
Thanks for the pre-work @ErisDS and @acburdine. Here is my conclusion of how things can work together.
Because of this case we should ship the ghost node application running in UTC.
Either we force the user to change the system time (which may not work, because some people will not read the docs good enough or are not able to change it) or we force UTC in the node process. For example we can add UTC support by adding process.env.TZ = 'UTC' before any date is used. I will read into known issues later how we can avoid running into trouble.
When we change the process to run in UTC, we need to convert all existing posts in the database to be in UTC, if the local server time is not UTC. That means we need a migration script. The migration script will read the timezone of the server. Then we transform all post dates into UTC and update them. The rest will work automatically because every blog who gets this new ghost update, will have a default timezone in the settings (which is Dublin TZ). But permalinks will break afterwards. Thats a very good reason to implement the redirect option. The redirect idea is the simplest solution we can offer and it will solve a lot of edge case.
When we support the redirect feature, importing data is not a problem at all. Because we can redirect every permalink to the correct url on the fly.
The only thing we should add is a meta attribute in the JSON file in which timezone the dates in the JSON file are stored to ensure we can convert the dates to correct UTC values.
@AileenCGN
Here is a list of what needs to be done to get it work:
/controllers/frontend/indexurlPathForPost which calculates the permalink based on a post based on server timezone, this fn needs to be extended to calculate the url based on blog timezoneI will implement the UTC force on application level and care about the importer.
I鈥檓 happy for feedback and edge cases which cannot be handled with this strategy.
Most helpful comment
this is going to be rad.