简体   繁体   中英

How to calculate Date from ISO8601 week number in Java

Is there any way of doing this: How to get dates of a week (I know week number)? for ISO 8601 week number without using any library or calender in Java?

UPDATE: The concepts presented here still apply, but the code is outmoded. The Joda-Time project, now in maintenance mode , advises migration to the java.time classes. See the java.time code in the Answer by Szulc .

Short Answer

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

For details, read on.

Avoid juDate

The old java.util.Date and java.util.Calendar classes bundled with Java are notoriously troublesome and should be avoided. Sun and its partners put a lot of neat stuff in the Java libraries, but not all of it is good. The date-time classes are perhaps the worst of it.

Furthermore those classes have weak support for ISO 8601 weeks . See this answer for details.

ISO Week Rules

You could write your own code using those classes, but I don't recommend this. The rules for calculation of ISO weeks are simple enough:

  • Week 1 has the first Thursday of the calendar year.
  • Monday is first day of week.

Joda-Time

In their place, the common replacement is a library called Joda-Time . This library includes excellent support for ISO weeks.

Simple to add to your project, just add a single .jar file.

Other Example Code

See this other answer of mine or this one for example code for getting a date-time from an ISO week number.

java.time

Java 8 has a new date-time framework, inspired by Joda-Time, found in the java.time package.

Adding Libraries

Java is built to mix libraries together. Doing so is one of the main purposes to object-oriented programming and late-binding. The comments on your question refer to the all-too-common situation where bosses irrationally or ignorantly forbid adding libraries. While there are valid reasons for such a ban, they are rare.

Forbidding adding libraries and jars in Java is like forbidding the hooking up of trailers on a fleet of vehicles equipped with a hitch.

The old date-time classes really are bad enough that many of us add Joda-Time to most any new project as a habit.

Half-Open

In date-time work, a common way to define a span of time is the "Half-Open" approach. This means the beginning is inclusive while the ending is exclusive. So a standard week begins on the first moment of a Monday, and ends on the first moment of the following Monday. Search StackOverflow.com for more discussion and examples.

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

Textual Representation of ISO Week

The ISO 8601 standard defines ways to represent a standard week and even a day within that week.

Take the year, a hyphen, a W delimiter, and the week number represents the whole week: YYYY-Www . Add a hyphen and day-of-week number to pinpoint a day within that week: YYYY-Www-D .

Joda-Time understands this format as seen in the code example below.

Example Code

Here is some Joda-Time 2.4 code. Search StackOverflow.com for discussion and examples of these concepts. This Question and this Answer pretty much duplicate many others.

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

Dump to console.

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

When run.

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

The Java 8 / java.time way

In Java 8, you can use TemporalField combined with LocalDate::with(TemporalField, long) method for getting the correct week (of the week based year) and TemporalAdjuster combined with LocalDate::with(TemporalAdjuster) method to jump to the required day of the week, like this:

final int year = 2020;
final int weekNumber = 34;

LocalDate mondayOfWeek = LocalDate.of(year, Month.JUNE, 1)
                         .with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, weekNumber)
                         .with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM