我想要在2 java.util.Date
之间的月数,而不计算月中的天数。
所以我只想比较年份和月份。
monthsBetween(new Date(2012,01,28), new Date(2012,02,01)) ---> 1
monthsBetween(new Date(2012,02,27), new Date(2012,02,28)) ---> 0
monthsBetween(new Date(2012,03,28), new Date(2012,07,01)) ---> 4
我尝试了这个(返回0,预期为1),使用Joda-time:
private static int monthsBetween(final Date fromDate, final Date toDate) {
DateTime date1 = new DateTime().withDate(2012, 1, 20);
DateTime date2 = new DateTime().withDate(2012, 2, 13);
PeriodType monthDay = PeriodType.yearDayTime().withDaysRemoved();
Period difference = new Period(date1, date2, monthDay);
int months = difference.getMonths();
return months;
}
还有这个(相同的结果),使用Joda-time:
private static int monthsBetween(final Date fromDate, final Date toDate) {
return Months.monthsBetween(new DateTime(fromDate), new DateTime(toDate).getMonths();
}
我该如何做到这一点?
答案 0 :(得分:8)
您要求的是整月的数量 - 这与说“忽略月份的某一部分”不同。
首先,我建议使用LocalDate
代替DateTime
进行计算。理想情况下,根本不要使用java.util.Date
,并将您的输入作为LocalDate
开始(例如,通过直接解析文本或数据来自何处。)将日期设置为两个日期分别为1,然后在几个月内取差价:
private static int monthsBetweenIgnoreDays(LocalDate start, LocalDate end) {
start = start.withDayOfMonth(1);
end = end.withDayOfMonth(1);
return Months.monthsBetween(start, end).getMonths();
}
答案 1 :(得分:5)
此版本基于JDK Calendar:
public static void main(String[] args) throws Exception {
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
Date d1 = f.parse("2012-01-01");
Date d2 = f.parse("2012-02-02");
int n = differenceInMonths(d1, d2);
System.out.println(n);
}
private static int differenceInMonths(Date d1, Date d2) {
Calendar c1 = Calendar.getInstance();
c1.setTime(d1);
Calendar c2 = Calendar.getInstance();
c2.setTime(d2);
int diff = 0;
if (c2.after(c1)) {
while (c2.after(c1)) {
c1.add(Calendar.MONTH, 1);
if (c2.after(c1)) {
diff++;
}
}
} else if (c2.before(c1)) {
while (c2.before(c1)) {
c1.add(Calendar.MONTH, -1);
if (c1.before(c2)) {
diff--;
}
}
}
return diff;
}
答案 2 :(得分:2)
如果你有年数和月数的int值:
months = (year2-year1)*12 + month2 - month1;
一年12个月。
答案 3 :(得分:2)
java.util
日期时间 API 及其格式化 API SimpleDateFormat
已过时且容易出错。建议完全停止使用它们并切换到 modern Date-Time API*。
使用现代 API java.time
的解决方案:由于您不需要在您的要求中考虑时间和时区,LocalDate
最适合您的要求。
演示:
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
public class Main {
public static void main(String[] args) {
// Test
System.out.println(monthsBetween(LocalDate.of(2012, 1, 28), LocalDate.of(2012, 2, 1)));
System.out.println(monthsBetween(LocalDate.of(2012, 2, 27), LocalDate.of(2012, 2, 28)));
System.out.println(monthsBetween(LocalDate.of(2012, 3, 28), LocalDate.of(2012, 7, 1)));
}
static int monthsBetween(final LocalDate fromDate, final LocalDate toDate) {
return Math.toIntExact(
ChronoUnit.MONTHS.between(
fromDate.with(TemporalAdjusters.firstDayOfMonth()),
toDate.with(TemporalAdjusters.firstDayOfMonth())
)
);
}
}
输出:
1
0
4
java.util.Date
:无论出于何种原因,如果您需要对java.util.Date
的对象执行此操作,您可以使用可转换的Date#toInstant
将java.util.Date
的对象转换为Instant
根据需要更改为其他 java.time
类型。
演示:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) throws ParseException {
// Test
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
System.out.println(monthsBetween(sdf.parse("2012-01-28"), sdf.parse("2012-02-01")));
System.out.println(monthsBetween(sdf.parse("2012-02-27"), sdf.parse("2012-02-28")));
System.out.println(monthsBetween(sdf.parse("2012-03-28"), sdf.parse("2012-07-01")));
}
static int monthsBetween(final Date fromDate, final Date toDate) {
ZonedDateTime zdtFrom = fromDate.toInstant().atZone(ZoneOffset.UTC);
ZonedDateTime zdtTo = toDate.toInstant().atZone(ZoneOffset.UTC);
return Math.toIntExact(
ChronoUnit.MONTHS.between(
zdtFrom.with(TemporalAdjusters.firstDayOfMonth()),
zdtTo.with(TemporalAdjusters.firstDayOfMonth())
)
);
}
}
输出:
1
0
4
从 modern Date-Time API 中详细了解 java.time
,Trail: Date Time*。
一些重要的注意事项:
java.util.Date(int, int, int)
。java.util.Date
和 java.util.Calendar
月是从 0 开始的,即一月是月#0。但是,SimpleDateFormat
将一月视为月份#1。int
被视为八进制数,只能支持 0-7 范围内的数字。您不是偶然遇到编译错误的,因为您只使用了 07 个月。例如,如果您使用 08 或 09,您就会遇到编译错误。* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 & 7. 如果您正在为 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaring 和 How to use ThreeTenABP in Android Project。
答案 4 :(得分:1)
/**
* Gets number of months between two dates.
* <p>Months are calculated as following:</p>
* <p>After calculating number of months from years and months from two dates,
* if there are still any extra days, it will be considered as one more month.
* For ex, Months between 2012-01-01 and 2013-02-06 will be 14 as
* Total Months = Months from year difference are 12 + Difference between months in dates is 1
* + one month since day 06 in enddate is greater than day 01 in startDate.
* </p>
* @param startDate
* @param endDate
* @return
*/
public static int getMonthsBetweenDates(Date startDate, Date endDate)
{
if(startDate.getTime() > endDate.getTime())
{
Date temp = startDate;
startDate = endDate;
endDate = temp;
}
Calendar startCalendar = Calendar.getInstance();
startCalendar.setTime(startDate);
Calendar endCalendar = Calendar.getInstance();
endCalendar.setTime(endDate);
int yearDiff = endCalendar.get(Calendar.YEAR)- startCalendar.get(Calendar.YEAR);
int monthsBetween = endCalendar.get(Calendar.MONTH)-startCalendar.get(Calendar.MONTH) +12*yearDiff;
if(endCalendar.get(Calendar.DAY_OF_MONTH) >= startCalendar.get(Calendar.DAY_OF_MONTH))
monthsBetween = monthsBetween + 1;
return monthsBetween;
}
答案 5 :(得分:1)
我只想获取Calendar实例的年和月字段,将年份转换为月份并获得差异。
private static int monthsBetween(final Date s1, final Date s2) {
final Calendar d1 = Calendar.getInstance();
d1.setTime(s1);
final Calendar d2 = Calendar.getInstance();
d2.setTime(s2);
int diff = (d2.get(Calendar.YEAR) - d1.get(Calendar.YEAR)) * 12 + d2.get(Calendar.MONTH) - d1.get(Calendar.MONTH);
return diff;
}
答案 6 :(得分:0)
它也适用于闰年
public static int getNumberOfMonths(Date fromDate, Date toDate) {
int monthCount = 0;
Calendar cal = Calendar.getInstance();
cal.setTime(fromDate);
int c1date = cal.get(Calendar.DATE);
int c1month = cal.get(Calendar.MONTH);
int c1year = cal.get(Calendar.YEAR);
cal.setTime(toDate);
int c2date = cal.get(Calendar.DATE);
int c2month = cal.get(Calendar.MONTH);
int c2year = cal.get(Calendar.YEAR);
System.out.println(" c1date:"+c1date+" month:"+c1month+" year:"+c1year);
System.out.println(" c2date:"+c2date+" month:"+c2month+" year:"+c2year);
GregorianCalendar grCal = new GregorianCalendar();
boolean isLeapYear1 = grCal.isLeapYear(c1year);
boolean isLeapYear2 = grCal.isLeapYear(c2year);
monthCount = ((c2year - c1year) * 12) + (c2month - c1month);
if(isLeapYear2 && c2month == 1 && c2date == 29){
monthCount = monthCount+ ((c1date == 28)?0:1);
}else if(isLeapYear1 && c1month == 1 && c1date == 29){
monthCount = monthCount+ ((c2date == 28)?0:1);
}else{
monthCount = monthCount+ ((c2date >= c1date)?0:1);
}
return monthCount;
}
答案 7 :(得分:0)
这会让你在几个月内获得差异
(endCal.get(Calendar.YEAR)*12+endCal.get(Calendar.MONTH))-(startCal.get(Calendar.YEAR)*12+startCal.get(Calendar.MONTH))