我尝试使用java DateTime
和方法plusMonths()
从给定的开始日期添加完整的月份。
当我的开始时间是一个月初时,一切都像预期的那样:
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 :(得分:8)
日期操作的问题是月份有不同的天数。在1月份,你有31天,2月只有28天。如果你将“一个月”添加到1月31日,软件无法猜出你想要达到的目标,所以它会增加月份的增量,这将给你2月31日 - 无效。接下来的步骤就是调和产生这些奇怪结果的日期。
注意:在原始的Java Date类中,在1月份添加一个月之后,你会得到3月2日或3日,这不是更好: - )
在月末迭代的正确方法是迭代当月的第一天并减去一天(或一毫秒):
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。
答案 2 :(得分:1)
你无法改变到31年2月,对象无法记住你的意思是指本月的最后一天而不是28日。
相反,我建议您使用每个月的第一天并减去一毫秒。这样计算就可以按照你想要的方式进行计算。
答案 3 :(得分: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
答案 4 :(得分:1)
您的问题是一个示例,说明为什么通常使用“半开”方法最好地跟踪时间跨度。在半开放(表示法:[)
)中,如果时间跨度为包含,则开头为独占。因此,“一个月”意味着该月第一天的第一个时刻,并且在的情况下运行,但不包括下个月第一天的第一个时刻。
Joda-Time库提供了一个代表时间跨度的类,Interval。
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
答案 5 :(得分:0)
如果要使用日期和时间,可以使用Java Calendar对象。 阅读有关Java Calendar对象的内容,您可以使其工作。
例如,在Calendar对象中,您可以执行此操作:
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.MONTH, 1);
答案 6 :(得分: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
答案 7 :(得分: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());
}
答案 8 :(得分:0)
在递增月份之前添加一天,然后减去一天:
new DateTime(date).plusDays(1).plusMonths(months).minusDays(1).toDate()