0

I have two dates:

Start Date: 2017-01-15
End Date: 2017-05-27

Now I want to find the whole month between these two dates. So the result should be:

Feb-2017
Mar-2017
Apr-2017

January is not included in the result because start date starts from the middle of the month and May is not included because end date does not cover whole May month.

How can I achieve this with Java?

I have tried doing something like:

String date1 = "2015-01-15";
String date2 = "2015-05-27";

DateFormat formater1 = new SimpleDateFormat("MMM-yyyy");
DateFormat formater = new SimpleDateFormat("yyyy-MM-dd");

Calendar startCalendar = Calendar.getInstance();
Calendar endCalendar = Calendar.getInstance();

try {
    startCalendar.setTime(formater.parse(date1));
    endCalendar.setTime(formater.parse(date2));
} catch (ParseException e) {
    e.printStackTrace();
}

System.out.println("startDate:" + startCalendar.getTime());
System.out.println("endCalendar:" + endCalendar.getTime());

while (startCalendar.before(endCalendar)) {
    // add one month to date per loop
    String date = formater1.format(startCalendar.getTime()).toUpperCase();
    System.out.println(date);
    startCalendar.add(Calendar.MONTH, 1);
}

But I don't know how to exclude Jan and May from the result. Currently, I am getting this result:

JAN-2015
FEB-2015
MAR-2015
APR-2015
MAY-2015
nbrooks
  • 18,126
  • 5
  • 54
  • 66
Raj Kantaria
  • 326
  • 3
  • 12
  • I have downvoted this question because it appears to be a zero-effort requirements dump. If you can [edit] your question to show us a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) of your attempt, or to clarify *precisely* where you are having difficulty, this downvote may be retracted. – Joe C Dec 04 '17 at 06:00
  • 1
    @LalitVerma Please try to avoid answering this question until it meets the quality standards outlined in the [help]. – Joe C Dec 04 '17 at 06:13
  • Start by checking the first and last dates, find out if they provide a full month range. From there, you can simply loop from the first + 1 date to the last - 1 date... – MadProgrammer Dec 04 '17 at 06:14
  • 1
    @JoeC I appreciate your suggestion, I have edited the question. – Raj Kantaria Dec 04 '17 at 06:35
  • You are using the long outdated classes `DateFormat`, `Calendar` and `Date`. You best first step would be to throw them out and instead use [`java.time`, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). It is much nicer to work with. – Ole V.V. Dec 04 '17 at 08:50

4 Answers4

6

With the release of Java 8, Oracle dramatically overhauled their date-time libraries to make it much simpler to implement calendar logic. Check out the java.time documentation for more details. Among the supported functions are withDayOfMonth and lastDayOfMonth, which allow you to find specific dates within a given month.

Have a look at this implementation, using the java.time APIs for formatting and date manipulation:

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

import static java.time.temporal.TemporalAdjusters.lastDayOfMonth;

public class Main {

    public static void main(String[] args) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM-yyyy");

        LocalDate start = LocalDate.of(2017, 1, 15);
        LocalDate end = LocalDate.of(2017, 5, 27);
        List<String> months = new ArrayList<>();

        LocalDate date = start;
        if (date.getDayOfMonth() == 1) {
            date = date.minusDays(1);
        }

        while (date.isBefore(end)) {
            if (date.plusMonths(1).with(lastDayOfMonth()).isAfter(end)) {
                break;
            }

            date = date.plusMonths(1).withDayOfMonth(1);
            months.add(date.format(formatter).toUpperCase());
        }

        System.out.println(months);
    }

}

Output:

> [FEB-2017, MAR-2017, APR-2017]
nbrooks
  • 18,126
  • 5
  • 54
  • 66
  • 2
    Good answer. Depending on the context, an appealing variant would store `YearMonth` objects in the list and only format them in the output. – Ole V.V. Dec 04 '17 at 10:54
  • 1
    @OleV.V. That's a good suggestion too. That could look something like this for adding records to the list `months.add(YearMonth.from(date));`. And then for outputting the formatted results: `months.stream().map(month -> month.format(formatter).toUpperCase()).forEach(System.out::println)`. – nbrooks Dec 05 '17 at 22:45
  • Thanks for supplying the code in the comment, looks good. If you like, you may take it one step further and also use `YearMonth` variables to control the loop rather than `LocalDate` (then you only need to convert to `YearMonth` before the loop, not in it). – Ole V.V. Dec 06 '17 at 05:49
2

tl;dr

YearMonth.from( 
    LocalDate.parse( "2017-01-15" ) 
)
.plusMonths( 1 )
.format( DateTimeFormatter.ofPattern( "MMM-uuuu" , Locale.US ) )

Feb-2017

YearMonth

The Answer by nbrooks is good. Alternatively, we can use the YearMonth class that represents, well, the month of a year.

