ISO-8601 week data representation for basic temporal operations
Asked Answered
G

2

6

I've got week data in ISO 8601 format. E.g.:

weekA = '2012-W48'
weekB = '2013-W03'

Is there a class in Java that can represent those weeks and supports basic temporal operations? I tried LocalDate.parse("2012-W48",DateTimeFormatter.ISO_WEEK_DATE); but this throws an error because this is a week, not an actual date (i.e. the day in the week is missing). Similar to the LocalDate class, I'd like to be able to do some basic temporal operations such as:

  • weekA.isBefore(weekB) returns true if weekA is before weekB
  • weeksBetween(weekA,weekB) returns the number of weeks between the two week dates, i.e. weekB-weekA in weeks.

Ideally I'd only use standard Java classes (Java >= 11).

Glennieglennis answered 12/3 at 16:32 Comment(2)
you can use new DateTimeFormatterBuilder().appendPattern("YYYY-'W'ww").parseDefaulting(ChronoField.DAY_OF_WEEK, 1).toFormatter() instead of ISO_WEEK_DATELeadership
Personally I wouldn't attempt to do this in standard Java. Firstly it isn't supported as far as week numbers are concerned and secondly such things are probably a lot more complex than one imagines so being assumptive will be problematic.Col
A
7

Using standard library

The original solution (check below) was using an external library. The credit for this solution goes to user85421. The idea is to parse the given string into a LocalDate by defaulting the day of the week to day-1.

public class Main {
    public static void main(String[] args) {
        String strWeekA = "2012-W48";
        String strWeekB = "2013-W03";

        DateTimeFormatter dtf = new DateTimeFormatterBuilder()
                .appendPattern("YYYY-'W'ww")
                .parseDefaulting(ChronoField.DAY_OF_WEEK, 1)
                .toFormatter();

        LocalDate date1 = LocalDate.parse(strWeekA, dtf);
        LocalDate date2 = LocalDate.parse(strWeekB, dtf);

        System.out.println(WEEKS.between(date1, date2));
    }
}

Output:

7

Online Demo

Using an external library (original solution)

You can use the ThreeTen-Extra library for your requirements.

You can use YearWeek, and its isBefore and isAfter methods.

You can use java.time.temporal.ChronoUnit#between to calculate the amount of time between two YearWeek objects. Alternatively, you can use YearWeek#until to get the same result.

Given below is the Maven dependency for it:

<dependency>
  <groupId>org.threeten</groupId>
  <artifactId>threeten-extra</artifactId>
  <version>1.7.2</version>
</dependency>

Demo:

import org.threeten.extra.YearWeek;
import static java.time.temporal.ChronoUnit.WEEKS;

public class Main {
    public static void main(String[] args) {
        String strWeekA = "2012-W48";
        String strWeekB = "2013-W03";
        YearWeek weekA = YearWeek.parse(strWeekA);
        YearWeek weekB = YearWeek.parse(strWeekB);
        System.out.println(weekA.isBefore(weekB));
        System.out.println(WEEKS.between(weekA, weekB));
        System.out.println(weekA.until(weekB, WEEKS));
    }
}

Output:

true
7
7
Astrea answered 12/3 at 16:49 Comment(0)
E
1

In Java, there isn't a direct class for representing ISO week dates like 2012-W48 in the java.time package without specifying the day of the week. However, you can work around this by appending a day of the week (like -1 for Monday) to your week strings and then using LocalDate with DateTimeFormatter.ISO_WEEK_DATE. Once you have LocalDate objects, you can perform the operations you mentioned. Here's how you can achieve this:

public class WeekOperations {

    public static void main(String[] args) {
        String weekA = "2012-W48";
        String weekB = "2013-W03";
        
        LocalDate dateA = parseWeek(weekA);
        LocalDate dateB = parseWeek(weekB);
        
        System.out.println("Week A is before Week B: " + dateA.isBefore(dateB));
        System.out.println("Weeks between Week A and Week B: " + weeksBetween(dateA, dateB));
    }
    
    private static LocalDate parseWeek(String week) {
        return LocalDate.parse(week + "-1", DateTimeFormatter.ISO_WEEK_DATE);
    }
    
    private static long weeksBetween(LocalDate start, LocalDate end) {
        return ChronoUnit.WEEKS.between(start, end);
    }
}

Please note that this approach assumes you're working with the first day of each ISO week. If you need to represent the entire week or perform operations on a different basis, you might need to adjust the logic accordingly. However, for comparison and difference calculation as you described, this method should work well.

Exarchate answered 12/3 at 21:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.