对于给定日期,检测该月的第n天,然后在Java中确定未来6个月内的相同日期

时间:2018-04-20 05:58:24

标签: java java-time dayofweek

对于给定日期,例如2018-03-05,我如何检测到它是该月的第一个星期一?

在确定了这一事实之后,如何计算接下来六个月中该月的第n天?例如,2018-04-02周一和2018-05-03周一。

就像this Question但使用Java。

我尝试了这段代码,但没有得到我期望的结果。我的期望:

  

[2018-04-02,2018-05-07,2018-06-04,2018-07-02,2018-08-06,2018-09-03]

也许我误解了ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH

LocalDate ld = LocalDate.parse( "2018-03-05" );
int alignedDayOfWeekInMonth = ld.get( ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH );
DayOfWeek dayOfWeek = ld.getDayOfWeek();
YearMonth ym = YearMonth.from( ld );

int countMonths = 6;
List < LocalDate > localDates = new ArrayList <>( countMonths );
TemporalAdjuster ta = TemporalAdjusters.dayOfWeekInMonth( alignedDayOfWeekInMonth , dayOfWeek );
for ( int i = 1 ; i <= countMonths ; i++ ) {
    LocalDate firstOfMonth = ym.plusMonths( i ).atDay( 1 );
    LocalDate localDate = firstOfMonth.with( ta );
    localDates.add( localDate );
}

转储到控制台。

System.out.println( "ld.toString(): " + ld );
System.out.println( "alignedDayOfWeekInMonth: " + alignedDayOfWeekInMonth );
System.out.println( "dayOfWeek.toString(): " + dayOfWeek );
System.out.println("ym.toString(): " + ym);
System.out.println( "localDates: " + localDates );

跑步时。

ld.toString(): 2018-03-05
alignedDayOfWeekInMonth: 5
dayOfWeek.toString(): MONDAY
ym.toString(): 2018-03
localDates: [2018-04-30, 2018-06-04, 2018-07-02, 2018-07-30, 2018-09-03, 2018-10-01]

相关问题,但使用旧版日期时间类而不是现代 java.time 类:Find which nth occurrence of a day in a month for a date in Java

3 个答案:

答案 0 :(得分:1)

您为TemporalAdjusters.dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek)使用了错误的字段,因为ordinal 是该月的,但是您使用了ALIGNED_DAY_OF_WEEK_IN_MONTH¹。

但是如何在 java.time 中获得一周中的一周?:
为此,您需要WeekFields,最常见的是WeekFields.ISO 现在,您可以使用ChronoField创建一周中WeekFields.ISO.weekOfMonth();

使用您的代码,它应该如下所示:

LocalDate ld = LocalDate.parse( "2018-03-05" );
DayOfWeek dayOfWeek = ld.getDayOfWeek();
int ordinal = ld.get(WeekFields.of(dayOfWeek, 7).weekOfMonth());
YearMonth ym = YearMonth.from( ld );

int countMonths = 6;
List < LocalDate > localDates = new ArrayList <>( countMonths );
TemporalAdjuster ta = TemporalAdjusters.dayOfWeekInMonth( ordinal, dayOfWeek );
for ( int i = 1 ; i <= countMonths ; i++ ) {
    LocalDate firstOfMonth = ym.plusMonths( i ).atDay( 1 );
    LocalDate localDate = firstOfMonth.with( ta );
    localDates.add( localDate );
}

¹:ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH是一周中的第n天,它不会像星期一那样以固定的DAY_OF_WEEK开头,而是以月的第一天开始。

答案 1 :(得分:1)

这个简单的更改修复了您的程序:

    int alignedWeekOfMonth = ld.get(ChronoField.ALIGNED_WEEK_OF_MONTH);

我已经重命名了您的变量alignedDayOfWeekInMonth,因此您需要将名称更改到您正在使用它的两个位置。然后您的程序打印:

ld.toString(): 2018-03-05
alignedWeekOfMonth: 1
dayOfWeek.toString(): MONDAY
ym.toString(): 2018-03
localDates: [2018-04-02, 2018-05-07, 2018-06-04, 2018-07-02, 2018-08-06, 2018-09-03]

该列表与您所说的预期一致。

你误解ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH似乎是对的。参考3月5日对齐周数的概念是第1个对齐周的第5天日。您使用的计时字段为您提供了5而不是1.要获得1,请使用ChronoField.ALIGNED_WEEK_OF_MONTH代替。一切正常。

答案 2 :(得分:0)

这段代码完全不花哨,但它有效:)

public static void main(String[] args) {    
    LocalDate ld = LocalDate.parse( "2018-03-04" );
    DayOfWeek dayOfWeek = DayOfWeek.WEDNESDAY;

    LocalDate first = ld.withDayOfMonth(1);

    List<LocalDate> firstDays = new ArrayList<>();
    //I deliberately included the start date in the loop. 
    //Easily fixed if it shouldn't be included
    for (int i = 0; i <= 6; i++) {
        LocalDate firstDay = getFirstDay(first.plusMonths(i), dayOfWeek);
        firstDays.add(firstDay);
    }
}

static LocalDate getFirstDay(LocalDate date, DayOfWeek searchedDay) {
    LocalDate temp = date;
    int i = 0;
    while (temp.getDayOfWeek() != searchedDay) {
         temp = date.plusDays(i++);
    }
    return temp;
}