小于或等于GregorianCalendar

时间:2014-02-05 15:05:15

标签: java gregorian-calendar

我的程序中有这个代码:

if (expire.after(start) && expire.before(end))
    //do somethig

但是这段代码不包括约束日。 我的意思是例如,如果开始是2014/01/15,结束是2014/01/20并且到期是2014/01/20,则不考虑到期。怎么解决?

我试过这样的方式:

if (expire.after(start) && (expire.equals(end) || expire.before(end)))

但它不起作用,我得到了相同的结果。

5 个答案:

答案 0 :(得分:1)

当我过去做过时间检查时,我总是只使用afterbefore,即使我的范围检查是开始< = current< = end。

您可以通过调整开始日期和结束日期以使其超出所需范围的范围来实现此目的。

例如,如果开始日期是2014/01/15,则使用2014/01/14 23:59:59的开始日期值作为用于比较的实际开始日期。对于结束日期,请使用2014/01/21 00:00:00而不是2014/01/20。使用这些值,您可以使用.after(startDate)和.before(endDate)。

以下是一些计算开始日期的代码:

    private static Date calculateStartDate(
        final int year,
        final int month,
        final int dayOfMonth)
    {
        Calendar calendar = Calendar.getInstance();
        Date returnValue;

        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month);
        calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
        calendar.set(Calendar.HOUR, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);

        returnValue = calendar.getTime();

        return returnValue;
    }

编辑在毫秒上方添加

答案 1 :(得分:1)

正如@assylias所说,你可能会尝试!expire.after(end),尽管这可能还不够。如果您改为使用expire.equals(end),那么您必须记住,这不仅仅是时间比较!在这里,您还可以比较时区信息,甚至是区域设置等。通常,仅使用GregorianCalendar进行日期比较是不好的,因为此类型也知道毫秒作为时间部分。因此,您可能要么手动将所有三个日历实例的整个时间部分设置为零(午夜,在某些日子省略时间区域中的时区异常)或更好,您应该提取日期信息并通过以下方式比较这些详细信息:使用以下工具:

public class DateComparator implements Comparator<GregorianCalendar> {
  public int compare(GregorianCalendar gcal1, GregorianCalendar gcal2) {
    int y1 = gcal1.get(Calendar.YEAR);
    int y2 = gcal2.get(Calendar.YEAR);
    if (y1 != y2) {
       return y1 - y2;
    }

    int m1 = gcal1.get(Calendar.MONTH);
    int m2 = gcal2.get(Calendar.MONTH);
    if (m1 != m2) {
       return m1 - m2;
    }
    return gcal1.get(Calendar.DATE) - gcal2.get(Calendar.DATE);
  }
}

但请确保在比较日期部分时始终拥有相同的时区。 否则,您可以尝试提供类型LocalDate的JodaTime。新Java 8中也包含类似的仅日期类型。

答案 2 :(得分:0)

或者

if ((expire.compareTo(start) >= 0) && (expire.compareTo(end) <= 0))

因为

http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html#after(java.lang.Object)

说.before相当于compareTo(when)&lt; 0和.after相当于compareTo(when)&gt; 0

答案 3 :(得分:0)

我终于解决了调整开始和结束日期,使它们超出了所需范围的界限。

例如,如果开始日期是2014/01/15,我将其设置为2014/01/14,如果结束日期是2014/01/20,我将其设置为2014/01/21。使用这些值,我可以使用.after和.before方法,没有任何问题。

感谢DwB的建议,感谢大家的支持!

答案 4 :(得分:0)

TL;博士

使用java.time.LocalDate获取仅限日期的值。

