Domanda

My input is a beginning date and an end date. And I want to check that it is between December 1 and March 31. (The year can change, and there will be only dates in, or dates outside this period).

So far I didn't found any solution with Joda-time. Can somebody give me a starting point how to do(not code, just the logic)? I didn't checked the code yet, but it is VERY Ugly, and I want to find an algorithmic solution

public static boolean isInWinter(Contract contract) {
    logger.info("begin isInWinter:");
    DateTime beginDate = contract.getBeginningDate();
    DateTime endDate = contract.getEndDate();
    /*
     * If the year is different (etc 2012 dec,2013 marc) check that the
     * beginning month is december, and the end month is jan,feb,marc
     */
    if (endDate.getYear() - beginDate.getYear() == 1) {
        if ((beginDate.getMonthOfYear() == 12)
                && ((endDate.getMonthOfYear() == 1
                        || endDate.getMonthOfYear() == 2 || endDate
                        .getMonthOfYear() == 3))) {
            logger.info("return true different year");
            return true;
        }
        /*
         * Same year can be if begin and end date is december or begin and
         * and date is jan,febr,marc TODO REMOVE Auto formatter
         */
    } else if (endDate.getYear() - beginDate.getYear() == 0) {
        if ((beginDate.getMonthOfYear() == 12 && endDate.getMonthOfYear() == 12)
                || ((beginDate.getMonthOfYear() == 1
                        || beginDate.getMonthOfYear() == 2 || beginDate
                        .getMonthOfYear() == 3) && (endDate
                        .getMonthOfYear() == 1
                        || endDate.getMonthOfYear() == 2 || endDate
                        .getMonthOfYear() == 3))) {
            logger.info("return true same year");
            return true;
        }

    }
    logger.info("return false");
    return false;
}
È stato utile?

Soluzione

Joda-Time

Joda-Time and its Interval class with the overlap method is just what you need. Very easy.

Time Zone

Unlike java.util.Date, a DateTime truly knows its assigned time zone. Generally better to specify than rely on default. Note that if you are tracking date+time (a DateTime rather than a LocalDate), then time zone is critical. The definition of a "day" beginning and ending depends on time zone. Businesses that work across time zones may choose to use UTC for this purpose.

Span of Time

FYI, besides Interval, Joda-Time also offers the Period and Duration classes for working with a span of time.

Start of Day

When working with date-time values but focusing on a "day", then adjust the time portion to the first moment of the day for that particular time zone. In Joda-Time, simply call the withTimeAtStartOfDay method.

Avoid the "midnight"-related classes and methods. They are no longer recommended by the Joda-Time team.

Half-Open

Joda-Time uses the "Half-Open" approach when comparing spans of time. The beginning in inclusive and the ending is exclusive. That means since you want from December 1 to March 31 that we define an Interval of the first moment of the day of December 1 to the first moment of the day of April 1. If you ponder this, and search StackOverflow for other postings on "joda interval", you'll come to see the wisdom of this approach.

Comparison

The Interval class offers handy comparison methods: contains, abuts, overlap, and gap. Be sure to read the doc to understand exact details.

java.time

Java 8 brings the new java.time package, inspired by Joda-Time, defined by JSR 310. Joda-Time continues to work in Java 8, but you may want to learn java.time rather than Joda-Time if you are new to date-time work.

Example Code

DateTimeZone timeZone = DateTimeZone.forID( "Europe/Budapest" ); // Or, perhaps DateTimeZone.UTC

// Inputs
DateTime contractStart = new DateTime( 2014, 1, 2, 0, 0, 0, timeZone );
DateTime contractStop = new DateTime( 2014, 5, 6, 0, 0, 0, timeZone );
Interval contractInterval = new Interval( contractStart, contractStop );

// Target to test
DateTime targetStart = new DateTime( 2013, DateTimeConstants.DECEMBER, 1, 0, 0, 0, timeZone );
DateTime targetStop = targetStart.plusMonths( 4 );
Interval targetInterval = new Interval( targetStart, targetStop );

boolean targetContainsContract = targetInterval.contains( contractInterval );
boolean targetOverlapsContract = ( targetInterval.overlap( contractInterval ) != null );

Dump to console…

System.out.println( "contractInterval: " + contractInterval );
System.out.println( "targetInterval: " + targetInterval );
System.out.println( "targetContainsContract: " + targetContainsContract );
System.out.println( "targetOverlapsContract: " + targetOverlapsContract );

When run…

contractInterval: 2014-01-02T00:00:00.000+01:00/2014-05-06T00:00:00.000+02:00
targetInterval: 2013-12-01T00:00:00.000+01:00/2014-04-01T00:00:00.000+02:00
targetContainsContract: false
targetOverlapsContract: true

Altri suggerimenti

Create an interval with the beginning and end date you get as inputs.

Create an interval going from March to December.

Your condition is true if either:

  • the march to december interval entirely contains the input interval,
  • or there is no overlap between the two intervals.

In code that would be:

marchToDecember.contains(interval) || marchToDecember.overlap(interval) == null

Javadàoc for Interval

Since you mention that the dates will be either both in or both out the period, you'll only need to test one of them.

So just test whether beginDate.getMonthOfYear() returns either 12, 1, 2 or 3.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top