Thomas Auinger
Thomas Auinger

Reputation: 2095

Parse week strings for comparison using Java 8

I want to compare string representations of weeks, e.g. week "01/17" is before "02/17" and after "52/16".

The following code throws an exception, I guess because my string doesn't hint at the exact day of each week. However, I don't care - it could all be Mondays or Thursdays or whatever:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("ww/YY", Locale.GERMANY);
LocalDate date1 = formatter.parse(str1, LocalDate::from);

Do I need to modify the parser? Or parse to some other format? Unfortunatley there is no object like YearMonth for weeks...

Upvotes: 2

Views: 320

Answers (3)

Basil Bourque
Basil Bourque

Reputation: 338316

tl;dr

YearWeek.parse( "2017-W01" )

ISO 8601

Or parse to some other format?

Yes, use another format.

Use the standard ISO 8601 formats when serializing date-time values to text. The standard includes support for week dates.

For a year-week that would be four year digits, a hyphen, a W, and two digits for the week of the year.

2017-W01

Get clear on your definition of a “week”. The ISO 8601 definition is that:

  • The Week # 1 contains the first Thursday of the year, and
  • Runs Monday-Sunday.

So years run either 52 or 53 weeks long. And note that under this definition, the first few days of the year may be in the prior year when week-numbering. Likewise, the last few days of the year may be in the following year when week-numbering.

If you want to indicate a particular day within that week, append a hyphen and a single digit running 1-7 for Monday-Sunday.

Tip: To see ISO 8601 week numbers by default on your computer, you may need to adjust your OS setting. For example, on macOS set System Preferences > Language & Region > Calendar > ISO 8601 to make apps such as Calendar.app to display week numbers with this standard definition.

2017-W01-7

By the way, a couple of similar representations:

  • An ordinal date meaning the year and the day-of-year-number running from 1-366 is year, a hyphen, and a three-digit number: 2017-123
  • Month-Day without year is two hyphens, month number, hyphen, and day-of-month number: --01-07

Note that the use of Locale as seen in the Question is irrelevant here with the standard ISO 8601 formats.

YearWeek

Unfortunatley there is no object like YearMonth for weeks...

Ahhh, but there is such a class.

For a class to directly represent the idea of a week-year, see the correct Answer by Henrik. That Answer shows the ThreeTen-Extra library’s class YearWeek.

The YearWeek class can directly parse and generate strings in standard format.

YearWeek yw = YearWeek.parse( "2017-W01" );

You can compare the YearWeek objects with methods: compareTo, equals, isBefore, isAfter.

yw.isBefore( thatYw )

The ThreeTen-Extra project offers other classes such as YearQuarter that you may find useful.

Upvotes: 2

assylias
assylias

Reputation: 328598

One solution would be to always default to the same day, say the Monday. You could build a custom formatter for that:

DateTimeFormatter fmt = new DateTimeFormatterBuilder()
          .appendPattern("ww/YY")
          .parseDefaulting(ChronoField.DAY_OF_WEEK, 1)
          .toFormatter(Locale.GERMANY);

You can now build LocalDates representing the Monday of the given week:

LocalDate d1 = LocalDate.parse("01/17", fmt);
LocalDate d2 = LocalDate.parse("52/16", fmt);
System.out.println(d1.isAfter(d2));

which prints true because 01/17 is after 52/16.

Upvotes: 5

I wasn't able to find a way for this to work with the DateTimeFormatter class, but I would like to suggest a different approach.

The Threeten Extra library contains a number of classes that were deemed too specific to include in the java.time library. One of them is the YearWeek class you mention.

Your problem can be solved by parsing the week-number and year manually from the input-string and then invoking the YearWeek creator-method like this:

YearWeek yw = YearWeek.of(year, monthOfYear);

Upvotes: 2

Related Questions