使用 java.time 查找一年中最后一周的第一天
Find first day of last week of year with java.time
我需要使用 Java 8 日期和时间 API (java.time) 找到一年最后一周的第一天,最后得出这个解决方案:
LocalDate date = LocalDate.of(2016, 2, 17);
LocalDate lastWeekOfYear = LocalDate.of(date.getYear() + 1, 1, 7)
.with(WeekFields.ISO.weekOfYear(), 1)
.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).minusDays(7);
此解决方案查找下一年的第一周,必要时将星期几调整为星期一并向后移动 7 天。有没有更聪明的方法可以达到同样的效果?
根据您的评论更新:
您可以从约会开始,得到一年的最后一天,然后返回到星期一。得到这个结果的WeekBasedYear,如果weekBasedYear和day year相同就接受它,否则返回上一个星期一接受它作为结果:
LocalDate day = LocalDate.of(2012, 2, 17);
LocalDate result = day.with(TemporalAdjusters.lastDayOfYear())
.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
//if day and result weekBasedYear are in the same weekYear then result else go back to previous Mondays
result = result.get(WeekFields.ISO.weekBasedYear())== day.getYear()? result :
result.with(TemporalAdjusters.previous(DayOfWeek.MONDAY));
System.out.println(result);
输出:
2012-12-24
希望对您有所帮助。
按照建议,我会自己回答这个问题(根据评论稍作改进),因为似乎没有明显更简单的解决方案。
LocalDate date = LocalDate.of(2016, 2, 17);
LocalDate lastWeekOfYear = LocalDate.of(date.getYear() + 1, 1, 7)
.with(WeekFields.ISO.weekOfWeekBasedYear(), 1)
.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).minusWeeks(1);
我认为 OP 找到的最后一个解决方案仍然不正确,因为我们在 ISO 周日期的上下文中移动,而不是普通日历日期。因此表达式 LocalDate.of(date.getYear() + 1, 1, 7)
在年份边界附近通常是错误的(参见示例方法 lastWeekOfYearOld(...)
)。相反,我们必须添加基于周的年份,而不是现在已在第二种方法中使用的日历年(绑定到 1 月至 12 月)lastWeekOfYearCorrect(...)
。我还展示了另一个基于 week-of-year-field 的上下文相关值范围的正确选择(参见方法 lastWeekOfYearAlternative(...)
.
public static void main(String[] args) {
System.out.println(
lastWeekOfYearOld(LocalDate.of(2015, 12, 31))); // 2015-12-28 (OK)
System.out.println(
lastWeekOfYearOld(LocalDate.of(2016, 1, 1))); // 2016-12-26 (Wrong)
System.out.println(
lastWeekOfYearCorrect(LocalDate.of(2015, 12, 31))); // 2015-12-28 (OK)
System.out.println(
lastWeekOfYearCorrect(LocalDate.of(2016, 1, 1))); // 2015-12-28 (OK)
System.out.println(
lastWeekOfYearAlternative(LocalDate.of(2015, 12, 31))); // 2015-12-28 (OK)
System.out.println(
lastWeekOfYearAlternative(LocalDate.of(2016, 1, 1))); // 2015-12-28 (OK)
}
private static LocalDate lastWeekOfYearOld(LocalDate date) {
return LocalDate.of(date.getYear() + 1, 1, 7)
.with(WeekFields.ISO.weekOfWeekBasedYear(), 1)
.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).minusWeeks(1);
}
private static LocalDate lastWeekOfYearCorrect(LocalDate date) {
date =
date.plus(1, IsoFields.WEEK_BASED_YEARS)
.with(DayOfWeek.MONDAY)
.with(WeekFields.ISO.weekOfWeekBasedYear(), 1);
return date.minusWeeks(1);
}
private static LocalDate lastWeekOfYearAlternative(LocalDate date) {
TemporalField woyField = WeekFields.ISO.weekOfWeekBasedYear();
date = date.with(woyField, woyField.rangeRefinedBy(date).getMaximum());
return date.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
}
tl;博士
org.threeten.extra.YearWeek.from( // Represents an entire week at a time, using standard ISO 8601 definition of “week”.
LocalDate.of( 2016 , Month.FEBRUARY , 17 )
) // Returns a `YearWeek` object to represent the week containing that date.
.plusYears( 1 ) // Move to following year.
.withWeek( 1 ) // Move to the first week of that following year.
.minusWeeks( 1 ) // Move to the prior week, which would be the last week of our desired week-based-year.
.atDay( // Determine the date of a particular day-of-week within that week.
DayOfWeek.MONDAY // Use the handy `java.time.DayOfWeek` enum predefining seven objects, one for each day of the week.
) // Returns a `LocalDate` object.
.toString() // Generate a String representing this `LocalDate` value in standard ISO 8601 format.
2016-12-26
YearWeek
ThreeTen-Extra 库提供了额外的日期时间 类 来补充 java.time.
YearWeek
class from that library suits your purpose. This class represents the entire week of a week-based year using standard ISO 8601定义。
获取当前年-周。
YearWeek yw = YearWeek.now( ZoneId.of( "Africa/Tunis" ) ) ; // Get the current year-week as seen in the wall-clock time of people inhabiting a particular region (a time zone).
或获取特定日期的 YearWeek
。
LocalDate ld = LocalDate.of( 2016 , Month.FEBRUARY , 17 ) ; // Feb 2, 2016.
YearWeek yw = YearWeek.from( ld ) ;
确定今年的最后一周数,52或53。这里我们使用三元运算符而不是更长的if-else
语句。
int w = yw.is53WeekYear() ? 53 : 52 ; // Determine last week number, either 52 or 53.
移至本年度的最后一周。
YearWeek ywLastOfYear = yw.withWeek( w ) ; // Produce a new `YearWeek` object based on the original’s values but for some adjustment - here we use the same year but use a different week number.
最后得到那个星期的第一天的日期,这里的第一天是星期一
LocalDate firstDayOfLastYearWeek = ywLastOfYear.atDay( DayOfWeek.MONDAY ) ;
这是一种方法。有关另一种方法,请参阅上面的 tl;dr 部分。
我需要使用 Java 8 日期和时间 API (java.time) 找到一年最后一周的第一天,最后得出这个解决方案:
LocalDate date = LocalDate.of(2016, 2, 17);
LocalDate lastWeekOfYear = LocalDate.of(date.getYear() + 1, 1, 7)
.with(WeekFields.ISO.weekOfYear(), 1)
.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).minusDays(7);
此解决方案查找下一年的第一周,必要时将星期几调整为星期一并向后移动 7 天。有没有更聪明的方法可以达到同样的效果?
根据您的评论更新:
您可以从约会开始,得到一年的最后一天,然后返回到星期一。得到这个结果的WeekBasedYear,如果weekBasedYear和day year相同就接受它,否则返回上一个星期一接受它作为结果:
LocalDate day = LocalDate.of(2012, 2, 17);
LocalDate result = day.with(TemporalAdjusters.lastDayOfYear())
.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
//if day and result weekBasedYear are in the same weekYear then result else go back to previous Mondays
result = result.get(WeekFields.ISO.weekBasedYear())== day.getYear()? result :
result.with(TemporalAdjusters.previous(DayOfWeek.MONDAY));
System.out.println(result);
输出:
2012-12-24
希望对您有所帮助。
按照建议,我会自己回答这个问题(根据评论稍作改进),因为似乎没有明显更简单的解决方案。
LocalDate date = LocalDate.of(2016, 2, 17);
LocalDate lastWeekOfYear = LocalDate.of(date.getYear() + 1, 1, 7)
.with(WeekFields.ISO.weekOfWeekBasedYear(), 1)
.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).minusWeeks(1);
我认为 OP 找到的最后一个解决方案仍然不正确,因为我们在 ISO 周日期的上下文中移动,而不是普通日历日期。因此表达式 LocalDate.of(date.getYear() + 1, 1, 7)
在年份边界附近通常是错误的(参见示例方法 lastWeekOfYearOld(...)
)。相反,我们必须添加基于周的年份,而不是现在已在第二种方法中使用的日历年(绑定到 1 月至 12 月)lastWeekOfYearCorrect(...)
。我还展示了另一个基于 week-of-year-field 的上下文相关值范围的正确选择(参见方法 lastWeekOfYearAlternative(...)
.
public static void main(String[] args) {
System.out.println(
lastWeekOfYearOld(LocalDate.of(2015, 12, 31))); // 2015-12-28 (OK)
System.out.println(
lastWeekOfYearOld(LocalDate.of(2016, 1, 1))); // 2016-12-26 (Wrong)
System.out.println(
lastWeekOfYearCorrect(LocalDate.of(2015, 12, 31))); // 2015-12-28 (OK)
System.out.println(
lastWeekOfYearCorrect(LocalDate.of(2016, 1, 1))); // 2015-12-28 (OK)
System.out.println(
lastWeekOfYearAlternative(LocalDate.of(2015, 12, 31))); // 2015-12-28 (OK)
System.out.println(
lastWeekOfYearAlternative(LocalDate.of(2016, 1, 1))); // 2015-12-28 (OK)
}
private static LocalDate lastWeekOfYearOld(LocalDate date) {
return LocalDate.of(date.getYear() + 1, 1, 7)
.with(WeekFields.ISO.weekOfWeekBasedYear(), 1)
.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).minusWeeks(1);
}
private static LocalDate lastWeekOfYearCorrect(LocalDate date) {
date =
date.plus(1, IsoFields.WEEK_BASED_YEARS)
.with(DayOfWeek.MONDAY)
.with(WeekFields.ISO.weekOfWeekBasedYear(), 1);
return date.minusWeeks(1);
}
private static LocalDate lastWeekOfYearAlternative(LocalDate date) {
TemporalField woyField = WeekFields.ISO.weekOfWeekBasedYear();
date = date.with(woyField, woyField.rangeRefinedBy(date).getMaximum());
return date.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
}
tl;博士
org.threeten.extra.YearWeek.from( // Represents an entire week at a time, using standard ISO 8601 definition of “week”.
LocalDate.of( 2016 , Month.FEBRUARY , 17 )
) // Returns a `YearWeek` object to represent the week containing that date.
.plusYears( 1 ) // Move to following year.
.withWeek( 1 ) // Move to the first week of that following year.
.minusWeeks( 1 ) // Move to the prior week, which would be the last week of our desired week-based-year.
.atDay( // Determine the date of a particular day-of-week within that week.
DayOfWeek.MONDAY // Use the handy `java.time.DayOfWeek` enum predefining seven objects, one for each day of the week.
) // Returns a `LocalDate` object.
.toString() // Generate a String representing this `LocalDate` value in standard ISO 8601 format.
2016-12-26
YearWeek
ThreeTen-Extra 库提供了额外的日期时间 类 来补充 java.time.
YearWeek
class from that library suits your purpose. This class represents the entire week of a week-based year using standard ISO 8601定义。
获取当前年-周。
YearWeek yw = YearWeek.now( ZoneId.of( "Africa/Tunis" ) ) ; // Get the current year-week as seen in the wall-clock time of people inhabiting a particular region (a time zone).
或获取特定日期的 YearWeek
。
LocalDate ld = LocalDate.of( 2016 , Month.FEBRUARY , 17 ) ; // Feb 2, 2016.
YearWeek yw = YearWeek.from( ld ) ;
确定今年的最后一周数,52或53。这里我们使用三元运算符而不是更长的if-else
语句。
int w = yw.is53WeekYear() ? 53 : 52 ; // Determine last week number, either 52 or 53.
移至本年度的最后一周。
YearWeek ywLastOfYear = yw.withWeek( w ) ; // Produce a new `YearWeek` object based on the original’s values but for some adjustment - here we use the same year but use a different week number.
最后得到那个星期的第一天的日期,这里的第一天是星期一
LocalDate firstDayOfLastYearWeek = ywLastOfYear.atDay( DayOfWeek.MONDAY ) ;
这是一种方法。有关另一种方法,请参阅上面的 tl;dr 部分。