I am working on a project. There I should find the total weeks of a year. I tried with the following code, but I get the wrong answer: 2020 has 53 weeks, but this code gives 52 weeks.
Where have I gone wrong in this code?
package com.hib.mapping;
import java.time.LocalDate;
import java.time.temporal.WeekFields;
import java.util.Calendar;
import java.util.GregorianCalendar;
import org.joda.time.DateTime;
public class TestWeek {
public static void main(String args[]) {
System.out.println(getWeeks());
}
public static int getWeeks() {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 2020);
cal.set(Calendar.MONTH, Calendar.JANUARY);
cal.set(Calendar.DAY_OF_MONTH, 1);
GregorianCalendar gregorianCalendar = new GregorianCalendar();
int weekDay = cal.get(Calendar.DAY_OF_WEEK) - 1;
if (gregorianCalendar.isLeapYear(2020)) {
if (weekDay == Calendar.THURSDAY || weekDay == Calendar.WEDNESDAY)
return 53;
else
return 52;
} else {
if (weekDay == Calendar.THURSDAY)
return 53;
else
return 52;
}
}
}
52
To know how many weeks there are in a year, you just divide the number of days there are in a year (365) by how many days there are in a week (7). The result will be the average number of weeks there are in a year, which is approximately 52.143, or 52 weeks plus 1 day.
Now we can use the ChronoUnit enum to calculate elapsed weeks. long weeks = ChronoUnit. WEEKS. between( startZdt , stopZdt );
Week number 1 has the first Thursday of the new calendar year. This definition means week-based year has either 52 or 53 whole weeks, always 7-days long (Monday-Sunday),for a year length of either 364 days or 371 days. In contrast, a calendar year has either 365 or 366 days crossing 52 partial weeks.
Days to years (ignoring leap year) and weeks conversion formula is expressed as: 1 year = 365 days 1 week = 7 days Using above formula we can construct our Java expression to convert days to years, weeks and days. years = days / 365; weeks = (days - (years * 365)) / 7; days = days - ((years * 365) + (weeks * 7));
Divide number of days with 365 to get total years i.e. years = days / 365;. Next, we will find remaining weeks. To find remaining weeks, divide remaining days after calculated years by 7, say weeks = (days - (years * 365)) / 7;. You can also use a simple approach i.e. weeks = (days % 365) / 7;.
There are many ways to get a year from date of which frequently used two methods are listed below. Let us discuss each of them in detail alongside implementing the methods The get () method of LocalDate class in Java method gets the value of the specified field from this Date as an int.
LocalDate date = LocalDate.of (year, month, day); int weekOfYear = date.get (WeekFields.of (locale).weekOfYear ()); The benefit over our pre-Java 8 examples is that we don't have the problem of the month field being zero-based. 3.2. Get Week Number Using Chronofield
This should work for any week numbering scheme that can be represented in a WeekFields
object.
public static int noOfWeeks(WeekFields wf, int year) {
LocalDate lastDayOfYear = YearMonth.of(year, Month.DECEMBER).atEndOfMonth();
if (lastDayOfYear.get(wf.weekBasedYear()) > year) { // belongs to following week year
return lastDayOfYear.minusWeeks(1).get(wf.weekOfWeekBasedYear());
}
else {
return lastDayOfYear.get(wf.weekOfWeekBasedYear());
}
}
The idea is to find the week number of the last week of the week based year. I try first with 31 December, but that may be in the first week of the following year. If so, I go one week back.
I have tested pretty thoroughly with WeekFields.ISO
, not so much with other WeekFields
objects, but as I said, I believe it works.
If you know for a fact that you will always need ISO 8601 weeks, I think you should go with one of the good answers by Sweeper and by Basil Bourque. I posted this in case you needed a more flexible solution that would work with other week numbering schemes too.
The code in your question is funny in that it imports classes both from Joda-Time and from java.time, yet uses the old Calendar
and GregorianCalendar
from Java 1.1. These classes were poorly designed and are now long outdated, you should not use them. Joda-Time is in maintenance mode, java.time has taken over after it. Which is what I use and recommend that you use.
Using the Wikipedia definition here. A year has 53 weeks if 1st Jan is a Thursday, or 31st Dec is a Thursday, otherwise it has 52 weeks. This definition is equivalent to the one you used. I think this is a way easier condition to check for, as you don't need to check for leap years.
Using the Java 8 java.time
APIs:
int year = 2020;
boolean is53weekYear = LocalDate.of(year, 1, 1).getDayOfWeek() == DayOfWeek.THURSDAY ||
LocalDate.of(year, 12, 31).getDayOfWeek() == DayOfWeek.THURSDAY;
int weekCount = is53weekYear ? 53 : 52;
For a standard ISO 8601 week, use the YearWeek
class from ThreeTen-Extra library with a ternary statement.
YearWeek // Represents an entire week of a week-based-year.
.of( 2020 , 1 ) // Pass the number of the week-based-year (*not* calendar year), and a week number ranging from 1 to 52 or 1 to 53.
.is53WeekYear() // Every standard week-based-year has either 52 or 52 complete weeks.
? 53 // Ternary statement returns 53 if the predicate returns True, …
: 52 // … otherwise returns 52.
That is, YearWeek.of( 2020 , 1 ).is53WeekYear() ? 53 : 52
You need to define a week. In your code sample, the definition of week varies by the JVM’s current default Locale
. So your results may vary at runtime.
Your code also uses terrible date-time classes that were supplanted years ago by the modern java.time classes. Stop using GregorianCalendar
& Calendar
; they were replaced for good reasons.
The ISO 8601 standard defines a week as:
That definition means:
If your definition differs, see the Answer by Ole V.V..
YearWeek:is53WeekYear
If this matches your definition, then add the ThreeTen-Extra library to your project to extend the java.time functionality built into Java 8 and later. You then have access to the YearWeek
class.
ZoneId z = ZoneId.of( "America/Montreal" ) ;
YearWeek yearWeekNow = YearWeek.now( z ) ;
boolean is53WeekYear = yearWeekNow.is53WeekYear() ;
int weeksLong = yearWeekNow.is53WeekYear() ? 53 : 52 ;
To ask about a particular week-based-year, just arbitrarily pick any week of the year. For example, for the week-based year 2020 we ask for week # 1.
int weeksLong = YearWeek.of( 2020 , 1 ).is53WeekYear() ? 53 : 52 ;
LocalDate weekStart = YearWeek.of( 2020 , 1 ).atDay( DayOfWeek.MONDAY ) ;
weeksLong = 53
weekStart = 2019-12-30
Notice how the first day of the week-based-year of 2020 is from the calendar-year 2019.
I think this should work just fine as well:
int year = 2020;
long numOfWeeks = LocalDate.of(year, 1, 1).datesUntil(LocalDate.of(year, 12, 31), Period.ofDays(7)).count();
System.out.println("Weeks: " + numOfWeeks);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With