Reputation: 1047
Can anyone explain why do I get those values while trying to parse a date? I've tried three different inputs, as follows:
1) Third week of 2013
Date date = new SimpleDateFormat("ww.yyyy").parse("02.2013");
Calendar cal = Calendar.getInstance();
cal.setTime(date);
System.out.println(cal.get(Calendar.WEEK_OF_YEAR) + "." + cal.get(Calendar.YEAR));
Which outputs: 02.2013
(as I expected)
2) First week of 2013
Date date = new SimpleDateFormat("ww.yyyy").parse("00.2013");
Calendar cal = Calendar.getInstance();
cal.setTime(date);
System.out.println(cal.get(Calendar.WEEK_OF_YEAR) + "." + cal.get(Calendar.YEAR));
Which outputs: 52.2012
(which is fine for me, since the first week of 2013 is also the last one of 2012)
3) Second week of 2013
Date date = new SimpleDateFormat("ww.yyyy").parse("01.2013");
Calendar cal = Calendar.getInstance();
cal.setTime(date);
System.out.println(cal.get(Calendar.WEEK_OF_YEAR) + "." + cal.get(Calendar.YEAR));
Which outputs: 1.2012
(which makes absolutely no sense to me)
Does anyone know why this happens?? I need to parse a date in the format (week of year).(year). Am I using the wrong pattern?
Upvotes: 7
Views: 779
Reputation: 79085
java.time
In March 2014, Java 8 introduced the modern, java.time
date-time API which supplanted the error-prone legacy java.util
date-time API. Any new code should use the java.time
API.
java.time
is based on ISO 8601 standard where month number, week number etc. start with the natural number 1
, unlike the confusing java.util
date-time API where they begin with 0
. Any attempt to parse a date-time with the month/week/day-of-week number 0
using java.time
API throws an exception, giving you a way to handle it as per your business requirement.
...which is fine for me, since the first week of 2013 is also the last one of 2012
No, the same week can not fall in two years.
java.time
APIWhile you can build a DateTimeFormatter
to parse your strings as they are, an easier way would be converting your strings into the format used by DateTimeFormatter#ISO_WEEK_DATE
with 1
as the day-of-the-week and parse them into LocalDate
instances.
Finally, get the week numbers from the LocalDate
instances. Note that the week number is Locale
-sensitive e.g. a week starts on Sunday in the US but in the UK, it starts on Monday. Check the US Calendar 2025 and the UK Calendar 2025 to find the difference.
Demo:
class Main {
public static void main(String[] args) {
Locale locale = Locale.US;
String[] arr = { "01.2013", "02.2013", "03.2013", "00.2013" };
for (String str : arr) {
str = str.replaceAll("(\\d{2})(\\.)(\\d{4})", "$3-W$1-1");
try {
LocalDate date = LocalDate.parse(str,
DateTimeFormatter.ISO_WEEK_DATE);
int weekNum = date.get(WeekFields.of(locale).weekOfWeekBasedYear());
System.out.println("Week number: " + weekNum);
} catch (DateTimeParseException e) {
System.out.println("Parsing error: " + e.getMessage());
}
}
}
}
Output:
Week number: 1
Week number: 2
Week number: 3
Parsing error: Text '2013-W00-1' could not be parsed: Invalid value for
WeekOfWeekBasedYear (valid values 1 - 52): 0
The regex pattern: There are three capture-groups in the above regex e.g. (01)(.)(2013)
for 01.2013
. I have used capture-group numbers 1 and 3 (denoted by $1
and $3
in the code) to get the final string to be parsed.
Learn more about the modern Date-Time API from Trail: Date Time.
The code using the DateTimeFormatter
from the
comment posted by Anonymous will be as follows:
class Main {
private static final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
.appendPattern("ww.YYYY")
.parseDefaulting(ChronoField.DAY_OF_WEEK, 1)
.toFormatter(Locale.ROOT);
public static void main(String[] args) {
Locale locale = Locale.US;
String[] arr = { "01.2013", "02.2013", "03.2013", "00.2013" };
for (String str : arr) {
try {
LocalDate date = LocalDate.parse(str, FORMATTER);
int weekNum = date.get(WeekFields.of(locale).weekOfWeekBasedYear());
System.out.println("Week number: " + weekNum);
} catch (DateTimeParseException e) {
System.out.println("Parsing error: " + e.getMessage());
}
}
}
}
The output will be the same.
Upvotes: 3
Reputation: 368
Use Calendar.getWeekYear() to get year value synced with Calendar.WEEK_OF_YEAR
field.
There is more information about Week of Year and Week Year at the GregorianCalendar doc.
Upvotes: 2
Reputation: 1500565
You're using ww
, which is "week of week-year", but then yyyy
which is "calendar year" rather than "week year". Setting the week-of-week-year and then setting the calendar year is a recipe for problems, because they're just separate numbering systems, effectively.
You should be using YYYY
in your format string to specify the week-year... although unfortunately it looks like you can't then get the value in a sane way. (I'd expect a Calendar.WEEKYEAR
constant, but there is no such thing.)
Also, week-of-year values start at 1, not 0... and no week is in two week-years; it's either the first week of 2013 or it's the last week of 2012... it's not both.
I would personally avoid using week-years and weeks if you possibly can - they can be very confusing, particularly when a date in one calendar year is in a different week year.
Upvotes: 16