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

时间:2014-08-01 16:19:56

标签: java iso8601 week-number

有没有办法这样做:How to get dates of a week (I know week number)? ISO 8601 week number而不使用Java中的任何库或日历?

3 个答案:

答案 0 :(得分:4)

更新:此处介绍的概念仍然适用,但代码已过时。现在位于Joda-Timemaintenance mode项目建议迁移到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 );

有关详细信息,请继续阅读。

避免使用j.u.Date

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

此外,这些类对ISO 8601 weeks的支持很弱。有关详细信息,请参阅this answer

ISO周规则

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

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

约达时间

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

简单地添加到您的项目中,只需添加一个.jar文件。

其他示例代码

请参阅此other answer of minethis one,了解从ISO周编号中获取日期时间的示例代码。

java.time

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

添加库

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

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

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

半开

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

Diagram of Half-Open approach to defining a week, going from start of Day 1 to start of Day 8

ISO周的文本表示

ISO 8601标准定义了represent a standard week的方式,甚至是该周内的一天。

取年份,连字符,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

答案 1 :(得分:2)

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);

答案 2 :(得分:2)

LocalDate date = 
  LocalDate.parse("2015 53", 
     new DateTimeFormatterBuilder().appendPattern("YYYY w")
    .parseDefaulting(WeekFields.ISO.dayOfWeek(), 1)
    .toFormatter()));