Reputation: 695
I develop a local calendar for my application. but there is an issue with monthly repeat event (day of week).
When i create an event starting on 16-9-2016(16 SEP 2016 FRIDAY)
and repeating Third Friday of each month. but next month it create on second
Friday 14-10-2016 (This is the issue). next month it will be on third Friday.
my code is
public Date nthWeekdayOfMonth(int dayOfWeek, int month, int year, int week, TimeZone timeZone) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(timeZone);
calendar.set(Calendar.DAY_OF_WEEK, dayOfWeek);
calendar.set(Calendar.WEEK_OF_MONTH, week);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.YEAR, year);
return calendar.getTime();
}
I know the issue. but i don`t know how to fix it.. is there any way to fix it ?
Upvotes: 5
Views: 7971
Reputation: 86296
java.time, the modern Java date and time API, has a built-in adjuster for that:
public LocalDate nthWeekdayOfMonth(DayOfWeek dayOfWeek, Month month, int year, int week) {
return LocalDate.of(year, month, 15)
.with(TemporalAdjusters.dayOfWeekInMonth(week, dayOfWeek));
}
Try it out:
System.out.println(nthWeekdayOfMonth(DayOfWeek.FRIDAY, Month.OCTOBER, 2016, 3));
Output:
2016-10-21
Please also note that the arguments that I pass to the method are much more telling.
Link: Oracle tutorial: Date Time explaining how to use java.time.
Upvotes: 3
Reputation: 3247
Java 8
LocalDate thirdFriday = java.time.LocalDate.now()
.with(TemporalAdjusters.firstDayOfMonth())
.with(TemporalAdjusters.nextOrSame(DayOfWeek.FRIDAY))
.plusDays(14)
Upvotes: 4
Reputation: 21
with Java LocalDateTime
LocalDateTime firstDayOfMonth = LocalDateTime.of(year, Month.of(month), 1, 0, 0);
// Returns 1-7 (NOT 0-6)
int firstDayValue = firstDayOfMonth.getDayOfWeek().getValue();
int thirdFriday = 20 + firstDayValue / 6 * 7 - firstDayValue;
return LocalDateTime.of(year, Month.of(month), thirdFriday, 0, 0);
Upvotes: 0
Reputation: 159
Below function can be used to calculate third friday of month using joda time. The function is verbose for sake of clarity on logic.
public static DateTime thirdFridayOfMonth(int year, int month) {
DateTime firstDayOfMonth = new DateTime(year, month, 1, 0, 0);
MutableDateTime mFirstDayOfMonth = new MutableDateTime(firstDayOfMonth);
//Now calculate days to 1st friday from 1st day of month
int daysToFirstFridayOfMonth = mFirstDayOfMonth.dayOfWeek().get() <= 5 ? (5 - mFirstDayofMonth.dayOfWeek().get()) : (7 - mFirstDayofMonth.dayOfWeek().get() + 5);
//move to first 1st friday of month
mFirstDayOfMonth.addDays(daysToFirstFridayOfMonth);
//move to 3rd friday of month
mFirstDayOfMonth.addWeeks(2);
return mFirstDayOfMonth.toDateTime();
}
Upvotes: 0
Reputation: 365
This is a functioning Java 8 implementation. The example from KayV did not work for September 2017, but it helped me to head in the right direction.
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.Month;
import java.time.temporal.TemporalAdjusters;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class OptionExpirationDates {
public static void main(String[] args) {
LocalDate startDate = LocalDate.of(2017, Month.FEBRUARY, 15);
List<LocalDate> optionExDates = optionExpirationDates(startDate, 20);
for (LocalDate temp : optionExDates) {
System.out.println(temp);
}
}
public static List<LocalDate> optionExpirationDates(LocalDate startDate, int limit) {
return Stream.iterate(startDate, date -> date.plusDays(1))
.map(LocalDate -> LocalDate.with(TemporalAdjusters.firstDayOfMonth()).minusDays(1)
.with(TemporalAdjusters.next(DayOfWeek.FRIDAY)).plusWeeks(2))
.distinct()
.limit(limit)
.collect(Collectors.toList());
}
}
Perhaps we should also mention that this code is to calculate an option expiration date, so that the search engine can pick it up.
Upvotes: 2
Reputation: 13845
Java 8 way of doing this is as follows:
LocalDate thirdFriday = LocalDate
.now()
.with(lastDayOfMonth())
.with(previous(DayOfWeek.FRIDAY)).minusDays(7);
Upvotes: 1
Reputation: 2326
You code seems to be working completely fine, there is nothing that is going wrong from what I can see, it may be that your parameters are wrong.
It is important to note that MONTH
and DAY
are 0-based so, 0 = January
and 0 = Sunday
so your parameters for getting the third friday should look like the following:
nthWeekdayOfMonth(6, 9, 2016, 3, TimeZone.getTimeZone("Europe/London"));
Which returns the following output:
Fri Oct 21 11:06:33 BST 2016
To break it down:
Please see the Calendar documentation for reference.
So for some reason, it works on my machine but it doesn't on others; I don't know what the issue could be with that but using DAY_OF_WEEK_IN_MONTH
seems to be a better option for this:
public static Date nthWeekdayOfMonth(int dayOfWeek, int month, int year, int week, TimeZone timeZone) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(timeZone);
calendar.set(Calendar.DAY_OF_WEEK, dayOfWeek);
//calendar.set(Calendar.WEEK_OF_MONTH, week);
calendar.set(Calendar.DAY_OF_WEEK_IN_MONTH, week);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.YEAR, year);
return calendar.getTime();
}
I usually use GregorianCalendar
but Calendar
should work just fine.
This should (hopefully) work for the most part, I've tested it on other machines and ideone.
Upvotes: 4
Reputation: 722
I could propose next decision:
public Date nthWeekdayOfMonth(int dayOfWeek, int month, int year, int week, TimeZone timeZone) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(timeZone);
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.DAY_OF_MONTH, 1);
// add +1 to week if first weekday of mounth > dayOfWeek
int localWeek = week;
if (calendar.get(calendar.DAY_OF_WEEK) > dayOfWeek) {
localWeek++;
}
calendar.set(Calendar.WEEK_OF_MONTH, localWeek);
calendar.set(Calendar.DAY_OF_WEEK, dayOfWeek);
return calendar.getTime();
}
for:
System.out.println(nthWeekdayOfMonth(Calendar.FRIDAY, Calendar.SEPTEMBER, 2016, 3, TimeZone.getTimeZone("Europe/London")));
System.out.println(nthWeekdayOfMonth(Calendar.FRIDAY, Calendar.OCTOBER, 2016, 3, TimeZone.getTimeZone("Europe/London")));
System.out.println(nthWeekdayOfMonth(Calendar.FRIDAY, Calendar.NOVEMBER, 2016, 3, TimeZone.getTimeZone("Europe/London")));
it returns:
Fri Sep 16 19:41:23 YEKT 2016
Fri Oct 21 19:41:23 YEKT 2016
Fri Nov 18 20:41:23 YEKT 2016
Upvotes: 3
Reputation: 15685
To take a different approach. If the first day of the month is a Saturday, then the third Friday is the 21st of that month. Extend this for the seven possible days:
You just need to check what day of the week the first of the month is.
Upvotes: 0