Java中按时间跨度计算的日历月数

Java中按时间跨度计算的日历月数,java,date,java-time,Java,Date,Java Time,对于从一个日期到另一个日期的时间跨度,如何获取包含我的跨度中的一天或多天的日历月数 例如: 2016-01-23/2016-01-23=1个日历月1月 2016-01-31/2016-02-01=2个日历月1月、2月 2016-01-23/2016-02-28=2个日历月1月、2月 2016-01-15/2016-03-15=3个日历月1月、2月、3月 2016-01-15/2017-03-15=15个日历月2016年1-12月加上2017年1月、2月、3月 我不把一个月定义为“30天”。我问的

对于从一个日期到另一个日期的时间跨度,如何获取包含我的跨度中的一天或多天的日历月数

例如:

2016-01-23/2016-01-23=1个日历月1月 2016-01-31/2016-02-01=2个日历月1月、2月 2016-01-23/2016-02-28=2个日历月1月、2月 2016-01-15/2016-03-15=3个日历月1月、2月、3月 2016-01-15/2017-03-15=15个日历月2016年1-12月加上2017年1月、2月、3月 我不把一个月定义为“30天”。我问的是日历月份,一月到十二月

与此类似,但这会询问PHP/MySQL。

调整开始和结束日期 关键是调整日期

将开始日期移到每月的第一天 将结束日期移到下个月的第一个月 我们将结束时间移到下个月,因为在考虑时间跨度时,通常使用半开放方法。半开放意味着开始是包含的,而结束是独占的。因此,午餐时间从12:00到13:00,但不包括下午1点的第61分钟。一周从周一到周一,持续七天,不包括第二个周一

所以从1月1日到3月1日的时间跨度是两个月,而不是三个月,因为我们一直到,但不包括,最后一天,3月1日

java.time java 8和更高版本中内置的java.time类使这方面的工作更容易

对于仅日期的值,如果没有一天中的某个时间和时区,请使用类

要调整,请使用。实现可以在类注释中找到复数“s”。我们需要和

现在,使用该类计算经过的整个月份

long calendarMonthsTouched = ChronoUnit.MONTHS.between( startAdjusted , stopAdjusted );
跨度:2016-01-31/2016-02-01

日历月数:2


见此。

计算两个日期的纪元月份,然后减去它们并加1

与另一个答案中一样,使用LocalDate,epochMonth帮助器方法可以简化:

private static int monthsTouched(LocalDate fromDate, LocalDate toDate) {
    return epochMonth(toDate) - epochMonth(fromDate) + 1;
}
private static int epochMonth(LocalDate date) {
    return date.getYear() * 12 + date.getMonthValue();
}
与问题中的结果一样,两个日期都包含在内

注意:为简洁起见跳过验证,例如,如果fromDate>toDate,结果是什么

试验

输出匹配问题的结果

1. 2. 2. 3. 15 使用ChronoField.PROLEPTIC_MONTH,它返回从零年开始的月份计数:

import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;

long monthsTouched = date2.getLong(PROLEPTIC_MONTH) - date1.getLong(PROLEPTIC_MONTH) + 1;

隐马尔可夫模型。。。询问并立即回答您自己的问题。您正在尝试记录如何执行此操作。如果是这样的话,这一部分不是更好吗?这不是他们创建它的原因吗?@Andreas是的,我在回答我自己的问题,作为一种在公共场合记录这些知识的方式,以便包括我在内的其他人以后可以找到它……当然,但我确实认为,鼓励早于新的文档部分。现在,如果你问了一个问题,得到了一个或多个答案,但没有一个是完全正确的,但你从中找到了真正的答案,回答你自己的问题肯定是个好主意。@Andreas这可能是你关于回答自己问题的意见,但这不是堆栈溢出管理的策略。您没有注意到堆栈溢出问题提交页面中内置的“回答您自己的问题”复选框吗?!!如果您希望更改堆栈溢出策略,请与他们(而不是我)联系。如果日期在不同的年份,是否希望月数能够超过12?还是只显示不同月份名称的数量?@Enwired我添加了最后一个示例,以显示可以远远超过12个的已用月份总数,而不是日历中的不同月份计数(通常为12个或更少)。这个问题是否经常被问到,以至于您认为此示例将帮助其他人?我对此表示怀疑,因为您声明没有为Java明确提出这样的问题。你是在找免费的销售代表还是什么?我对规范问题没有异议,但我不需要这个问题。@nhouser9请引用堆栈溢出的策略声明,它只允许常见问题。第二,今天问到数月的问题。在试图推断他们的意图时,我意识到至少有三个月的定义,一个是完整的日历月,另一个是30天的组,第三个是部分日历月。我搜索了第三个,找到了其他语言的帖子,但没有找到Java。如果你找到一个dup,引用它,我将自己结束这个问题。@BasilBourque显然你可以问一个不常见的问题。但我不认为有必要提出一个不常被问到或从未被问过的规范性问题。只是我的意见,回答得好。在内部使用相同机制的另一个解决方案是使用两个YearMonth实例,并在几个月加上一个月内确定增量。
private static int monthsTouched(LocalDate fromDate, LocalDate toDate) {
    return epochMonth(toDate) - epochMonth(fromDate) + 1;
}
private static int epochMonth(LocalDate date) {
    return date.getYear() * 12 + date.getMonthValue();
}
public static void main(String[] args) {
    test("2016-01-23", "2016-01-23");
    test("2016-01-31", "2016-02-01");
    test("2016-01-23", "2016-02-28");
    test("2016-01-15", "2016-03-15");
    test("2016-01-15", "2017-03-15");
}
private static void test(String fromDate, String toDate) {
    System.out.println(monthsTouched(LocalDate.parse(fromDate), LocalDate.parse(toDate)));
}
import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;

long monthsTouched = date2.getLong(PROLEPTIC_MONTH) - date1.getLong(PROLEPTIC_MONTH) + 1;