Displaying Dates in the Timezone of the User – 在用户的时区显示日期

最后修改: 2015年 6月 29日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

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.

在本期Reddit应用案例研究中,我们将加入被根据用户的时区来安排帖子的时间

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

2.一个新的用户偏好–时区

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:

然后,我们只需使时区在用户首选项页中可配置–利用一个简单但非常有用的JQuery 插件

<select id="timezone" name="timezone"></select>
<script>
    $(function() {
        $('#timezone').timezones();
    });
</script>

Note that the default timezone is the server timezone – which runs on UTC.

请注意,默认的时区是服务器的时区–UTC上运行。

3. The Controller

3.控制器

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.

这种转换是非常直接的,但请注意,它只发生在写操作上–服务器仍然返回UTC的读取。

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.

这对我们的客户来说完全没问题,因为我们会在JS中进行转换 – 但值得理解的是,对于读取操作,服务器仍然返回UTC日期

4. The Front-End

4.前端

Now – let’s see how to use the user’s timezone in front-end:

现在–让我们看看如何在前端使用用户的时区。

4.1. Display the Posts

4.1.显示帖子

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():

这里是我们的函数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.

Moment.js在这里帮助进行时区转换。

4.2. Schedule a New Post

4.2.安排一个新帖子

We also need to modify our schedulePostForm.html:

我们还需要修改我们的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:

最后–我们还需要修改我们的editPostForm.html,使submissonDate的旧值本地化。

$(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

5.结论

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.

在这篇简单的文章中,我们在Reddit应用程序中引入了一个简单但非常有用的功能–能够根据你自己的时区查看一切。

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.

这是我在使用该应用程序时的主要痛点之一–事实上,一切都在UTC。现在,所有的日期都正确地显示在用户的时区,因为它们应该是这样。