Get weeks of the month depending on week start

2020-04-16 20:01发布

问题:

I am using a custom calendar in my app. I have given the users option to select the first day of the week which could be: Saturday, Sunday, Monday

I want to get the number of weeks in a month - depending on when the week starts, overriding the default value of week start - Sunday.

Code:

public int getWeeksOfMonth(int year, int month) { 
    Calendar calendar = Calendar.getInstance(); 
    calendar.set(Calendar.MONTH, month-1);
    calendar.set(Calendar.YEAR, year);
    int numOfWeeksInMonth = calendar.getActualMaximum(Calendar.WEEK_OF_MONTH); 

    return numOfWeeksInMonth;
}

回答1:

Try

calendar.setFirstDayOfWeek(Calendar.MONDAY); //sets first day to monday, for example.

In your case you might want to do this:

public int getWeeksOfMonth(int year, int month, int weekStart) { 
    Calendar calendar = Calendar.getInstance();  
    calendar.set(Calendar.MONTH, month-1);
    calendar.set(Calendar.YEAR, year);
    calendar.setFirstDayOfWeek(weekStart);
    int numOfWeeksInMonth = calendar.getActualMaximum(Calendar.WEEK_OF_MONTH); 

    return numOfWeeksInMonth;
}

And call the method with a line such as

int weeks = getWeeksOfMonth(2012, 5, Calendar.WEDNESDAY);


回答2:

Try to set the first day of the week first:

Calendar.setFirstDayOfWeek()



回答3:

tl;dr

ChronoUnit.WEEKS.between( calendarStart , calendarStop )

Avoid legacy classes

Avoid the troublesome old date-time classes that are now legacy, supplanted by the modern java.time classes.

java.time

Track the day-of-week by using the DayOfWeek enum.

DayOfWeek firstDayOfWeek = DayOfWeek.MONDAY ;

Get the month you are interested in, represented by a YearMonth. Perhaps the current month. For current month, you must specify the desired/expected time zone as for any given moment the date may vary around the globe by zone.

ZoneId z = ZoneId.of( "America/Montreal" ) ;
YearMonth ym = YearMonth.now( z ) ;

Get first and last day of the month.

LocalDate monthStart = ym.atDay( 1 ) ;
LocalDate monthStop = ym.atEndOfMonth() ;

Get date for the day-of-week. For that, use a TemporalAdjuster, one provided by the TemporalAdjusters class (note the plural s).

Spans of time in java.time are wisely defined using Half-Open approach, where the beginning is inclusive while the ending is exclusive. So note how we need to get the date of the desired day-of-week after the end of the month. If the end-of-month happened to itself be the desired day-of-week, we need to go past it.

LocalDate calendarStart = monthStart.with( TemporalAdjusters.previousOrSame( firstDayOfWeek ) ) ;
LocalDate calendarStop = monthStop.with( TemporalAdjusters.next( firstDayOfWeek ) ) ;

Calculate the number of weeks between.

long weeks = ChronoUnit.WEEKS.between( calendarStart , calendarStop ) ;

See this code run live at IdeOne.com.

firstDayOfWeek: MONDAY

ym: 2017-09

month: 2017-09-01/2017-09-30

calendar: 2017-08-28/2017-10-02

weeks: 5


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.

Where to obtain the java.time classes?

  • Java SE 8, Java SE 9, and later
    • Built-in.
    • Part of the standard Java API with a bundled implementation.
    • Java 9 adds some minor features and fixes.
  • Java SE 6 and Java SE 7
    • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android
    • The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
    • See How to use ThreeTenABP….

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.