我希望使用Java 8软件包java.time获得给定周和年的星期一日期。 但在某些时候我面临着问题,因为它没有回复正确的约会。
private LocalDate getDateFromWeekAndYear(final String week,final String year){
LocalDate date = LocalDate.now();
date = date.with(WeekFields.ISO.dayOfWeek(), 1);
date = date.with(WeekFields.ISO.weekOfWeekBasedYear(), Long.parseLong(week));
date = date.with(WeekFields.ISO.weekBasedYear(), Long.parseLong(year));
return date;
}
例如:
我是否存在任何逻辑错误或其他问题?
答案 0 :(得分:3)
首先,您需要计算一年中第一周的第一个星期一, 然后简单地加上7的多个日期。
public static LocalDate firstMonday(int week, int year) {
LocalDate firstMonOfFirstWeek = LocalDate.now()
.with(IsoFields.WEEK_BASED_YEAR, year) // year
.with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 1) // First week of the year
.with(ChronoField.DAY_OF_WEEK, 1); // Monday
// Plus multi of 7
return firstMonOfFirstWeek.plusDays( (week - 1) * 7);
}
public static void main(String[] args) {
System.out.println(firstMonday(1, 2013)); // 2012-12-31
System.out.println(firstMonday(53 ,2015 )); // 2015-12-28
}
答案 1 :(得分:3)
这比OP的部分无效期望更难以解决,大多数答案都显示出来。
首先要说的是:定义基于周的操作的正确顺序非常重要。 OP首先应用日操纵,然后是基于年的操纵。正确的方法是相反的!我将展示正确的帮助方法实现:
public static void main(String... args) {
System.out.println(
getDateFromWeekAndYear("53", "2015")); // 2015-12-28, NOT 2014-12-28
System.out.println(
getDateFromWeekAndYear("53", "2015").get(WeekFields.ISO.weekOfWeekBasedYear())); // 53
System.out.println(
getDateFromWeekAndYear("53", "2014")); // 2014-12-29
System.out.println(
getDateFromWeekAndYear("53", "2014").get(WeekFields.ISO.weekOfWeekBasedYear())); // 1
}
private static LocalDate getDateFromWeekAndYear(final String week,final String year) {
int y = Integer.parseInt(year);
LocalDate date = LocalDate.of(y, 7, 1); // safer than choosing current date
// date = date.with(WeekFields.ISO.weekBasedYear(), y); // no longer necessary
date = date.with(WeekFields.ISO.weekOfWeekBasedYear(), Long.parseLong(week));
date = date.with(WeekFields.ISO.dayOfWeek(), 1);
return date;
}
如果您不遵守此特定订单,那么您确实有时会获得2015-W53输入的2014年日期(取决于当前日期)。
第二个问题:我也避免从当前日期开始,以便不接近日历年的开始或结束(日历年!=基于周的年份),而是选择midth一年作为起点。
第三个问题是在2014年(基于工作日)的第53周的宽松处理。它不存在,因为2014年只有52周!严格的算法应该识别并拒绝这样的输入。因此,我建议不要在2015年的第一周使用YearWeek.of(2014, 53)
(在外部库Threeten-Extra中),另请参阅其javadoc。比这种宽松的处理更好
YearWeek yw = YearWeek.of(2014, 52);
if (yw.is53WeekYear()) {
yw = YearWeek.of(2014, 53);
}
或使用我自己的时间库Time4J中的代码(其类CalendarWeek具有额外的i18n功能和额外周算术与YearWeek
相比):
CalendarWeek.of(2014, 53); // throws an exception
System.out.println(CalendarWeek.of(2014, 1).withLastWeekOfYear()); // 2014-W52
仅使用java.time
- package:
使用这样的外部库至少有助于以透明的方式解决第一个问题。如果您不愿意添加额外的依赖项,那么如果无效,您可以执行此操作来处理第53周:
如果对助手方法的结果应用的表达式WeekFields.ISO.weekOfWeekBasedYear()
产生值1,那么您知道第53周无效。然后您可以决定是否要接受宽松处理或抛出异常。但默默调整这样一个无效的输入是恕我直言的糟糕设计。
答案 2 :(得分:1)
YearWeek.of ( 2013 , 1 ).atDay ( DayOfWeek.MONDAY )
您的期望不正确。 2015-W53
的星期一是2015-12-28
,而不是2014-12-28
,2015年而不是2014年。没有理由期待2014年。如果您需要更多解释,请编辑您的问题以解释您的想法
您可能会对日历年与基于周的年份感到困惑。在ISO 8601 definition of a week based year,周第一个包含日历年的第一个星期四。这意味着我们在这些年间有一些重叠。日历年的最后几天可能存在于下一周的年份中。反之亦然,日历年的前几天可能存在于上一周的基础上。
例如,您可以在下面的屏幕截图中看到,2012年日历(12月31日)的最后一天属于2013年第1周的第一周的第一周。在另一个屏幕截图中,我们有相反的情况,即2016年(1月1日,2日和3日)的前三天在2015年的第59周登陆。
2013-W01
的星期一是2012-12-31
。2015-W53
的星期一是2015-12-28
。 YearWeek
我建议将ThreeTen-Extra库添加到您的项目中以使用YearWeek
类。而不是仅传递年和周的整数,而是传递此类的对象。这样做可以使您的代码更加自我记录,提供类型安全性并确保有效的值。
// Pass ( week-based-year-number, week-number ). *Not* calendar year! See the ISO 8601 standard.
YearWeek yw = YearWeek.of( 2013 , 1 );
你可以从那一周开始任何一天。
LocalDate ld = yw.atDay( DayOfWeek.MONDAY );
我们试试这种代码吧。
YearWeek yw1 = YearWeek.of ( 2013 , 1 );
LocalDate ld1 = yw1.atDay ( DayOfWeek.MONDAY );
YearWeek yw2 = YearWeek.of ( 2015 , 53 );
LocalDate ld2 = yw2.atDay ( DayOfWeek.MONDAY );
System.out.println ( "yw1: " + yw1 + " Monday: " + ld1 );
System.out.println ( "yw2: " + yw2 + " Monday: " + ld2 );
yw1:2013-W01星期一:2012-12-31
yw2:2015-W53星期一:2015-12-28
提示:要在Calendar.app中查看Mac上的ISO 8601 standard week个号码,请设置System Preferences
> Language & Region
> Calendar
> ISO 8601
。然后在Calendar.app中设置Preferences
> Advanced
> Show week numbers
。