Java中两个日期之间的星期数

时间:2018-08-29 17:24:13

标签: java date datetime

我的意图是获取两个日期范围之间的星期数。第24周的日期为第24周,第35周的日期为第26周。现在的问题是,如果我将2018-08-22T12:18:06,166作为开始日期,我将得到34,35,36。我不希望在这里看到36,因为结束日期不会在36周内。任何人都可以帮助我。这个问题与此处Week numbers from start date to end date Java提供的解决方案不同。解决方案存在我最近检测到的问题

下面是获取它的代码:

public static void main(String[] args) {
    DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss','SSS");
    LocalDateTime startDate = LocalDateTime.parse("2018-08-24T12:18:06,166", format);
    LocalDateTime endDate = LocalDateTime.parse("2018-08-26T12:19:06,188", format);

    numberOfWeeks(startDate, endDate);

}

public static void numberOfWeeks(LocalDateTime startDate, LocalDateTime endDate) {
    int addWeek = 0;

    TemporalField tf = WeekFields.SUNDAY_START.weekOfYear();
    if (startDate.get(tf) < endDate.get(tf)) {
        addWeek = 1;
    }
    long weeks = WEEKS.between(startDate, endDate) + addWeek;
    List<String> numberWeeks = new ArrayList<>();
    if (weeks >= 0) {
        int week = 0;
        do {
            //Get the number of week
            LocalDateTime dt = startDate.plusWeeks(week);
            int weekNumber = dt.get(tf);
            numberWeeks.add(String.format("%d-W%d", dt.getYear(), weekNumber));
            week++;
        } while (week <= weeks);
    }
    System.out.println(numberWeeks);
}

2 个答案:

答案 0 :(得分:4)

public static void numberOfWeeks(LocalDateTime startDateTime, LocalDateTime endDateTime) {
    if (startDateTime.isAfter(endDateTime)) {
        throw new IllegalArgumentException("End date must not be before start date");
    }

    LocalDate endDate = endDateTime.toLocalDate();
    List<String> numberWeeks = new ArrayList<>();
    LocalDate currentDate = startDateTime.toLocalDate();
    while (currentDate.isBefore(endDate)) {
        numberWeeks.add(formatWeek(currentDate));
        currentDate = currentDate.plusWeeks(1);
    }
    // Now currentDate is on or after endDate, but are they in the same week?
    if (currentDate.get(WeekFields.SUNDAY_START.weekOfWeekBasedYear()) 
            == endDate.get(WeekFields.SUNDAY_START.weekOfWeekBasedYear())) {
        numberWeeks.add(formatWeek(currentDate));
    }

    System.out.println(numberWeeks);
}

public static String formatWeek(LocalDate currentDate) {
    return String.format("%d-W%d", 
            currentDate.get(WeekFields.SUNDAY_START.weekBasedYear()), 
            currentDate.get(WeekFields.SUNDAY_START.weekOfWeekBasedYear()));
}

使用问题打印中main方法上方的方法:

  

[2018-W34,2018-W35]

我看到您已忽略链接问题中的the other answer,该问题使用了ThreeTen Extra库中的YearWeek。所以我以为你不想那样做。所以我连续几周都在使用LocalDate

虽然有几个用户未能重现您的确切问题,但我确实同意问题中的代码存在缺陷。

答案 1 :(得分:3)

tl; dr

LocalDateTime.parse( "2018-08-24T12:18:06,166".replace( "," , "." ) ).toLocalDate()
.with( TemporalAdjusters.previousOrSame( DayOfWeek.SUNDAY ) )
.datesUntil(
    LocalDateTime.parse( "2018-08-26T12:19:06,188".replace( "," , "." ) ).toLocalDate()
    .with( TemporalAdjusters.previousOrSame( DayOfWeek.SUNDAY ) )
    .plusWeeks( 1 ) 
    ,
    Period.ofWeeks( 1 )
)
.map( localDate -> localDate.get( WeekFields.SUNDAY_START.weekOfWeekBasedYear() ) )
.collect( Collectors.toList() )
.toString()
  

