Java:接受了无效的一周

时间:2016-12-25 12:37:42

标签: java

我编写了以下Java代码,以获得一年中第一天的第一天。

    Calendar cal = Calendar.getInstance(Locale.GERMAN);
    cal.clear();
    cal.set(Calendar.DAY_OF_WEEK_IN_MONTH, Calendar.MONDAY);
    cal.set(Calendar.YEAR, 2016);
    cal.set(Calendar.WEEK_OF_YEAR, weekNumber);

    DateFormat sdf = new SimpleDateFormat("dd.MM.yyyy");

    System.out.println( sdf.format(cal.getTime()) );

通过使用53年的输入周,它应该导致错误,因为2016年不存在这一周。相反,它显示了明年可能的第一个日期。

是否有一种简洁的方法来纠正我的代码,或者我必须自己检查一年中的输入周?

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

TL;博士

如果您的意思是标准的ISO 8601周,请使用YearWeek库中的ThreeTen-Extra课程。

针对特定周工作年的特定周数:

YearWeek.of(                         // Standard ISO 8601 week, where week # 1 has the first Thursday of the calendar year, and runs Monday-Sunday.
    2018 ,                           // Week-based year, NOT calendar year.
    37                               // Week-of-week-based-year. Runs 1-52 or 1-53. 
)
.atDay( DayOfWeek.MONDAY )           // Returns a `LocalDate` object.

if如果输入无效,则java.time.DateTimeException的陷阱,如果该周基于年份没有这样的一周。

本周:

YearWeek.now(                        // Standard ISO 8601 week, where week # 1 has the first Thursday of the calendar year, and runs Monday-Sunday.
    ZoneId.of( "Pacific/Auckland" )  // Determining a week means determining a date, and that requires a time zone. For any given moment, the date varies around the globe by zone.
)
.atDay( DayOfWeek.MONDAY )           // Returns a `LocalDate` object.

定义“周”

用“周”定义你的意思。第1周是1月1日吗?在新的一年中,第一周是第一个将所有七天组成的日子吗?如果是这样,一周的最后几天,周日 - 周六或周一 - 周日或其他什么?或者第一周是第一周的某一天?

麻烦的旧日期时间类根据Locale定义一周。如果未指定Locale,则会默默隐式应用JVM的当前默认值Locale。所以你的结果在运行时会有所不同。

如果可能,我建议使用标准ISO 8601 week定义。本周从周一至周日开始,第一周包含该日历年的第一个星期四。所以每年有52或53周。

获取当前日期意味着获取当前日期。时区对于确定日期至关重要。对于任何给定的时刻,日期在全球范围内因地区而异。例如,在Paris France午夜后的几分钟是新的一天,而Montréal Québec中仍然是“昨天”。

如果未指定时区,则JVM会隐式应用其当前的默认时区。该默认值可能随时更改,因此您的结果可能会有所不同。最好明确指定您期望/预期的时区作为参数。

continent/region的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用诸如ESTIST之类的3-4字母缩写,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "America/Montreal" ) ;  
LocalDate today = LocalDate.now( z ) ;

如果要使用JVM的当前默认时区,请求它并作为参数传递。如果省略,则隐式应用JVM的当前默认值。最好是明确的,因为默认情况下可以在运行时期间由JVM中任何应用程序的任何线程中的任何代码随时更改

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.

如果你只是想在那个日期或之前的某个星期,那么就不要在意这一周。使用TemporalAdjuster中的TemporalAjdusters实施。通过DayOfWeek枚举确定您的星期几。

LocalDate mondayOnOrBeforeToday = today.with( TemporalAdjusters.previousOrSame( DayOfWeek.MONDAY ) ) ;

ThreeTen-Extra

如果您确实希望使用ISO 8601 weeksIsoFields课程中提供的支持有限。但我建议您将ThreeTen-Extra库添加到项目中。该库提供了额外的日期时间类,补充了Java SE 8及更高版本中内置的类。特别是,你得到了YearWeek类。

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
YearWeek yw = YearWeek.now( z ) ;

要求该周的某一天的LocalDate

LocalDate ld = yw.atDay( DayOfWeek.MONDAY ) ;

关于 java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和& SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*类。

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore