Reputation: 1954
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
Upvotes: 11
Views: 3125
Reputation: 859
Below code works for me.
public static int getTotalWeeksInYear(int year){
int totalWeeks=0;
Calendar calendar=Calendar.getInstance();
for(int month=0;month<12;mmonth++){
int day=1;
do{
calendar.set(year, month, day);
if(calendar.get(Calendar.DAY_OF_WEEK)==5)
totalWeeks++;
day++;
}while (day <=calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
}
return totalWeeks;
}
Using Java.time
public static long getTotalWeekByLocalDate(LocalDate ldate) {
long weeksInYear = IsoFields.WEEK_OF_WEEK_BASED_YEAR.rangeRefinedBy(ldate).getMaximum();
return weeksInYear;
}
Upvotes: 0
Reputation: 340098
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.
Upvotes: 7
Reputation: 86379
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.
Upvotes: 4
Reputation: 274358
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;
Upvotes: 6
Reputation: 1954
After trying a lot in java 8. I could not find a solution. then I prepared Joda date and time dependency. It gave me a good answer as I expected
code:
for (int i = 2020; i < 2100; i++) {
int weeks = new DateTime().withYear(i).weekOfWeekyear().getMaximumValue();
System.out.println(i + " years : " + weeks);
}
Maven Dependency:
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.5</version>
</dependency>
Upvotes: -1
Reputation: 826
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);
Upvotes: 1