亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Java日歷中的未來日期給出了一種奇怪的行為

Java日歷中的未來日期給出了一種奇怪的行為

慕的地8271018 2022-01-06 17:03:25
我有一個應用程序,我創建了用戶可以選擇約會的日期。如果用戶在 9 點開始工作,并且約會需要 2 小時,我會在 9 點、11 點、13 點創建日期……當然,直到限制。然后我改變了一天,重新開始。這是執行此操作的代碼:    public List<Agenda> createListOfDates(Calendar initial, Calendar end,         int appointmentDuration, int lunchTimeDuration, int lunchTimeStart) {        List<Agenda> agendaList = new ArrayList<Agenda>();        Agenda agenda = new Agenda();        agenda.setWorkingHour(initial.getTime());        agendaList.add(agenda);        while (true) {            initial.add(Calendar.HOUR_OF_DAY, appointmentDuration);//          Logger.error("" + initial.getTime());            if (initial.getTime().after(end.getTime())) {                break;            } else if (initial.get(Calendar.HOUR_OF_DAY) == lunchTimeStart                    && initial.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY                    ) {                initial.add(Calendar.HOUR_OF_DAY, lunchTimeDuration);                agenda = new Agenda();                agenda.setWorkingHour(initial.getTime());                agendaList.add(agenda);            } else {                agenda = new Agenda();                agenda.setWorkingHour(initial.getTime());                agendaList.add(agenda);            }        }        for(Agenda agendaX : agendaList){        Logger.info("" + agendaX.getWorkingHour());}        return agendaList;    }我正在使用“美國/圣保羅”時區來創建這些日期。我將變量“initial”和“end”設置為“America/Sao_Paulo”。我的系統時區是“GMT”,沒關系,因為我想將這些日期以 GMT 格式保存在數據庫中。當我在最后一個“for”中打印日期時,神奇的是它已經從“America/Sao_Paulo”轉換為“GMT”并且打印正確。奇怪的是,從某個日期開始,它會更改時區。打印示例:Sat Mar 30 12:00:00 GMT 2019Sat Mar 30 14:00:00 GMT 2019Sat Mar 30 16:00:00 GMT 2019Sat Mar 30 18:00:00 GMT 2019Mon Apr 01 13:00:00 BST 2019Mon Apr 01 15:00:00 BST 2019Mon Apr 01 18:00:00 BST 2019Mon Apr 01 20:00:00 BST 2019Mon Apr 01 22:00:00 BST 2019雖然在格林威治標準時間,這是正確的,但我無法理解這個 BST。會不會是因為以后太多了?它總是從四月開始。
查看完整描述

1 回答

?
慕村9548890

TA貢獻1884條經驗 獲得超4個贊

您的系統時間不是格林威治標準時間,而是歐洲/倫敦(或類似時間)。三月倫敦時間與格林威治標準時間一致。不是在四月。這就是為什么。


getWorkingHour()返回一個實例Date(另一個設計糟糕且過時的類,但現在讓它成為一個不同的故事)。當您將其附加到空字符串時,會Date.toString被隱式調用并使用您的系統時區構建字符串。在標準時間,它打印GMT為時區縮寫。夏令時 (DST) 于 3 月的最后一個星期日在倫敦開始,在本例中為 3 月 31 日。因此,在 4 月Date.toString,您的 JVM 使用英國夏令時及其縮寫BST來打印時間。


好的解決方案包括兩個變化:


不要依賴 JVM 的默認時區。它可以隨時從您程序的另一部分或在同一 JVM 中運行的另一個程序進行更改,因此太脆弱了。而是為您的日期時間操作提供明確的時區。

跳過舊的日期時間類Calendar,Date而是使用 java.time,現代 Java 日期和時間 API。使用起來更好,并提供更清晰的代碼,尤其是在時區之間的轉換方面。

而不是Calendar使用ZonedDateTime。根據 JDBC 驅動程序的功能,將其轉換為UTCInstant或OffsetDateTimeUTC 以保存到數據庫。


要創建ZonedDateTime,一種選擇是使用其of方法之一(有幾種):


    ZonedDateTime initial = ZonedDateTime.of(2019, 3, 10, 9, 0, 0, 0, ZoneId.of("America/Sao_Paulo"));

這將在圣保羅創建日期時間 2019 年 3 月 10 日 09:00。添加 2 小時:


    int appointmentDuration = 2;

    ZonedDateTime current = initial.plusHours(appointmentDuration);

    System.out.println(current);

輸出:


2019-03-10T11:00-03:00[美國/圣保羅]


要Instant為您的數據庫轉換為:


    Instant inst = current.toInstant();

    System.out.println(inst);

輸出:


2019-03-10T14:00:00Z


瞬間是時區中立的,只是一個時間點,但以 UTC 打印。某些 JDBC 驅動程序在 UTC 時間接受它們。如果你的沒有發生,你需要給它一個OffsetDateTime。像這樣轉換:


    OffsetDateTime odt = current.toOffsetDateTime().withOffsetSameInstant(ZoneOffset.UTC);

    System.out.println(odt);

輸出:


2019-03-10T14:00Z


請注意,我明確給出了 UTC 而不是依賴于 JVM 默認值。所以這在UTC中是明確的。您注意到日期和時間與從Instant.


查看完整回答
反對 回復 2022-01-06
  • 1 回答
  • 0 關注
  • 153 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號