2013-11-01 16 views
4

我嘗試使用java DateTime和方法plusMonths()從給定開始日期添加完整月份。使用Java中的Joda-Time DateTime添加一個月迄今爲止失敗

當我開始時間是一個月的開始,一切工作像預期:

DateTime startOfMonth = new DateTime(2013, 1, 1, 00, 00, 00); 
    System.out.println(startOfMonth.toString()); 
    for (int i = 0; i < 12; i++) { 
     startOfMonth = startOfMonth.plusMonths(1); 
     System.out.println(startOfMonth.toString()); 
} 

輸出爲每月的第一天像預期,一切都很好!

2013-01-01T00:00:00.000+01:00 
2013-02-01T00:00:00.000+01:00 
2013-03-01T00:00:00.000+01:00 
2013-04-01T00:00:00.000+02:00 
2013-05-01T00:00:00.000+02:00 
2013-06-01T00:00:00.000+02:00 
2013-07-01T00:00:00.000+02:00 
2013-08-01T00:00:00.000+02:00 
2013-09-01T00:00:00.000+02:00 
2013-10-01T00:00:00.000+02:00 
2013-11-01T00:00:00.000+01:00 
2013-12-01T00:00:00.000+01:00 
2014-01-01T00:00:00.000+01:00 

但是,當我改變我的例子到一個月結束它不會返回我想要的!

System.out.println(""); 
DateTime endOfMonth = new DateTime(2012, 12, 31, 23, 59, 59); 
System.out.println(endOfMonth.toString()); 
for (int i = 0; i < 12; i++) { 
    endOfMonth = endOfMonth.plusMonths(1); 
    System.out.println(endOfMonth.toString()); 
} 

這將返回:

2012-12-31T23:59:59.000+01:00 
2013-01-31T23:59:59.000+01:00 
2013-02-28T23:59:59.000+01:00 
2013-03-28T23:59:59.000+01:00 
2013-04-28T23:59:59.000+02:00 
2013-05-28T23:59:59.000+02:00 
2013-06-28T23:59:59.000+02:00 
2013-07-28T23:59:59.000+02:00 
2013-08-28T23:59:59.000+02:00 
2013-09-28T23:59:59.000+02:00 
2013-10-28T23:59:59.000+01:00 
2013-11-28T23:59:59.000+01:00 
2013-12-28T23:59:59.000+01:00 

那麼,爲什麼"2013-02-28T23:59:59.000+01:00"加上一個月不"2013-03-31T23:59:59.000+01:00"? 這三天在哪裏?

+0

也許你需要專門處理二月的情況。正如下面的答案表明這是DateTime的行爲方式。 – mawia

+0

@mawia很多個月的時間少於31天。 –

+0

這裏是得到本月最後一天的正確方法: http://stackoverflow.com/questions/9711454/how-to-get-the-last-date-of-a-particular-month-with- jodatime – Admit

回答

8

日期操作的問題是,幾個月有不同的天數。 1月份,你有31天,2月份只有28天。如果你在1月31日增加「一個月」,軟件無法猜測你想達到什麼目的,所以它增加了2月31日的月份增量 - 無效。接下來的步驟是調整產生這些奇怪結果的日期。

注:原始的Java日期類,你會1個月加入一月一日之後獲得第二或第三三月這是不是:-)

正確的方法正好更好地遍歷結束一個月來迭代,然後每月的第一天,減法一天(或一毫秒):

DateTime startOfMonth = new DateTime(2013, 1, 1, 00, 00, 00); 
System.out.println(startOfMonth.toString()); 
for (int i = 0; i < 12; i++) { 
    startOfMonth = startOfMonth.plusMonths(1); 
    DateTime endOfMonth = startOfMonth.minusDays(1); // magic here 
    System.out.println(startOfMonth + "-" + endOfMonth); 
} 

如果你只需要一個日期範圍,使用半開區間[start,end)其中end永遠是第一位的一個月。

+1

或減一秒/毫秒 –

4

由於2013年2月僅有28天,因此當您在一個月後添加時,它將保持每個月的第28天。

這在doc指定:

計算將盡力只更改月份字段 保留一個月的同一天。但是,在某些情況下,它可能需要更改較小的字段。例如,2007-03-31加 一個月不能導致2007-04-31,所以將當月的一天調整爲 至2007-04-30。

+0

我的問題是,我有一個開始和結束時間的應用程序和一些分辨率顯示一些數據的分辨率。例如,我可以選擇1.1.2013 00:00:00至1.1.2014 00:00:00,分辨率爲月份。現在我可以在垃圾箱中查看每個月的一些數據。這些設置將存儲在帶有本地時間的模板中。當有人在不同的時區使用相同的模板時,就會出現問題。 然後開始時間和結束時間爲例如31.12.2012 23:00:00至31.12.2013 23:00:00(-1小時).... – Gatschet

+0

...1月和2月這不成問題。但是月份行程只有28天,因爲28.2.2013加上一個月的結果在28.3.2013!通過這種方式,客戶沒有完整的月... – Gatschet

1

你不能改變到二月的31,並且沒有辦法讓對象記住你的意思是一個月的最後一天,而不是28日。

相反,我建議你使用每個月的第一天,減去1毫秒。這樣計算就會以您想要的方式獲得價值。

0