( ! ( myLocalDate.isBefore( start ) )   // Is target date NOT before the start (meaning, is the target equal to or later than
&& 
myLocalDate.isBefore( stop )

...或者,更好:

org.threeten.extra.LocalDateRange.of(            // Half-Open range.
    LocalDate.of( 2014 , Month.JANUARY , 15 ) ,  // Inclusive.
    LocalDate.of( 2014 , Month.JANUARY , 20 )    // Exclusive.
).contains(
    LocalDate.of( 2014 , Month.JANUARY , 11 )
)
  

GregorianCalendar是一个麻烦的过时类。避免它。

详细

我不了解您的业务问题的逻辑,但也许这个示例代码会有所帮助。

我相信你会发现在“半开放式”方法中使用时间跨度效果最佳。跨度的开始是包含的,结尾是独占的。有关更多讨论,请参阅another answer of mine此图表...

enter image description here

java.time

以下是使用Java 8及更高版本中内置的现代 java.time 类的一些代码。

LocalDate

LocalDate类表示没有时间且没有时区的仅限日期的值。

时区对于确定日期至关重要。对于任何给定的时刻,日期在全球范围内因地区而异。例如,在Paris France午夜后的几分钟是新的一天,而Montréal Québec中仍然是“昨天”。

如果未指定时区,则JVM会隐式应用其当前的默认时区。该默认值可能随时更改,因此您的结果可能会有所不同。最好明确指定您期望/预期的时区作为参数。

continent/region的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用诸如ESTIST之类的3-4字母缩写,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "America/Montreal" ) ;  
LocalDate today = LocalDate.now( z ) ;

如果要使用JVM的当前默认时区,请求它并作为参数传递。如果省略,则隐式应用JVM的当前默认值。最好是明确的,因为默认情况下可以在运行时期间由JVM中任何应用程序的任何线程中的任何代码随时更改

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.

或指定日期。您可以将月份设置为一个数字,1月至12月的数字为1-12。

LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ;  // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.

或者,更好的是,使用预定义的Month枚举对象,一年中的每个月一个。提示:在整个代码库中使用这些Month对象,而不仅仅是整数,以使代码更具自我记录功能,确保有效值,并提供type-safety

LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;

比较日期

LocalDate类提供了比较方法:isBeforeisAfterisEqualequalscompareTo

从您的问题中不完全确定您的比较规则是什么。但我猜你错过了使用!运算符来表示“NOT”条件的概念。

使用半开放式方法,我们想询问目标日期“是否等于或晚于结束时间”。

LocalDate start = LocalDate.of( 2014 , Month.JANUARY , 15 ) ;
LocalDate stop = LocalDate.of( 2014 , Month.JANUARY , 20 ) ;

boolean rangeContainsTarget = ( ld.isEqual( start ) || (ld.isAfter( start ) ) && ld.isBefore( stop ) ;  // Half-Open test, the long-way. "is equal to or later than the beginning AND before than ending"

要求“等于或晚于”的较短方式是“不在之前”。

boolean rangeContainsTarget = ( ! ( ld.isBefore( start ) ) && ld.isBefore( stop ) ;  // Half-Open test, the long-way. "is not before the beginning AND before than ending"

范围对象

ThreeTen-Extra库添加到项目中以访问LocalDateRange类。它将一系列时间定义为一对LocalDate个对象。该课程提供了方便的方法,例如abutscontainsintersection等。它使用半开放式方法。

LocalDateRange range = LocalDateRange.of( start , stop ) ;
boolean rangeContainsTarget = range.contains( target ) ;

关于 java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和&amp; SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore


约达时间

更新 Joda-Time项目现在位于maintenance mode,团队建议迁移到java.time课程。这部分保留了完整的历史记录。

使用Joda-Time 2.3库查看此代码。

// Specify a time zone rather than rely on default.
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Oslo" );

DateTime event = new DateTime( 2014, 1, 20, 23, 59, 59, timeZone );

DateTime begin = new DateTime( 2014, 01, 15, 0, 0, 0, timeZone ); // Inclusive
// After the stroke of midnight of the 20th, on the first moment of the new day (the 21st), event is late.
DateTime end = new DateTime( 2014, 01, 21, 0, 0, 0, timeZone ); // Exclusive. All split-second moments before this are acceptable, but this moment and onwards is not acceptable.

Interval interval = new Interval( begin, end );
boolean isEventOnSchedule = interval.contains( event );

转储到控制台...

System.out.println( "event: " + event );
System.out.println( "begin: " + begin );
System.out.println( "end: " + end );
System.out.println( "interval: " + interval );
System.out.println( "isEventOnSchedule: " + isEventOnSchedule );

跑步时......

event: 2014-01-20T23:59:59.000+01:00
begin: 2014-01-15T00:00:00.000+01:00
end: 2014-01-21T00:00:00.000+01:00
interval: 2014-01-15T00:00:00.000+01:00/2014-01-21T00:00:00.000+01:00
isEventOnSchedule: true