对于给定日期,例如 2018-03-05,如何检测它是该月的第一个星期一?
在确定这一事实之后,我如何计算接下来六个月中每月相同的第 n 天?例如,星期一 2018-04-02 和星期一 2018-05-03。
就像这个问题一样,但使用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类:查找Java中一个月中某一天的哪n个出现
这个简单的更改可以修复您的程序:
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 日是第一个对齐周的第 5 天。您使用的计时字段给了您 5,而不是 1。若要获取 1,请改用 ChronoField.ALIGNED_WEEK_OF_MONTH
。然后一切都好了。
您使用了错误的字段TemporalAdjusters.dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek)
因为ordinal
是月份中的一周,但您使用了ALIGNED_DAY_OF_WEEK_IN_MONTH
¹。
但是如何在java.time中获取月份中的一周呢?
为此您需要 WeekFields
,最常见的是 WeekFields.ISO
.
现在,您可以使用 WeekFields.ISO.weekOfMonth();
创建月份中一周的ChronoField
。
使用您的代码,这应该如下所示:
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开始,而是从每月的第一天开始。
这段代码一点也不花哨,但它:)
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;
}