LocalDate startDate = LocalDate.parse( "2017-01-15" ) ;
LocalDate stopDate = LocalDate.parse( "2017-05-27" ) ;

Get the YearMonth of each.

YearMonth start = YearMonth.from( startDate ) ;
YearMonth stop = YearMonth.from( stopDate ) ;

Collect those in-between.

int initialCapacity = ( (int) ChronoUnit.MONTHS.between( startDate , stopDate ) ) + 1 ;  // Adding one for good measure - I didn't really think out this detail.
List< YearMonth > yms = new ArrayList<>( initialCapacity ) ;

Loop each incremental month.

YearMonth ym = start.plusMonths( 1 ) ;  // Add one, to *not* include the first month.
while ( ym.isBefore( stop ) ) {         // Do *not* include the last month.
    yms.add( ym ) ;
    ym = ym.plusMonths( 1 ) ;
}

Dump to console.

System.out.println("Months between " + startDate + " and " + stopDate + " = " + yms ) ;

See this code run live at IdeOne.com.

Months between 2017-01-15 and 2017-05-27 = [2017-02, 2017-03, 2017-04]

Strings

Generate a string in any format you wish to present the value of your YearMonth. The default is standard ISO 8601 format.

DateTimeFormatter f = DateTimeFormatter.ofPattern( "MMM-uuuu" , Locale.US ) ;
for( YearMonth yearMonth : yms ) {
    System.out.println( yearMonth.format( f ) ) ;
}

Feb-2017

Mar-2017

Apr-2017


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
1

I was able to solve this by the following code:

public static void main(String... strings) throws ParseException {
    String date1 = "2017-01-01";
    String date2 = "2017-05-27";

    DateFormat formater1 = new SimpleDateFormat("MMM-yyyy");
    DateFormat formater = new SimpleDateFormat("yyyy-MM-dd");

    Calendar startCalendar = Calendar.getInstance();
    Calendar endCalendar = Calendar.getInstance();

    try {
        startCalendar.setTime(formater.parse(date1));
        endCalendar.setTime(formater.parse(date2));
    } catch (ParseException e) {
        e.printStackTrace();
    }

    while (startCalendar.before(endCalendar)) {
        if (isFirstDayofMonth(startCalendar) && !(startCalendar.get(Calendar.MONTH) == endCalendar.get(Calendar.MONTH) && startCalendar.get(Calendar.YEAR) == endCalendar.get(Calendar.YEAR))) {
            String date = formater1.format(startCalendar.getTime()).toUpperCase();
            System.out.println(date);
        }
        startCalendar.set(Calendar.DATE, 1);
        startCalendar.add(Calendar.MONTH, 1);
    }
    if (isLastDayofMonth(endCalendar)) {
        String date = formater1.format(endCalendar.getTime()).toUpperCase();
        System.out.println(date);
    }

}

private static boolean isFirstDayofMonth(Calendar calendar) {
    if (calendar == null) {
        return false;
    }

    int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
    return (dayOfMonth == 1);
}

private static boolean isLastDayofMonth(Calendar calendar) {
    if (calendar == null) {
        return false;
    }

    boolean isLastDay = calendar.get(Calendar.DATE) == calendar.getActualMaximum(Calendar.DATE);
    return isLastDay;
}
Raj Kantaria
  • 326
  • 3
  • 12
  • 1
    This Answer is ill-advised, using troublesome old date-time classes that are now legacy, supplanted by the modern java.time classes. – Basil Bourque Dec 04 '17 at 15:53
0

I have written a program that is not using Months and Date formatter, I am handling all formatting manually.

public class cn {

    public enum Months {JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC}

    public static void main(String arg[]) {

        String s = "2015-01-15";
        String e = "2016-05-27";
        String s1[] = s.split("-");
        String e1[] = e.split("-");
        int syear = Integer.parseInt(s1[0]);
        int smonth = Integer.parseInt(s1[1]);
        int sday = Integer.parseInt(s1[2]);
        int fyear = Integer.parseInt(e1[0]);
        int fmonth = Integer.parseInt(e1[1]);
        int fday = Integer.parseInt(e1[0]);

        if (syear == fyear) {
            for (int i = smonth + 1; i < fmonth; i++) {
                System.out.println(Months.values()[i] + "-" + syear);
            }
        } else {
            int i = 0;

            while (syear <= fyear) {
                if (syear < fyear) {
                    for (i = smonth + 1; i < 12; i++) {
                        System.out.println(Months.values()[i] + "-" + syear);
                    }
                    i = 1;
                    syear++;
                } else {
                    for (; i < fmonth; i++) {
                        System.out.println(Months.values()[i] + "-" + syear);
                    }
                }
            }
        }
    }
}

EDIT:
Above program works for different year also.

nbrooks
  • 18,126
  • 5
  • 54
  • 66
Lalit Verma
  • 782
  • 10
  • 25