[英]Future dates in java calendar are giving a strange behaviour
我有一個應用程序,可以創建用戶可以選擇約會的日期。 如果用戶從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;
}
我正在使用“ America / Sao_Paulo”時區來創建這些日期。 我將變量“ initial”和“ end”設置為“ America / Sao_Paulo”。 我的系統時區是“ GMT”,沒關系,因為我想將這些日期保存在數據庫的GMT中。 當我在最后一個“ for”中打印日期時,已經神奇地將其從“ America / Sao_Paulo”轉換為“ GMT”,並且打印正確。 奇怪的是,從某個日期開始,它會更改時區。 打印示例:
Sat Mar 30 12:00:00 GMT 2019
Sat Mar 30 14:00:00 GMT 2019
Sat Mar 30 16:00:00 GMT 2019
Sat Mar 30 18:00:00 GMT 2019
Mon Apr 01 13:00:00 BST 2019
Mon Apr 01 15:00:00 BST 2019
Mon Apr 01 18:00:00 BST 2019
Mon Apr 01 20:00:00 BST 2019
Mon Apr 01 22:00:00 BST 2019
雖然在格林尼治標准時間(GMT),這是正確的,但我無法理解此BST。 可能是因為將來太多了嗎? 它總是從四月開始。
您的系統時間不是格林尼治標准時間,而是歐洲/倫敦(或類似時間)。 3月,倫敦時間恰逢格林尼治標准時間。 不在四月。 這就是為什么。
getWorkingHour()
返回Date
一個實例(另一個設計欠佳且過時的類,但現在讓它變成一個不同的故事)。 當您將其附加到空字符串時, Date.toString
被隱式調用,並使用您的系統時區構建該字符串。 在標准時間,它將GMT
打印為時區縮寫。 夏令時(DST)在3月的最后一個星期日,即3月31日,在倫敦開始。因此,在4月,JVM上的Date.toString
使用英國夏令時及其縮寫BST
來打印時間。
好的解決方案涉及兩個更改:
Calendar
和Date
,而使用現代Java日期和時間API java.time。 使用它會更好,代碼也更清晰,尤其是在時區之間進行轉換時。 代替Calendar
使用ZonedDateTime
。 根據JDBC驅動程序的功能,將其轉換為UTC中的Instant
或OffsetDateTime
以保存到數據庫。
要創建一個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
所打印的內容一致。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.