3

I have to parse date using the following format: "201710" where 10 - week of year number. I tried to implement it in this way:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyw");
java.time.LocalDate startDate = java.time.LocalDate.parse("201710", formatter);
System.out.println(startDate);

But it throws exception:

java.time.format.DateTimeParseException: Text '201710' could not be parsed at index 0   

And after that I need to get first and last day of week from LocalDate object. e.g "201710" - 05.03 12.03 (first day of week needs to be Sunday).

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
Will Graham
  • 340
  • 1
  • 3
  • 16
  • 1
    your code and your exception to not match up. the code says "201710", but the exception says "2017101". Maybe a typo? – Japu_D_Cret Mar 23 '17 at 14:08
  • just typo, exception is java.time.format.DateTimeParseException: Text '201710' could not be parsed at index 0 I see "yyyyw" format is not supportable. What is the problem? – Will Graham Mar 23 '17 at 14:09
  • 1
    The new `java.time` classes seem to be just about as user friendly as the old ones. – Kayaman Mar 23 '17 at 14:17
  • @Kayaman, Please help with pattern. – Will Graham Mar 23 '17 at 14:22
  • @Kayaman, thanks for pointing to the other question. The answers there solve the problem when there is a space between year and week, not when year and week is one string of 6 digits with nothing to separate. – Ole V.V. Mar 23 '17 at 14:39
  • @OleV.V. no matter if my format is "201710" "yyyyw" or "2017 10" "yyyy ww", I still get exception. – Will Graham Mar 23 '17 at 14:42
  • @OleV.V. Well, you're right. I've got at least one working solution... anyway, here was the previous duplicate http://stackoverflow.com/questions/27928720/how-to-parse-date-from-string-with-year-and-week-using-java-time – Kayaman Mar 23 '17 at 14:43
  • By the way, you might want to consider using standard [ISO 8601 format for a week](https://en.wikipedia.org/wiki/ISO_week_date): yyyy-Www such as `2017-W07`. Supported by the [*ThreeTen-Extra*](https://www.threeten.org/threeten-extra/) library class [`YearWeek`](https://www.threeten.org/threeten-extra/apidocs/org/threeten/extra/YearWeek.html). – Basil Bourque Sep 30 '18 at 23:23

3 Answers3

4

The accepted answer of @Kayaman is not correct because you cannot mix standard date representations (using yyyy = year-of-era) and week-date representations (using ww = week of week-based year). The subtile difference between a standard calendar year and a weekbased year is relevant near the start or end of a calendar year. Conclusion: Don't use the symbol "y", but rather the symbol "Y". Counter example for the input "201501":

Correct solution

DateTimeFormatter formatter =
    new DateTimeFormatterBuilder()
    .appendValue(WeekFields.ISO.weekBasedYear(), 4)
    .appendValue(WeekFields.ISO.weekOfWeekBasedYear(), 2)
    .parseDefaulting(ChronoField.DAY_OF_WEEK, 1)
    .toFormatter();
LocalDate startDate = LocalDate.parse("201501", formatter);
System.out.println(startDate); // 2014-12-29

Based on the proposal of @Kayaman:

DateTimeFormatter dtf =
    new DateTimeFormatterBuilder()
    .appendValue(ChronoField.YEAR, 4)
    .appendValue(ChronoField.ALIGNED_WEEK_OF_YEAR, 2)
    .parseDefaulting(WeekFields.ISO.dayOfWeek(), 1)
    .toFormatter();
System.out.println(LocalDate.parse("201501", dtf)); // 2015-01-05 (wrong)

The resulting dates are different! The difference is caused by the definition of the calendar year which always starts on first of January while a week-based year always starts on Monday (ISO-8601-definition) using the first week of calendar year which has at least 4 days.

Additional note a): Java-8 does not manage adjacent digit parsing of localizible fields like the week-based fields (see also the associated JDK issue), therefore I have chosen the builder-based solution instead of defining the pattern "YYYYww" (Java-9 promises a solution, however). But even with Java-9, a build-based approach is still necessary because of the need to define a default for the missing day-of-week (here: setting to Monday).

Additional note b): If you are looking for a true type for the combination of week-based year and week-of-year and use LocalDate just as a workaround for this missing type, well, you can find such a type in 3rd-party libraries, either in Threeten-Extra or in my library Time4J. Example:

    ChronoFormatter<CalendarWeek> cf =
        ChronoFormatter.ofPattern(
            "YYYYww",
            PatternType.CLDR,
            Locale.ROOT,
            CalendarWeek.chronology()
        );
    CalendarWeek cw = cf.parse("201501");
    System.out.println(cw); // 2015-W01
    System.out.println(cw.at(Weekday.MONDAY)); // 2014-12-29
Meno Hochschild
  • 42,708
  • 7
  • 104
  • 126
2

The (previous) duplicate works if there's a space between the values, however without a space the following parses nicely.

DateTimeFormatter dtf = new DateTimeFormatterBuilder()
        .appendValue(ChronoField.YEAR, 4)
        .appendValue(ChronoField.ALIGNED_WEEK_OF_YEAR, 2)
        .parseDefaulting(WeekFields.SUNDAY_START.dayOfWeek(), 1)
        .toFormatter();

System.out.println(LocalDate.parse("201710", dtf));
// 2017-03-05

Replacing the SUNDAY_START with ISO will give you weeks starting with mondays (so it will print 2017-03-06).

Community
  • 1
  • 1
Kayaman
  • 72,141
  • 5
  • 83
  • 121
  • @Will Graham, please check if you want year and aligned week of year. It’s consistent and unusual. You may want week-based year and week number. It’s a good answer in that it gives you working code that you can then tailor to your need. – Ole V.V. Mar 24 '17 at 07:07
  • I have given a counter example in my answer. – Meno Hochschild Mar 24 '17 at 11:40
1

ThreeTen-Extra

The ThreeTen-Extra project adds functionality to the java.time classes.

YearWeek

This library offers the YearWeek class that may prove useful to you. This class uses the ISO 8601 standard definition of a week.

If possible, I suggest you change your own strings to use the standard format: yyyy-Www such as 2018-W07. The standard format is used by default in the YearWeek class for generating/parsing stings.

YearWeek yw = YearWeek.parse( "2018-W07" );

But if you insist on your own non-standard format, we must define our own DateTimeFormatter to match your input. I took one line of the YearWeek.parse method from the YearWeek.java source code, and modified to fit your case by disabling two method calls.

DateTimeFormatter f =
new DateTimeFormatterBuilder()
// .parseCaseInsensitive()
.appendValue( WEEK_BASED_YEAR , 4 , 10 , SignStyle.EXCEEDS_PAD )
// .appendLiteral("-W")
.appendValue( WEEK_OF_WEEK_BASED_YEAR , 2 )
.toFormatter();

Let’s try it.

YearWeek yw = YearWeek.parse( "201807" , f );

yw.toString(): 2018-W07


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154