How to parse date from string using year and week using java.time

In old java, I can do it like this:

System.out.println(new SimpleDateFormat("yyyy w", Locale.UK).parse("2015 1"));
// shows Mon Dec 29 00:00:00 CET 2014

System.out.println(new SimpleDateFormat("yyyy w", Locale.US).parse("2015 1"));
// shows Mon Dec 28 00:00:00 CET 2014

      

I would like to use java.time in Java 8.

System.out.println( LocalDate.parse("2015 1", DateTimeFormatter.ofPattern("yyyy w", Locale.US)));

      

Result:

java.time.format.DateTimeParseException: text '2015 1' could not be parsed: unable to get LocalDate from TemporalAccessor: {WeekOfWeekBasedYear [WeekFields [SUNDAY, 1]] = 1, Year = 2015}, ISO type java.time.format. Parsed

How do I do this in java.time?

Moreover, I'm not satisfied with what Locale has to go through to determine the first day of the week: Monday versus Sunday. This is not a country function, but a calendar function. I would like to use something like java.time.temporal.WeekFields.ISO to show the world that this week starts on Monday.

I found a similar case on this stackoverflow question.

but not for java.time in Java 8. Also, a solution that first creates a date object and then sets the correct week is not elegant. I want to create the final date in one shot.

+3


source to share


3 answers


Direct answer and solution:

System.out.println( 
  LocalDate.parse("2015 1", 
    new DateTimeFormatterBuilder().appendPattern("YYYY w")
    .parseDefaulting(WeekFields.ISO.dayOfWeek(), 1)
    .toFormatter()));
// output: 2014-12-29

      

Explanations:

a) You should use Y instead of y because you are interested in ISO-8601-week-date, not in the era of the era.



b) The calendar date cannot be generated simply by specifying the (weekly) year and week number. The day of the week is important for determining the day within the specified calendar week. The predefined format for weekly dates requires the missing day of the week. Therefore, you need to build a custom parser using the builder template. Then you need to tell the parser what day of the week you want - using the method parseDefaulting()

.

c) I insist (and defend JSR-310 here) by saying that the question of when the week starts is not a calendar issue, but a country specific issue. The USA and France (for example) use the same calendar, but have different ideas on how to define the week. The ISO-8601 standard can be applied using an explicit ISO reference field WeekFields.ISO.dayOfWeek()

. Note: . Testing has shown that using in ChronoField.DAY_OF_WEEK

conjunction with Locale.ROOT

does not always guarantee ISO weekly behavior as stated in my first version of this answer (the reasons are not yet clear for me, it seems to me that a close look at the sources is necessary to understand non-intuitive behavior.)

d) The java-time package does it well - except that Monday is just listed as number 1. I'd prefer an enumeration. Or use an enum and its method getValue()

.

e) Side note: SimpleDateFormat

Behaves by default. The java-time package is stricter and refuses to reinvent the missing day of the week out of thin air - even in soft mode (which is pretty good in my opinion). The software doesn't have to guess so much; instead, the programmer has to think more about which day of the week is correct. Here again: Application requirements are likely to be different in the US and France regarding the correct default setting.

+5


source


The answer was answered by Meno Hochschild . Here's an alternative route.

YearWeek

Use the YearWeek

class in the ThreeTen-Extra library. This library extends java.time with additional functionality. This class represents an annual week in the ISO 8601 week date system .

The factory method YearWeek.of

takes a couple of integer arguments, a week number and a week number.

YearWeek yw = YearWeek.of( 2015 , 1 );  

      

ISO 8601

Ideally, you would use the standard ISO 8601 formats for strings representing date and time values. For year-week, which will be theyyyy-Www

default week number, hyphen, a W

and two digits for week number, with zero padding if necessary.

2015-W01

The java.time classes and the ThreeTen-Extra classes use the standard ISO 8601 formats by default when parsing and generating strings. So life is much easier if you stick to the standard.

YearWeek yw = YearWeek.parse( "2015-W01" );
String output = yw.toString(); // 2015-W01

      

Parsing integers.

You have a non-standard format for numbers. So let's parse your string as two parts, one number each, to be interpreted as integers int

.



String string = "2015 1";
String[] parts = string.split(" "); // SPACE character.
String part1 = parts[0]; // 2015
String part2 = parts[1]; // 1

      

The class Integer

converts such strings to int

primitive values.

int weekBasedYearNumber = Integer.parseInt( part1 ) ;
int weekNumber = Integer.parseInt( part2 ) ;

      

Now call this factory method.

YearWeek yw = YearWeek.of( weekBasedYearNumber , weekNumber );

      

LocalDate

Regarding the first day of the week, here we are discussing the ISO 8601 standard definition of the week. In this definition, Monday is always the first day, a week from Monday to Sunday. Week # 1 contains the first Thursday of the calendar year. In the case of 2015-W01, that Thursday will be January 1, 2015.

So no Locale

.

I'm not entirely sure about your purpose, but it looks like you are fetching specific dates over several days in your week. It's pretty easy with class YearWeek

and DayOfWeek

enum.

LocalDate monday = yw.atDay( DayOfWeek.MONDAY );  // 2014-12-29 start-of-week.
LocalDate friday = yw.atDay( DayOfWeek.FRIDAY );  // 2015-01-02
LocalDate sunday = yw.atDay( DayOfWeek.SUNDAY );  // 2015-01-04 end-of-week.

      

screenshot of calendar month January 2015 with ISO 8601 week number 1 launched from 2014-12-29 Monday to 2015-01-04 Sunday

+2


source


This can also be achieved by setting the default parsing value for the day of the week using "ChronoField.Day_Of_Week" and setting the value to "1" as follows:

System.out.println( "Date From Year and Week : "+
              LocalDate.parse("2015 1", 
                new DateTimeFormatterBuilder().appendPattern("YYYY w")
                .parseDefaulting(ChronoField.DAY_OF_WEEK, 1)
                .toFormatter()));

      

0


source







All Articles