如果您想使用日期和時間,則可以使用java日曆對象。 閱讀關於Java日曆對象,你可以使這個工作。

例如日曆對象,你可以這樣做:

Calendar cal = Calendar.getInstance(); 
cal.setTime(new Date()); 

cal.add(Calendar.MONTH, 1); 
+0

我在我的例子DateTime替換java.util.Calendar,但結果是相同的!從「2013-02-28T23:59:59.000 + 01:00」開始的cal.add(Calendar.MONTH,1)仍然是「2013-03-28T23:59:59.000 + 01:00」 – Gatschet

0

這個工作對我來說:

public static void main(String[] args) { 
    Calendar endOfMonth = Calendar.getInstance(); 
    endOfMonth.set(Calendar.DAY_OF_MONTH, 31); 
    endOfMonth.set(Calendar.MONTH, 11); 
    endOfMonth.set(Calendar.YEAR, 2012); 

    endOfMonth.set(Calendar.HOUR_OF_DAY, 23); 
    endOfMonth.set(Calendar.MINUTE, 59); 
    endOfMonth.set(Calendar.SECOND, 59); 
    endOfMonth.set(Calendar.MILLISECOND, 59); 

    System.out.println(endOfMonth.getTime()); 
    for (int i = 0; i < 12; i++) { 
     endOfMonth.add(Calendar.MONTH, 1); 

     if(i >= 2){ 
      endOfMonth.add(Calendar.MONTH, 1); 
      endOfMonth.set(Calendar.DAY_OF_MONTH, 1); 
      endOfMonth.add(Calendar.DAY_OF_MONTH, -1); 
     } 

     System.out.println(endOfMonth.getTime()); 
    } 
} 

,其結果是:

Mon Dec 31 23:59:59 GMT+04:00 2012 
Thu Jan 31 23:59:59 GMT+04:00 2013 
Thu Feb 28 23:59:59 GMT+04:00 2013 
Sun Mar 31 23:59:59 GMT+04:00 2013 
Tue Apr 30 23:59:59 GMT+04:00 2013 
Fri May 31 23:59:59 GMT+04:00 2013 
Sun Jun 30 23:59:59 GMT+04:00 2013 
Wed Jul 31 23:59:59 GMT+04:00 2013 
Sat Aug 31 23:59:59 GMT+04:00 2013 
Mon Sep 30 23:59:59 GMT+04:00 2013 
Thu Oct 31 23:59:59 GMT+04:00 2013 
Sat Nov 30 23:59:59 GMT+04:00 2013 
Tue Dec 31 23:59:59 GMT+04:00 2013 
1

正如在評論中提到上面的Joda獲取本月最後一天的方法是獲得dayOfMonth屬性的最大值。

public static void endOfMonth() { 
    DateTime startOfMonth = new DateTime(2013, 1, 1, 00, 00, 00); 

    for (int i = 0; i < 12; i++) { 
     int lastDay = startOfMonth.dayOfMonth().getMaximumValue(); 
     System.out.println(startOfMonth.withDayOfMonth(lastDay).toString()); 

     startOfMonth = startOfMonth.plusMonths(1); 
    } 
} 

這將產生:

2013-01-31T00:00:00.000-06:00 
2013-02-28T00:00:00.000-06:00 
2013-03-31T00:00:00.000-05:00 
2013-04-30T00:00:00.000-05:00 
2013-05-31T00:00:00.000-05:00 
2013-06-30T00:00:00.000-05:00 
2013-07-31T00:00:00.000-05:00 
2013-08-31T00:00:00.000-05:00 
2013-09-30T00:00:00.000-05:00 
2013-10-31T00:00:00.000-05:00 
2013-11-30T00:00:00.000-06:00 
2013-12-31T00:00:00.000-06:00 
0

這樣計算,我認爲最好的解決方法是修復原來的種子日期和不斷遞增的月數添加爲您遍歷。這樣你就不會隨着你的進展而積累任何調整。試試這個:

System.out.println(""); 
    DateTime endOfMonth = new DateTime(2012, 12, 31, 23, 59, 59); 
    System.out.println(endOfMonth.toString()); 
    for (int i = 0; i < 12; i++) { 
     DateTime newEndOfMonth = endOfMonth.plusMonths(i+1); 
     System.out.println(newEndOfMonth.toString()); 
    } 
1

半開

你的問題是,爲什麼跟蹤時間跨度的例子使用「半開」的做法通常是最好的做法。在Half-Open(註釋:[))中,開始的時間跨度爲,包括,而結尾是,獨佔。所以「一個月」是指該月的第一天的第一個時刻,運行到,但不包括在下個月的第一天的第一個時刻的

喬達時間庫提供了一個類來表示這樣的時間跨度。

DateTimeZone timeZone = DateTimeZone.forID("Europe/Zurich"); 
DateTime firstOfYear = new DateTime(2013, 1, 1, 0, 0, 0, timeZone).withTimeAtStartOfDay(); 
Interval month01_Interval = new Interval(firstOfYear, firstOfYear.plusMonths(1).withTimeAtStartOfDay()); 

當運行:

month01_Interval : 2013-01-01T00:00:00.000+01:00/2013-02-01T00:00:00.000+01:00 
0

添加1天遞增一個月前,覈減1天算賬:

new DateTime(date).plusDays(1).plusMonths(months).minusDays(1).toDate()