如何在Java中生成季度日期序列?

时间:2017-12-01 21:23:49

标签: java r date java-date

我正在尝试在Java中创建一个函数,该函数在给定开始日期和结束日期的情况下生成季度日期序列。

例如,在R中,我可以这样做:

generateQuarterlySequence = function(startDate, endDate)
{
  require(zoo)

  # Generate date sequence
  dateSequence = seq.Date(from = as.Date(startDate), 
                          to = as.Date(endDate), 
                          by = "quarter")

  # Convert to quarters
  dateSequence = as.yearqtr(dateSequence, format = "%Y-%m-%d") 

  # Get rid of extra white space
  dateSequence = gsub(" ", "", dateSequence) 

  return(dateSequence)

}

generateQuarterlySequence(startDate = "2017-06-30", endDate = "2017-12-31")
[1] "2017Q2" "2017Q3" "2017Q4"

任何摇滚明星都在关注如何在Java中完成这项工作?你会让这个Java初学者非常开心!

干杯, 乔

4 个答案:

答案 0 :(得分:4)

我知道在评论中我建议ThreeTen-Extra。但是,这是一个使用纯mel.eval("catchQuiet(`python(\"cmds.file('/drive/myfile.obj', i=1)\")`)") 作为内置于Java 8及更高版本的解决方案,可通过ThreeTen Backport在Java 6和7中使用。

java.time

使用您的示例参数尝试:

public static List<String> generateQuarterlySequence(LocalDate startDate, LocalDate endDate) {
    // first truncate startDate to first day of quarter
    int startMonth = startDate.getMonthValue();
    startMonth-= (startMonth - 1) % 3;
    startDate = startDate.withMonth(startMonth).withDayOfMonth(1);

    DateTimeFormatter quarterFormatter 
            = DateTimeFormatter.ofPattern("uuuuQQQ", Locale.ENGLISH);
    List<String> quarterSequence = new ArrayList<>();

    // iterate thorough quarters
    LocalDate currentQuarterStart = startDate;
    while (! currentQuarterStart.isAfter(endDate)) {
        quarterSequence.add(currentQuarterStart.format(quarterFormatter));
        currentQuarterStart = currentQuarterStart.plusMonths(3);
    }
    return quarterSequence;
}

打印

    System.out.println(generateQuarterlySequence(LocalDate.of(2017, Month.JUNE, 30),
            LocalDate.of(2017, Month.DECEMBER, 31)));

答案 1 :(得分:2)

TL;博士

YearQuarter.from( LocalDate.parse( "2017-06-30" ) )
           .plusQuarters( 1 )

org.threeten.extra.YearQuarter

使用java.time的其他Answer by Ole V.V.很好。或者,这里是使用YearQuarter项目中的ThreeTen-Extra类的代码,该类扩展了具有附加功能的java.time。如果您在宿舍中做了很多工作,您会发现将ThreeTen-Extra库添加到您的项目中是值得的。

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

LocalDate start = LocalDate.parse( "2017-06-30" );
LocalDate stop = LocalDate.parse( "2017-12-31" );

根据这些,确定ISO 8601日历系统中的年度季度,意味着Q1是1月到3月,Q2是4月到6月,Q3是7月到9月,Q4是10月到12月。

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

将一系列季度收集为List

int initialCapacity = ( int ) ( ChronoUnit.YEARS.between( start , stop ) + 1 ) * 4;
List < YearQuarter > quarters = new ArrayList <>( initialCapacity );

每个季度循环,通过调用plusQuarters递增,并收集到列表中。

YearQuarter yq = yqStart;
while ( ! yq.isAfter( yqStop ) )
{
    quarters.add( yq );
    // Setup next loop.
    yq = yq.plusQuarters( 1 );
}

转储到控制台。

System.out.println( start + "/" + stop + " = " + quarters );
  

2017-06-30 / 2017-12-31 = [2017-Q2,2017-Q3,2017-Q4]

关于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

答案 2 :(得分:2)

我的库Time4J支持使用Java-8的流式API实现非常简单的解决方案:

DateInterval range = 
    DateInterval.between(
        PlainDate.of(2017, 6, 30),
        PlainDate.of(2017, 12, 31)
    );
range.stream(Duration.of(1, CalendarUnit.QUARTERS))
    .map(CalendarQuarter::from)
    .forEach(System.out::println);

// 2017-Q2
// 2017-Q3
// 2017-Q4

代码首先构造一个可流传输的date interval。您可以通过迭代地将四分之一年添加到间隔的开始日期来定义流。 map-operation将流中生成的(格里高利)日期映射到Time4J中所需的年度季度,称为CalendarQuarter,最后调用其toString()方法生成输出。

如果您希望消除输出中的连字符,则可以在另一个map方法中应用简单的string-replace-method或使用合适的formatter(最好将其存储在静态常量中它是不可改变的):

ChronoFormatter<CalendarQuarter> f =
  ChronoFormatter.ofPattern(
      "uuuuQQQ", PatternType.CLDR, Locale.ROOT, CalendarQuarter.chronology());
range.stream(Duration.of(1, CalendarUnit.QUARTERS))
    .map(CalendarQuarter::from)
    .map(cq -> f.format(cq))
    .forEach(System.out::println);

// 2017Q2
// 2017Q3
// 2017Q4

最后一段代码甚至可以通过省略中间类型CalendarQuarter来简化,因为格里高利日期(此处:PlainDate)也可以以相同的方式格式化为季度日期(一张地图) - 操作少)。

答案 3 :(得分:1)

这里是使用纯Java 8流和java.time api的解决方案:

public static void main(String[] args) {
    LocalDate startDate = LocalDate.of(2000, 12, 25);
    LocalDate endDate = LocalDate.of(2002, 4, 1);
    Stream<LocalDate> quarterBounds = Stream.iterate(
            startDate.with(IsoFields.DAY_OF_QUARTER, 1), date -> date.plus(3, MONTHS));

    DateTimeFormatter quarterFormatter = 
            DateTimeFormatter.ofPattern("uuuuQQQ", Locale.ENGLISH);
    quarterBounds
            .filter(d -> !endDate.isBefore(d))
            .peek(System.out::println)
            .map(quarterFormatter::format)
            .forEach(System.out::println);
}

样本输出:

2000-10-01
2000Q4
2001-01-01
2001Q1
2001-04-01
2001Q2
2001-07-01
2001Q3
2001-10-01
2001Q4
2002-01-01
2002Q1
2002-04-01
2002Q2

通过How to get the first date and last date of current quarter in java.util.Date