Ajmal Muhammad
Ajmal Muhammad

Reputation: 695

Get third friday of a month

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

Answers (9)

Anonymous
Anonymous

Reputation: 86296

java.time

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

alex314159
alex314159

Reputation: 3247

Java 8

LocalDate thirdFriday = java.time.LocalDate.now()
                        .with(TemporalAdjusters.firstDayOfMonth())
                        .with(TemporalAdjusters.nextOrSame(DayOfWeek.FRIDAY))
                        .plusDays(14)

Upvotes: 4

Joseph Janos
Joseph Janos

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

shagun akarsh
shagun akarsh

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

sdittmar
sdittmar

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

KayV
KayV

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

px06
px06

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:

  1. Day of week is 6, because Sunday = 0.
  2. Month is 9 - i.e. October
  3. Year is normal - 2016
  4. Week is NOT 0-based so 3rd week will be index 3
  5. TimeZone as normal

Please see the Calendar documentation for reference.


EDIT

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

mv200580
mv200580

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

rossum
rossum

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:

  • Saturday 1st -> Friday 21st.
  • Sunday 1st -> Friday 20th
  • Monday 1st -> Friday 19th
  • Tuesday 1st -> Friday 18th
  • Wednesday 1st -> Friday 17th
  • Thursday 1st -> Friday 16th
  • Friday 1st -> Friday 15th

You just need to check what day of the week the first of the month is.

Upvotes: 0

Related Questions