如何从Java中的ISO8601周数计算日期

有没有办法做到这一点: 如何获得一周的日期(我知道周数)? 对于ISO 8601 周数而不使用Java中的任何库或日历?

更新:此处介绍的概念仍然适用,但代码已过时。 现在处于维护模式的Joda-Time项目建议迁移到java.time类。 请参阅Answer by Szulc中的java.time代码。

简答

DateTime dateTimeStart = new DateTime( "2003-W01-1", DateTimeZone.UTC ); // Joda-Time 2.4. DateTime dateTimeStop = dateTimeStart.plusWeeks( 1 ); 

有关详情,请继续阅读。

避免juDate

与Java捆绑在一起的旧java.util.Date和java.util.Calendar类是众所周知的麻烦,应该避免。 Sun及其合作伙伴在Java库中添加了许多简洁的东西,但并非所有这些都很好。 日期时间类可能是最糟糕的。

此外,这些课程对ISO 8601周的支持较弱。 请参阅此答案了解详情。

ISO周规则

您可以使用这些类编写自己的代码,但我不建议这样做。 计算ISO周的规则很简单:

  • 第1周是该日历年的第一个星期四。
  • 星期一是一周的第一天。

乔达时间

在他们的位置,常见的替代品是一个名为Joda-Time的库。 该库包含对ISO周的出色支持。

只需添加一个.jar文件即可轻松添加到项目中。

其他示例代码

请参阅我的另一个答案或这个例子,以获取ISO周号的日期时间代码。

java.time

Java 8有一个新的日期时间框架,受Joda-Time的启发,可以在java.time包中找到。

添加库

Java是为了将库混合在一起而构建的。 这样做是面向对象编程和后期绑定的主要目的之一。 对你的问题的评论指的是老板非理性或无知地禁止添加图书馆这种常见的情况。 虽然这种禁令有正当理由,但很少见。

禁止在Java中添加库和jar子就像禁止在装有挂钩的车辆上挂钩拖车。

旧的日期时间课程确实很糟糕,我们很多人都把Joda-Time添加到大多数新项目作为习惯。

半开

在日期时间工作中,定义时间跨度的常用方法是“半开放”方法。 这意味着开头是包容性的,而结尾是独占的。 因此,标准周从星期一的第一个时刻开始,到下一个星期一的第一个时刻结束。 搜索StackOverflow.com以获取更多讨论和示例。

定义一周的半开放方法图,从第1天开始到第8天开始

ISO周的文本表示

ISO 8601标准定义了表示标准周甚至一周内的一天的方法。

拿一年,一个连字符,一个W分隔符,周数表示整周: YYYY-Www 。 添加连字符和星期几数字以确定该周内的一天: YYYY-Www-D

Joda-Time理解这种格式,如下面的代码示例所示。

示例代码

这是一些Joda-Time 2.4代码。 搜索StackOverflow.com以获取这些概念的讨论和示例。 这个问题和这个答案几乎与其他许多重复。

 int year = 2003; int week = 1; // Domain: 1 to 53. // Build a String in ISO 8601 Week format: YYYY-Www-D // Hard-coding a `1` for Monday, the standard first-day-of-week. String input = ( String.format( "%04d", year ) + "-W" + String.format( "%02d", week ) + "-1" ); // Specify the time zone by which to define the beginning of a day. DateTimeZone timeZone = DateTimeZone.UTC; // Or: DateTimeZone.forID( "America/Montreal" ); // Calculate beginning and ending, using Half-Open (inclusive, exclusive) approach. DateTime dateTimeStart = new DateTime( input, timeZone ); DateTime dateTimeStop = dateTimeStart.plusWeeks( 1 ); // Use Joda-Time's tidy Interval class to represent the entire week. Use getters to access start and stop. Interval weekInterval = new Interval( dateTimeStart, dateTimeStop ); // Is today in that week? Joda-Time has handy methods: contains, isBefore, isAfter, overlap. boolean isTodayInThatWeek = weekInterval.contains( DateTime.now() ); 

转储到控制台。

 System.out.println( "input: " + input ); System.out.println( "dateTimeStart: " + dateTimeStart ); System.out.println( "dateTimeStop: " + dateTimeStop ); System.out.println( "interval: " + interval ); System.out.println( "isTodayInThatWeek: " + isTodayInThatWeek ); 

跑步的时候。

 input: 2003-W01-1 dateTimeStart: 2002-12-30T00:00:00.000Z dateTimeStop: 2003-01-06T00:00:00.000Z interval: 2002-12-30T00:00:00.000Z/2003-01-06T00:00:00.000Z isTodayInThatWeek: false 

Java 8 / java.time方式

在Java 8中,您可以使用TemporalField结合LocalDate :: with(TemporalField,long)方法获取基于星期的星期和TemporalAdjuster结合LocalDate :: with(TemporalAdjuster)方法来跳转到所需的星期几,如这个:

 final int weekNumber = 34; LocalDate weekByNumber = date.with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, weekNumber); final TemporalAdjuster adjuster = TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY); LocalDate mondayOfWeekByNumber = weekByNumber.with(adjuster); 
 LocalDate date = LocalDate.parse("2015 53", new DateTimeFormatterBuilder().appendPattern("YYYY w") .parseDefaulting(WeekFields.ISO.dayOfWeek(), 1) .toFormatter()));