如何在Java中获取两个日期之间的季度数?

4

我有一个fromDate变量,值为"2015年1月1日",还有一个toDate变量,值为"2015年4月1日"。我想要计算出两个日期之间的季度数。我的代码如下:


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);
            }


但它的输出是Q1-15,Q2-15没有出现。如果我将 toDate 输入为 "02-Apr-2015",那么它就会输出 Q1-15,Q2-15。请帮助我找到我的错误所在。
5个回答

3

IsoFields.QUARTER_YEARS

Java 8及其以后版本中提供了一个专门的单位:java.time.temporal.IsoFields.QUARTER_YEARS,它实现了TemporalUnit和其between方法,用于处理此类情况。

long delta = 
    IsoFields.QUARTER_YEARS.between(
        LocalDate.of(2015, 1, 1), 
        LocalDate.of(2015, 4, 1));
System.out.println(delta); // 1

2
while (cal1.getTime().after(cal.getTime()))

cal1.getTime()变成"01-Apr-2015"时,它不再是在cal.getTime()之后,所以while循环会停止。这就是为什么它不能进行最后一次迭代,从而无法得到最后一个季度。

你可以这样做:

while (cal1.getTime().after(cal.getTime()) || cal1.getTime().equals(cal.getTime()))

2
更新:请参阅Meno Hochschild的答案,以获取更简单、更短的解决方案。
我在这里留下我的回答,以演示可能在相关工作中有用的YearQuarter类。
使用java.time 现代java.time类比旧的日期时间类更容易处理。那些旧的类现在已经过时了。
本答案假定“季度”是指标准的ISO 8601季度,即每年的第一、第二、第三和第四个三个月组成的季度。
LocalDate类表示仅具有日期值而没有时间和时区的值。
LocalDate start = LocalDate.of ( 2015 , Month.JANUARY , 1 );
LocalDate stop = LocalDate.of ( 2015 , Month.APRIL , 1 );

YearQuarter

ThreeTen-Extra项目库添加到您的项目中,以访问YearQuarter类。

获取日期的开始和结束季度。

YearQuarter yqStart = YearQuarter.from ( start );
YearQuarter yqStop = YearQuarter.from ( stop );

每次循环一季度,直到达到限制。

此处的代码基于“半开放”方法来定义时间跨度,这在日期时间工作中常用。开始是“包含”的,而结束是“不包含”的。我建议您在整个逻辑中始终使用这种方法,以避免歧义、混淆和错误。如果您坚持使用“闭合”方法(开始和结束都是包含的),请将while测试改为“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.
}

转储到控制台。
System.out.println ( "start/stop: " + start + "/" + stop );
System.out.println ( "yqStart/yqStop: " + yqStart + "/" + yqStop );
System.out.println ( "yqs: " + yqs );

开始/结束:2015年1月1日/2015年4月1日 yqStart/yqStop:2015年第一季度/2015年第二季度 yqs:[2015年第一季度]
关于java.time Java 8及更高版本内置了java.time框架。这些类取代了老旧的传统日期时间类,如java.util.DateCalendarSimpleDateFormatJoda-Time项目现在处于维护模式,建议迁移到java.time类。
要了解更多信息,请查看Oracle教程。并在Stack Overflow上搜索许多示例和解释。规范是JSR 310
如何获取java.time类? 该项目扩展了java.time的功能,称为ThreeTen-Extra。该项目是java.time可能未来添加的类的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuarter更多

太麻烦使用while循环或下载另一个库,看看我的答案。 - Meno Hochschild
确实,您的答案(https://dev59.com/Y4nca4cB1Zd3GeqP6iLj#42408143)更好,简短而精炼。 - Basil Bourque

0

尝试这些方法,对我有用

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};
}

0
在循环的第一次迭代中,您将fromDate增加了三个月。这使得它等于toDate,因此您不会再进行另一个迭代。
您需要
(cal1.getTime().after(cal.getTime())||(cal1.getTime().equals(cal.getTime())


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接