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.


« 上一篇: Baeldung周报第27期
» 下一篇: Baeldung周报第28期