Say a month end date is the date in a month which is the last non-weekend and non-holiday day in that month. How can I find the most recent past month end date with Joda time? For example, the answer for today would be Friday 28th May because that was May's month end and May was the most recent month to end.
-
What if today is already 28th May? Would you return today or still this from last month? – BalusC Jun 14 '10 at 11:40
-
@BalusC in that case I would want the April month end. – ppTaylor Jun 14 '10 at 11:46
-
@polygenelubricants then I would want 28th May – ppTaylor Jun 14 '10 at 14:03
-
possible duplicate of [Get the week start and end date given a current date and week start](http://stackoverflow.com/questions/9235845/get-the-week-start-and-end-date-given-a-current-date-and-week-start) and [this](http://stackoverflow.com/q/12676169/642706) and [this](http://stackoverflow.com/q/17520937/642706) and [this](http://stackoverflow.com/q/14521539/642706) and [this](http://stackoverflow.com/q/3083781/642706). – Basil Bourque Jun 09 '14 at 23:56
3 Answers
DateTime.dayOfMonth.getMaximumValue() gives the last day of the month. Get the weekday of that day to check whether it is in the weekend.

- 74,049
- 16
- 131
- 175
Generally speaking:
- Find current month
- Go back a month
- Start from last day of that month:
- If it's neither a weekend nor a holiday, that's the end date
- Otherwise, go back a day and repeat
Or maybe it's:
- Start from today:
- If it's neither...
This isn't the most efficient, but it's cheap to cache the value once you compute it, because it'll be valid for a whole month. You can easily compute "all" month end dates and store it in a lookup table too. You definitely want to compute when the next one will be, because that's when the current cached value expires.
Example
Here's a snippet I quickly concocted:
import org.joda.time.*;
public class LastMonthEnd {
static int count = 0;
static boolean isWeekendOrHoliday(DateTime d) {
return (count++ < 5);
}
public static void main(String[] args) {
DateTime d = new DateTime().minusMonths(1).dayOfMonth().withMaximumValue();
while (isWeekendOrHoliday(d)) {
d = d.minusDays(1);
}
System.out.println(d);
}
}
Today (2010-06-14 12:04:57Z
), this prints "2010-05-26T12:00:42.702Z"
. Note that isWeekendOrHoliday
is just a stub for an actual implementation. I'd imagine that the real test will be rather complicated (the holiday part), and may be worth a question on its own.

- 376,812
- 128
- 561
- 623
Based on your question and comments, you are trying to solve problem like this:
- if today is a working day, then return the last working day of last month
- if today is not a working day, then:
- if the most recent working day is the last day of the month, return the most recent working day
- else return the last working day of last month
Here is an implementation with financial scheduling library Lamma (http://lamma.io). The method Date.backward(Calendar)
is used to find the most recent working day.
If you really want do implement in Joda, then you basically need to implement Date.pastMonthEnd() and Date.backward(Calendar) by yourself.
public static void main(String [] args) {
// print 2014-05-30, because 2014-05-31 is holiday
System.out.println(findDate(new Date(2014, 5, 31)));
// print 2014-04-30
System.out.println(findDate(new Date(2014, 5, 30)));
// print 2014-04-30, because the most recent working day of 2014-05-25 is not the last working day of May
System.out.println(findDate(new Date(2014, 5, 25)));
}
private static HolidayRule cal = weekends(); // let's use weekend calendar for now
public static Date findDate(Date current) {
if (cal.isHoliday(current)) {
Date lastWorkingDayOfThisMonth = current.lastDayOfMonth().backward(cal);
Date mostRecentWorkingDay = current.backward(cal);
if (lastWorkingDayOfThisMonth.equals(mostRecentWorkingDay)) {
return mostRecentWorkingDay;
} else {
return lastWorkingDayOfLastMonth(current);
}
} else {
return lastWorkingDayOfLastMonth(current);
}
}
public static Date lastWorkingDayOfLastMonth(Date d) {
return d.lastDayOfPreviousMonth().backward(cal);
}

- 2,065
- 24
- 20