知識庫 / Java Dates RSS 訂閱

在用户時區顯示日期

Java Dates,REST,Spring
HongKong
4
04:00 AM · Dec 06 ,2025

1. 概述

在本篇 Reddit 應用案例研究中,我們將添加根據用户時區安排帖子的功能。

處理時區問題在技術上極具挑戰性,並且技術選項非常廣泛。我們的首要關注點是,我們需要根據用户的自身(可配置的)時區向用户顯示日期。我們還需要決定日期將以何種格式存儲在數據庫中

2. 新用户偏好 – 時區

首先,我們將添加一個新的字段 – 時區 – 到我們現有的偏好設置中:

@Entity
public class Preference {
    ...
    private String timezone;
}

我們隨後只需在用户偏好頁面上配置時區——利用一個簡單但非常實用的 jQuery 插件:

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

請注意,默認時區為服務器時區——它運行在 UTC 之中。

3. 控制器

現在,我們來進入有趣的部分。我們需要將用户時區中的日期轉換為服務器時區:

@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);
    }
}

轉換過程相對簡單,但請注意,它僅在寫入操作時發生 – 服務器在讀取操作時仍返回 UTC 時間。

這對於我們的客户端來説完全沒問題,因為我們會使用 JavaScript 進行轉換 – 但值得注意的是,在讀取操作中,服務器仍返回 UTC 時間的日期

4. 前端

現在,讓我們看看如何在前端中使用用户時區:

4.1. 顯示帖子

我們需要使用用户的時區顯示帖子的 submissionDate

<table><thead><tr>
<th>Post title</th>
<th>Submission Date 
  (<span id="timezone" sec:authentication="principal.preference.timezone">UTC</span>)</th>
</tr></thead></table>

以下是我們的函數 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 在時區轉換方面提供幫助。

4.2. 安排新帖

我們需要修改我們的 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>

最後,我們需要修改我們的 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. 結論在本文中,我們向 Reddit 應用引入了一個簡單但非常實用的功能——根據您自己的時區查看所有內容。

這原本是我使用該應用時遇到的主要問題之一——一切都顯示為 UTC 時間。現在——所有日期都已正確顯示在用户的時區中,正如它們應該的那樣。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.