[34,35]

让我们采用correct Answer by Ole V.V.中显示的WeekFields的想法,但是使用Java Stream技术来缩短代码。尽管很有趣,但我不一定推荐这种方法。

首先解析您的输入字符串以获取LocalDate对象。 LocalDate类表示没有日期和时区的仅日期值。

不幸的是, java.time 类无法将逗号作为小数秒定界符来支持,而是期望使用句点(FULL STOP)。这与ISO 8601标准相反,该标准同时允许和实际上 prefers 逗号。这是我在本来很好的 java.time 类中发现的少数缺陷之一,可能是由于美国程序员的偏见。为了解决此缺陷,我们用“ FULL STOP”代替逗号。

LocalDate inputDateStart = 
    LocalDateTime.parse( 
        "2018-08-24T12:18:06,166".replace( "," , "." )  // Unfortunately, the *java.time* classes fail to support the comma and instead only period. This runs contrary to the ISO 8601 standard which allows both and prefers comma.
    )
    .toLocalDate()
;  
LocalDate inputDateStop = 
    LocalDateTime.parse( 
        "2018-08-26T12:19:06,188".replace( "," , "." ) 
    )
    .toLocalDate()
;

您要使用定义为从星期日开始的星期。因此,将输入日期调整为该日期或该日期之前的星期日。

请注意,在这里我们要增加一个星期的时间来满足课题的需求。更常见的是,我们将进行此加法操作,以遵循“半开”方法来定义时间范围,其中开始时间为包含,而结束时间为排他。与“半开式”相比,“问题”显然希望采用“全闭式”方法,其中开始和结束都包括在内(我不建议这样做)。

LocalDate start = inputDateStart.with( 
    TemporalAdjusters.previousOrSame( DayOfWeek.SUNDAY ) 
);
LocalDate stop = inputDateStop.with( 
    TemporalAdjusters.previousOrSame( DayOfWeek.SUNDAY ) 
)
.plusWeeks( 1 )  // Add one to suit the Question, whereas commonly in date-time work we would have used Half-Open logic.
;  

将一系列日期定义为Stream< LocalDate >。通过一周的Period,我们一次跳了一周。

Stream< LocalDate > stream = 
    startDate
    .datesUntil( 
        stopDate , 
        Period.ofWeeks( 1 ) 
    )
;

如果需要,可以通过将其从流中收集到列表中来查看这些日期。但是请注意,这将耗尽所有资源。您需要重新建立流以继续我们的代码。

List< LocalDate > dates = stream.collect( Collectors.toList() );
System.out.println( dates );
  

[2018-08-19,2018-08-26]

遍历流中的那一系列日期。在每个LocalDate对象上,获取星期数。将每个返回的星期数收集为Integer对象,所有这些都收集在List中。

List< Integer > weekNumbers = 
    stream
    .map( 
        localDate -> localDate.get( WeekFields.SUNDAY_START.weekOfWeekBasedYear() ) 
    )
    .collect( Collectors.toList() )
;

转储到控制台。

System.out.println( weekNumbers );
  

[34,35]

单线

如果您真的想简短地发疯,我们可以在一行代码中完成所有这些操作。我不推荐这样做,但是尝试很有趣。

System.out.println(
    LocalDateTime.parse( "2018-08-24T12:18:06,166".replace( "," , "." ) ).toLocalDate()
    .with( TemporalAdjusters.previousOrSame( DayOfWeek.SUNDAY ) )
    .datesUntil(
        LocalDateTime.parse( "2018-08-26T12:19:06,188".replace( "," , "." ) ).toLocalDate()
        .with( TemporalAdjusters.previousOrSame( DayOfWeek.SUNDAY ) )
        .plusWeeks( 1 ) 
        ,
        Period.ofWeeks( 1 )
    )
    .map( localDate -> localDate.get( WeekFields.SUNDAY_START.weekOfWeekBasedYear() ) )
    .collect( Collectors.toList() )
);
  

[34,35]