1. Overview
In this installment of the Reddit app case study, we’re going to be adding the be scheduling post’s according to the user’s timezone.
Dealing with timezones is notoriously difficult and the technical options are wide open. Our first concern is that we need to show dates to the user according to their own (configurable) timezone. We also need to decide what format the date will be saved as, in the database.
2. A New User Preference – timezone
First, we’ll add a new field – timezone – to our already existing preferences:
@Entity
public class Preference {
...
private String timezone;
}
We then simply make the timezone configurable in the user Preferences Page – leveraging a simple but very useful JQuery plugin:
<select id="timezone" name="timezone"></select>
<script>
$(function() {
$('#timezone').timezones();
});
</script>
Note that the default timezone is the server timezone – which runs on UTC.
3. The Controller
Now, for the fun part. We need to convert dates from the user’s timezone to the server’s timezone:
@Controller
@RequestMapping(value = "/api/scheduledPosts")
public class ScheduledPostRestController {
private static final SimpleDateFormat dateFormat =
new SimpleDateFormat("yyyy-MM-dd HH:mm");
@RequestMapping(method = RequestMethod.POST)
@ResponseStatus(HttpStatus.OK)
public void schedule(
@RequestBody Post post,
@RequestParam(value = "date") String date) throws ParseException
{
post.setSubmissionDate(
calculateSubmissionDate(date, getCurrentUser().getPreference().getTimezone()));
...
}
@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
@ResponseStatus(HttpStatus.OK)
public void updatePost(
@RequestBody Post post,
@RequestParam(value = "date") String date) throws ParseException
{
post.setSubmissionDate(
calculateSubmissionDate(date, getCurrentUser().getPreference().getTimezone()));
...
}
private synchronized Date calculateSubmissionDate(String dateString, String userTimeZone)
throws ParseException {
dateFormat.setTimeZone(TimeZone.getTimeZone(userTimeZone));
return dateFormat.parse(dateString);
}
}
The conversion is pretty straightforward, but do note that it’s only happening on write operations – the server still returns UTC for reads.
That’s perfectly fine for our client, because we’ll do the conversion in JS – but it’s worth understanding that, for read operations, the server still returns UTC dates.
4. The Front-End
Now – let’s see how to use the user’s timezone in front-end:
4.1. Display the Posts
We will need to display the post’s submissionDate using the user’s timezone:
<table><thead><tr>
<th>Post title</th>
<th>Submission Date
(<span id="timezone" sec:authentication="principal.preference.timezone">UTC</span>)</th>
</tr></thead></table>
And here is our function loadPage():
function loadPage(page){
...
$('.table').append('<tr><td>'+post.title+'</td><td>'+
convertDate(post.submissionDate)+'</td></tr>');
...
}
function convertDate(date){
var serverTimezone = [[${#dates.format(#calendars.createToday(), 'z')}]];
var serverDate = moment.tz(date, serverTimezone);
var clientDate = serverDate.clone().tz($("#timezone").html());
var myformat = "YYYY-MM-DD HH:mm";
return clientDate.format(myformat);
}
Moment.js helps here with the timezone conversion.
4.2. Schedule a New Post
We also need to modify our schedulePostForm.html:
Submission Date (<span sec:authentication="principal.preference.timezone">UTC</span>)
<input id="date" name="date" />
<script type="text/javascript">
function schedulePost(){
var data = {};
$('form').serializeArray().map(function(x){data[x.name] = x.value;});
$.ajax({
url: 'api/scheduledPosts?date='+$("#date").val(),
data: JSON.stringify(data),
type: 'POST',
contentType:'application/json',
success: function(result) {
window.location.href="scheduledPosts";
},
error: function(error) {
alert(error.responseText);
}
});
}
</script>
Finally – we also need to modify our editPostForm.html to localize the submissonDate old value:
$(function() {
var serverTimezone = [[${#dates.format(#calendars.createToday(), 'z')}]];
var serverDate = moment.tz($("#date").val(), serverTimezone);
var clientDate = serverDate.clone().tz($("#timezone").html());
var myformat = "YYYY-MM-DD HH:mm";
$("#date").val(clientDate.format(myformat));
});
5. Conclusion
In this simple article, we introduced a simple but highly useful feature into the Reddit app – the ability to see everything according to your own timezone.
This was one of the main pain points as I was using the app – the fact that everything was in UTC. Now – all dates are properly displayed in the timezone of the user, as they should be.