7

In plain Java, I have this code to get the last Sunday of the month.

Calendar getNthOfMonth(int n, int day_of_week, int month, int year) {
    Calendar compareDate = Date(1, month, year);
    compareDate.set(DAY_OF_WEEK, day_of_week);
    compareDate.set(DAY_OF_WEEK_IN_MONTH, n);
    return compareDate;
}
// Usage
Calendar lastSundayOfNovember = getNthOfMonth(-1, SUNDAY, NOVEMBER, 2012)

What is a clean and elegant way to achieve the same result using Joda-Time?

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
knub
  • 3,892
  • 8
  • 38
  • 63

7 Answers7

6

This is quite an old post but possibly this answer will help someone. Use the java.time classes that replace Joda-Time.

private static LocalDate getNthOfMonth(int type, DayOfWeek dayOfWeek, int month, int year){
    return LocalDate.now().withMonth(month).withYear(year).with(TemporalAdjusters.dayOfWeekInMonth(type, dayOfWeek));
}
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
naren
  • 301
  • 4
  • 8
5
public class Time {
public static void main(String[] args) {
    System.out.println(getNthOfMonth(DateTimeConstants.SUNDAY, DateTimeConstants.SEP, 2012));
}


public static LocalDate getNthOfMonth(int day_of_week, int month, int year) {
    LocalDate date = new LocalDate(year, month, 1).dayOfMonth()  
             .withMaximumValue()
             .dayOfWeek()
             .setCopy(day_of_week);
    if(date.getMonthOfYear() != month) {
        return date.dayOfWeek().addToCopy(-7);
    }
    return date;
}
}
KrHubert
  • 1,030
  • 7
  • 17
5

You can try something like that:

public class Foo {

  public static LocalDate getNthSundayOfMonth(final int n, final int month, final int year) {
    final LocalDate firstSunday = new LocalDate(year, month, 1).withDayOfWeek(DateTimeConstants.SUNDAY);
    if (n > 1) {
      final LocalDate nThSunday = firstSunday.plusWeeks(n - 1);
      final LocalDate lastDayInMonth = firstSunday.dayOfMonth().withMaximumValue();
      if (nThSunday.isAfter(lastDayInMonth)) {
        throw new IllegalArgumentException("There is no " + n + "th Sunday in this month!");
      }
      return nThSunday;
    }
    return firstSunday;
  }


  public static void main(final String[] args) {
    System.out.println(getNthSundayOfMonth(1, DateTimeConstants.SEPTEMBER, 2012));
    System.out.println(getNthSundayOfMonth(2, DateTimeConstants.SEPTEMBER, 2012));
    System.out.println(getNthSundayOfMonth(3, DateTimeConstants.SEPTEMBER, 2012));
    System.out.println(getNthSundayOfMonth(4, DateTimeConstants.SEPTEMBER, 2012));
    System.out.println(getNthSundayOfMonth(5, DateTimeConstants.SEPTEMBER, 2012));
  }
}

Output:

2012-09-02
2012-09-09
2012-09-16
2012-09-23
2012-09-30
Ortwin Angermeier
  • 5,957
  • 2
  • 34
  • 34
  • Use java.time classes and `TemporalAdjuster` instead, to shorten this code. See [this Answer](https://stackoverflow.com/a/45792784/642706). – Basil Bourque Aug 21 '17 at 14:30
3

With Joda

Let's say we have a date:

DateTime date = new DateTime(2017, 6, 1, 0, 0, 0);

`First we need to know if the month has 31, 30, 28 or 29 days :

int lastofMonth = date.dayOfMonth().getMaximumValue();

From this we create a new date:

DateTime endOfMonth = new DateTime(2017, 6, lastOfMonth, 0, 0, 0);

The we find out what day of week the last day is:

int whatDayIsLast = endOfMonth.getDayOfWeek();

Now we can create a date, which will be the date of the last Sunday of the month:

DateTime lastSunday = new DateTime(2017, 6, lastOfMonth - whatDayIsLast, 0, 0, 0);

For my example (June 2017), the result will be:

DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyy-MM-dd");
System.out.println(dtf.print(lastSunday);

2017-06-25

ESDEE
  • 125
  • 7
2
   static LocalDate getNthOfMonth(int n, int day_of_week, int month, int year)
   {
      if (n == -1)
      {
         return getNthOfMonth(0, day_of_week, month + 1, year);
      }
      final LocalDate compareDate = new LocalDate(year, month, 1);
      if (compareDate.getDayOfWeek() > day_of_week)
      {
         return compareDate.withDayOfWeek(day_of_week).plusDays(7 * n);   
      }
      else
      {
         return compareDate.withDayOfWeek(day_of_week).plusDays(7 * (n - 1));    
      }
   }  
Ilya
  • 29,135
  • 19
  • 110
  • 158
  • Use java.time classes and `TemporalAdjuster` instead, to shorten this code. See [this Answer](https://stackoverflow.com/a/45792784/642706). – Basil Bourque Aug 21 '17 at 14:28
2

// Following method will give last Sunday of the given month and year

public Date getLastSunday(int month, int year) {
    Calendar cal = Calendar.getInstance();
    cal.set(year, month + 1, 1);
    int dayOftheWeek = cal.get(Calendar.DAY_OF_WEEK);
    int val = dayOftheWeek == Calendar.SUNDAY ? -7: -(dayOftheWeek-1);
    cal.add(Calendar.DAY_OF_MONTH, val);
    return cal.getTime();
}

// obj.getLastSunday(Calendar.OCTOBER, 2014);

Bupathi
  • 21
  • 3
2

Solution using Java-8 java.time API

Get the local date on the last Sunday of the specified year and month:

In order to achieve this with the modern date-time API of Java, you can pass TemporalAdjusters.lastInMonth(DayOfWeek.SUNDAY) as an argument to any LocalDate of the specified year and month.

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

public class Main {
    public static void main(String[] args) {
        // Test
        System.out.println(getLastSundayOfMonth(2020, 12));
    }

    public static LocalDate getLastSundayOfMonth(int year, int month) {
        return YearMonth.of(year, month)
                .atEndOfMonth() //Returns a LocalDate at the end of the month
                .with(TemporalAdjusters.lastInMonth(DayOfWeek.SUNDAY));
    }
}

Output:

2020-12-27

I've used YearMonth#atEndOfMonth to get the LocalDate. Instead of this, YearMonth#atDay can also be used.

Get the local date on the nth day-of-week (e.g. 2nd Thu) of the specified year and month:

you can pass TemporalAdjusters#dayOfWeekInMonth as an argument to any LocalDate of the specified year and month.

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

public class Main {
    public static void main(String[] args) {
        // Test
        System.out.println(localDateOnNthDayOfWeekOfMonth(DayOfWeek.THURSDAY, 2, 2020, 12));
    }

    public static LocalDate localDateOnNthDayOfWeekOfMonth(DayOfWeek dayOfWeek, int ordinal, int year, int month) {
        return YearMonth.of(year, month)
                .atEndOfMonth() // Returns a LocalDate at the end of the month
                .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.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110