简体   繁体   中英

Joda-Time - How to find “Second Thursday of Month”

I'm not seeing a good way to set a date to a certain day of the week for a certain week of the month. Joda-Time 's LocalDate does not have a withWeekOfMonth method. I can see a possible algorithm, but it seems way to complicated, so I'm going to assume I'm missing something. What I need is to determine the next date someone is paid. And if they are paid on the Second Thursday of the Month, what date is that.

Anyone already solved this problem?

Ok, I was able to come up with this, which seems to work fine.

/**  
 * Finds a date such as 2nd Tuesday of a month.  
 */  
public static LocalDate calcDayOfWeekOfMonth( final DayOfWeek pDayOfWeek, final int pWeekOfMonth, final LocalDate pStartDate )  
{  
    LocalDate result = pStartDate;  
    int month = result.getMonthOfYear();  
    result = result.withDayOfMonth( 1 );  
    result = result.withDayOfWeek( pDayOfWeek.ordinal() );  
    if ( result.getMonthOfYear() != month )  
    {  
        result = result.plusWeeks( 1 );  
    }  
    result = result.plusWeeks( pWeekOfMonth - 1 );  
    return result;  
}  

I personally don't know of any super-simple way of doing it, this is what I use to get it:

/**
 * Calculates the nth occurrence of a day of the week, for a given month and
 * year.
 * 
 * @param dayOfWeek
 *            The day of the week to calculate the day for (In the range of
 *            [1,7], where 1 is Monday.
 * @param month
 *            The month to calculate the day for.
 * @param year
 *            The year to calculate the day for.
 * @param n
 *            The occurrence of the weekday to calculate. (ie. 1st, 2nd,
 *            3rd)
 * @return A {@link LocalDate} with the nth occurrence of the day of week,
 *         for the given month and year.
 */
public static LocalDate nthWeekdayOfMonth(int dayOfWeek, int month, int year, int n) {
    LocalDate start = new LocalDate(year, month, 1);
    LocalDate date = start.withDayOfWeek(dayOfWeek);
    return (date.isBefore(start)) ? date.plusWeeks(n) : date.plusWeeks(n - 1);
}

Example:

System.out.println(nthWeekdayOfMonth(4, 1, 2012, 2));

Output:

2012-01-12

Solution using Java-8 java.time API

With the modern date-time API of Java, you can pass TemporalAdjusters#dayOfWeekInMonth as an argument to LocalDate#with to achieve this.

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;

public class Main {
    public static void main(String[] args) {
        // Test with today's date, 26-Dec-2020
        System.out.println(
            localDateOnNthDayOfWeekOfMonth(DayOfWeek.THURSDAY, 2, LocalDate.now())
        );
    }

    public static LocalDate localDateOnNthDayOfWeekOfMonth
    (
        final DayOfWeek dayOfWeek, 
        final int ordinal,
        final LocalDate startDate
    ) {
        return startDate.with(
            TemporalAdjusters.dayOfWeekInMonth(ordinal, dayOfWeek)
        );
    }
}

Output:

2020-12-10

Learn about Java-8 date-time API from Trail: Date Time .

Note for Java 6 or 7 users:

For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project .

Example how to detect 2nd Monday

val DateTime.is2ndMonday
    get() = dayOfWeek == 1 && dayOfMonth > 7

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM