Reputation: 157
I am having fromDate
as "01-Jan-2015"
and toDate
as "01-Apr-2015"
. I want to find number of quarters between fromDate
and toDate
. My code is like
String fromDate = "01-Jan-2015";
String toDate = "01-Apr-2015";
ArrayList<String> quarters = new ArrayList<String>();
DateFormat df = new SimpleDateFormat("dd-MMM-yyyy");
DateFormat dfYY = new SimpleDateFormat("yy");
Calendar cal = Calendar.getInstance();
cal.setTime(df.parse(fromDate));
Calendar cal1 = Calendar.getInstance();
cal1.setTime(df.parse(toDate));
while (cal1.getTime().after(cal.getTime())) {
int month = cal.get(Calendar.MONTH) + 1;
int quarter = month % 3 == 0 ? (month / 3) : (month / 3) + 1;
quarters.add("Q" + quarter + "-" + dfYY.format(cal.getTime()));
cal.add(Calendar.MONTH, 3);
}
But it is giving output as Q1-15, Q2-15 is missing. If I enter toDate
as"02-Apr-2015" then it is giving Q1-15, Q2-15. Please help me where I am going wrong.
Upvotes: 4
Views: 4587
Reputation: 44061
IsoFields.QUARTER_YEARS
A special unit exists for this purpose in Java 8 and later: java.time.temporal.IsoFields.QUARTER_YEARS
implementing TemporalUnit
and its between
method.
long delta =
IsoFields.QUARTER_YEARS.between(
LocalDate.of(2015, 1, 1),
LocalDate.of(2015, 4, 1));
System.out.println(delta); // 1
Upvotes: 5
Reputation: 1
Try these methods , Worked for me
public int getQuartersBetweenDates(Date startDate, Date endDate) {
int numofquarters=0;
String[] yearquarter=null;
Date temp=startDate;
String[] targetYearQuarter= getYearQuarter(endDate);
if(endDate.after(startDate)){
yearquarter=getYearQuarter(temp);
while(!(targetYearQuarter[0].equalsIgnoreCase(yearquarter[0])
&& targetYearQuarter[1].equalsIgnoreCase(yearquarter[1]))){
yearquarter=addQuarters(1,yearquarter[0],yearquarter[1]);
numofquarters++;
}
}
else{
yearquarter=getYearQuarter(temp);
while(!(targetYearQuarter[0].equalsIgnoreCase(yearquarter[0])
&& targetYearQuarter[1].equalsIgnoreCase(yearquarter[1]))){
yearquarter=addQuarters(-1,yearquarter[0],yearquarter[1]);
numofquarters--;
}
}
return numofquarters;
}
public String[] addQuarters(int numofQuarters,String year,String quarter){
int tempyear=Integer.parseInt(year)+(numofQuarters/4);
int tempquarter=Integer.parseInt(quarter.replace("Q",""))+(numofQuarters%4);
if(tempquarter>4){
tempquarter=tempquarter-4;
tempyear+=1;
}
if(tempquarter<1){
tempquarter=tempquarter+4;
tempyear-=1;
}
year=String.valueOf(tempyear);
quarter="Q"+tempquarter;
return new String[]{year,quarter};
}
Upvotes: 0
Reputation: 338181
UPDATE See the Answer by Meno Hochschild for a much simpler shorter solution.
I leave my Answer here to demonstrate the YearQuarter
class that is likely to be handy in related work.
Much easier with the modern java.time classes rather than the troublesome old date-time classes. Those old classes are now legacy.
This Answer assumes by “quarter” you mean the standard ISO 8601 quarters, the first, second, third, and fourth groups of three months across the calendar year.
The LocalDate
class represents a date-only value without time-of-day and without time zone.
LocalDate start = LocalDate.of ( 2015 , Month.JANUARY , 1 );
LocalDate stop = LocalDate.of ( 2015 , Month.APRIL , 1 );
YearQuarter
Add the ThreeTen-Extra project library to your project to access the YearQuarter
class.
Get start and stop quarters of your dates.
YearQuarter yqStart = YearQuarter.from ( start );
YearQuarter yqStop = YearQuarter.from ( stop );
Loop one quarter at a time until reaching the limit.
The code here bases the loop on the Half-Open approach to defining a span of time, commonly used in date-time work. The beginning is inclusive while the ending is exclusive. I recommend using this approach consistently throughout your logic to avoid ambiguity, confusion, and errors. If instead you insist on the Closed approach (both beginning and ending are inclusive), change the while
test to “while not after”, while( ! yq.isAfter( yqStop ) )
.
int initialCapacity = ( int ) ( ( ChronoUnit.MONTHS.between ( start , stop ) / 3 ) + 3 ); // Probably `+1` is good enough, but I've not thought it through.
List<YearQuarter> yqs = new ArrayList<> ( initialCapacity );
YearQuarter yq = yqStart;
while ( yq.isBefore ( yqStop ) ) { // Using Half-Open approach where the beginning is *inclusive* while the ending is *exclusive*.
yqs.add ( yq ); // Collect this quarter.
// Set up next loop.
yq = yq.plusQuarters ( 1 ); // Move to next quarter.
}
Dump to console.
System.out.println ( "start/stop: " + start + "/" + stop );
System.out.println ( "yqStart/yqStop: " + yqStart + "/" + yqStop );
System.out.println ( "yqs: " + yqs );
start/stop: 2015-01-01/2015-04-01
yqStart/yqStop: 2015-Q1/2015-Q2
yqs: [2015-Q1]
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.
Upvotes: 2
Reputation: 801
while (cal1.getTime().after(cal.getTime()))
As soon as cal1.getTime()
is "01-Apr-2015" it isnt "after" cal.getTime()
anymore so the while loop will stop.
Thats why it doesnt make the last iteration which would give you the last Quarter.
you could go like:
while (cal1.getTime().after(cal.getTime()) || cal1.getTime().equals(cal.getTime()))
Upvotes: 2
Reputation: 2863
On the first iteration of the loop, you increment fromDate by three months. This makes it equal to toDate, so you don't get another iteration.
You need
(cal1.getTime().after(cal.getTime())||(cal1.getTime().equals(cal.getTime())
Upvotes: 0