[英]Calendar issue in Adding month +1 to to calendar month in Android
[英]Java Calendar/Date Issue while adding Month
如果我們在當前日期(IST 2013年5月31日星期五18:33:00)加上1個月,則會得出:
星期日2013年6月30日18:33:00
如果我們減去1個月,將得出:
IST 2013年5月30日18:33:00
是一個錯誤還是任何人都可以提供推理?
請找到相同的代碼:
Calendar c1 = Calendar.getInstance()
System.out.println(c1.getTime());
c1.add(Calendar.MONTH, 1);
System.out.println(c1.getTime());
c1.add(Calendar.MONTH, -1);
System.out.println(c1.getTime());
輸出量
Fri May 31 18:33:00 IST 2013
Sun Jun 30 18:33:00 IST 2013
Thu May 30 18:33:00 IST 2013
每月的更改是預期的行為,在此處記錄為“添加規則2”: http : //docs.oracle.com/javase/6/docs/api/java/util/Calendar.html
add(f,delta)將delta添加到字段f。 這等效於通過兩個調整來調用set(f,get(f)+ delta):
添加規則1.調用后字段f的值減去調用之前字段f的值是delta,對字段f中發生的任何溢出取模。 當字段值超出其范圍時會發生溢出,結果,下一個較大的字段將遞增或遞減,然后將字段值調整回其范圍。
添加規則2 。 如果預期較小的字段是不變的,但由於字段f更改后其最小值或最大值或其他約束(例如時區偏移量更改)而發生變化,則不可能使其等於先前值,則其值是不可能的調整為盡可能接近其期望值。 較小的字段表示較小的時間單位。 HOUR是比DAY_OF_MONTH小的字段。 不會對預計不會不變的較小字段進行調整。 日歷系統確定期望哪些字段是不變的。
有了這些規則,如果再添加1個月,然后再添加-1個月,就無法保留月份中的某天。
不,這是一個功能,並已記錄在案(很抱歉,這里很挑剔,但您在詢問之前是否確實閱讀過文檔?)。 閱讀有關add()
方法的文檔中的“ Field Manipulation
部分。 相關部分:
如果預期較小的字段是不變的,但由於字段f更改后其最小值或最大值或其他約束(例如時區偏移量更改)而發生變化,則不可能使其等於先前值,則其值是不可能的調整為盡可能接近其期望值。
示例:考慮一個最初設置為1999年8月31日的GregorianCalendar。調用add(Calendar.MONTH,13)將日歷設置為2000年9月30日。添加規則1將MONTH字段設置為9月,因為將8個月加上13個月將得出9月下一年。 由於在GregorianCalendar中,DAY_OF_MONTH在9月不能為31,因此添加規則2會將DAY_OF_MONTH設置為30(最接近的可能值)。 盡管它是一個較小的字段,但是DAY_OF_WEEK不受規則2的調整,因為當GregorianCalendar中的月份更改時,它可能會更改。
這是設計正確的。
從5月31日起增加一個月后,您將獲得6月30日(該月的最后一天)。
如果您從6月30日減去一個月,則會得到5月31日(一個月前)。
當您使用getTime()
獲得時間時,便完成了計算。 因此,我在這里看不到任何錯誤。
使用取代了麻煩的舊舊日期時間類(包括Calendar
的java.time類來進行現代更新。
定義您的時區。 以continent/region
的格式指定正確的時區名稱 ,例如America/Montreal
, Africa/Casablanca
或Pacific/Auckland
。 切勿使用EST
或IST
等3-4個字母的縮寫,因為它們不是真實的時區,不是標准化的,甚至不是唯一的(!)。 我猜您的意思是IST
是印度時間,但也許是愛爾蘭標准時間或其他時間?
final ZoneId z = ZoneId.of ( "Asia/Kolkata" );
ZonedDateTime
類表示調整到特定時區的時間軸上的時刻。
final ZonedDateTime zdt = ZonedDateTime.of ( 2013, 5, 31, 18, 33, 0, 0, z );
plusMonths
| minusMonths
final ZonedDateTime zdtMonthPlus = zdt.plusMonths ( 1 );
final ZonedDateTime zdtMonthMinus = zdtMonthPlus.minusMonths ( 1 );
轉儲到控制台。
System.out.println ( "zdt.toString(): " + zdt );
System.out.println ( "zdtMonthPlus.toString(): " + zdtMonthPlus );
System.out.println ( "zdtMonthMinus.toString(): " + zdtMonthMinus );
我們看到的行為與舊版Calendar
類相同。 如果從5月31日開始添加一個月,則沒有6月31日,因此它會退回到該月的最后一天,即6月30日。從6月30日減去時,該類將嘗試匹配同一天,因此它使用May 30歲
zdt.toString():2013-05-31T18:33 + 05:30 [亞洲/加爾各答]
zdtMonthPlus.toString():2013-06-30T18:33 + 05:30 [亞洲/加爾各答]
zdtMonthMinus.toString():2013-05-30T18:33 + 05:30 [亞洲/加爾各答]
plus( Duration)
| minus( Duration )
如果您想要其他行為,請對您的代碼使用另一種方法。 例如,如果用“月”來表示“ 30天的普通24小時天(忽略諸如夏時制之類的異常)”,則應添加/減去30天的持續時間。
Duration thirtyDays = Duration.ofDays( 30 ); // 30 days of generic 24-hour length. Ignoring anomalies such as DST. Ignoring calendar months.
final ZonedDateTime zdtMonthPlusDuration = zdt.plus ( thirtyDays );
final ZonedDateTime zdtMonthMinusDuration = zdtMonthPlusDuration.minus ( thirtyDays );
fiftyDays.toString():PT720H
zdtMonthPlusDuration.toString():2013-06-30T18:33 + 05:30 [亞洲/加爾各答]
zdtMonthMinusDuration.toString():2013-05-31T18:33 + 05:30 [亞洲/加爾各答]
java.time框架內置於Java 8及更高版本中。 這些類取代了麻煩的舊的舊式日期時間類,例如java.util.Date
, Calendar
和SimpleDateFormat
。
現在處於維護模式的Joda-Time項目建議遷移到java.time類。
要了解更多信息,請參見Oracle教程 。 並在Stack Overflow中搜索許多示例和說明。 規格為JSR 310 。
在哪里獲取java.time類?
ThreeTen-Extra項目使用其他類擴展了java.time。 該項目為將來可能在java.time中添加內容提供了一個試驗場。 您可以在這里找到一些有用的類,比如Interval
, YearWeek
, YearQuarter
,和更多 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.