【问题标题】:Get third friday of a month获得一个月的第三个星期五
【发布时间】:2023-03-21 01:37:02
【问题描述】:

我正在为我的应用程序开发一个本地日历。但这是每月重复事件(星期几)的问题。

当我创建一个从16-9-2016(16 SEP 2016 FRIDAY) 开始并重复每个月的第三个星期五的事件时。但下个月它会在第二个创建 2016 年 14 月 10 日星期五(这是问题)。下个月是第三个星期五。

我的代码是

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();
    }

我知道这个问题。但我不知道如何解决它.. 有什么办法可以解决它?

【问题讨论】:

  • 提示:如果可能,请使用 Java8 日期/时间 API 而不是好的日历。日历真的很重要。
  • @GhostCat 抱歉我们的系统使用 Java7。有没有办法通过使用 Java7 日历来修复它
  • 如果您使用的是 Java7,您可以尝试Joda Time,然后this answer 包含示例代码。
  • 您在哪里遇到问题?我刚刚使用以下参数进行了尝试,它对我有用:nthWeekdayOfMonth(6, 9, 2016, 3, TimeZone.getTimeZone("Europe/London"));,返回:Fri Oct 21 10:59:09 BST 2016 除非,我做错了一个参数......

标签: java calendar


【解决方案1】:

您的代码似乎运行良好,从我所见没有任何问题,可能是您的参数错误。

请务必注意,MONTHDAY 从 0 开始,因此,0 = January0 = Sunday 因此获得第三个星期五的参数应如下所示:

nthWeekdayOfMonth(6, 9, 2016, 3, TimeZone.getTimeZone("Europe/London"));

返回以下输出:

Fri Oct 21 11:06:33 BST 2016

分解:

  1. 星期是 6,因为星期日 = 0。
  2. 月份是 9 - 即 10 月
  3. 正常年份 - 2016
  4. 周不是从 0 开始的,因此第 3 周将是索引 3
  5. 时区正常

请参阅Calendar documentation 以供参考。


编辑

所以出于某种原因,它可以在我的机器上运行,但它不能在其他机器上运行;我不知道这可能是什么问题,但使用 DAY_OF_WEEK_IN_MONTH 似乎是一个更好的选择:

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();
}

我通常使用GregorianCalendar,但Calendar 应该可以正常工作。

应该(希望)在大多数情况下都可以工作,我已经在其他机器和ideone 上对其进行了测试。

【讨论】:

  • 我得到了 2016 年 10 月 14 日星期五 20:16:10 IST
  • 我正在使用 java7 日历。和时区 印度时区 (GMT +5:30)
  • @AjmalMuhammad 你是如何设置你的时区的?您使用的是哪个时区?
  • @AjmalMuhammad 我刚刚设置了TimeZone.getTimeZone("IST");TimeZone.getTimeZone("Asia/Kolkata");,它仍然可以正常工作,你能否发布更多代码,以便我可以看到你到底哪里出错了......跨度>
  • 根据文档,该月的第一周“由getFirstDayOfWeek()getMinimalDaysInFirstWeek() 定义”。所以你需要知道这些是什么来控制你的代码做什么。
【解决方案2】:

我可以提出下一个决定:

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();
}

为:

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")));

它返回:

Fri Sep 16 19:41:23 YEKT 2016
Fri Oct 21 19:41:23 YEKT 2016
Fri Nov 18 20:41:23 YEKT 2016

【讨论】:

  • 它对我来说很好用.. 谢谢.. 我做了一点修改。
【解决方案3】:

Java 8

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

【讨论】:

    【解决方案4】:

    java.time

    java.time,现代 Java 日期和时间 API,有一个内置的调整器:

    public LocalDate nthWeekdayOfMonth(DayOfWeek dayOfWeek, Month month, int year, int week) {
        return LocalDate.of(year, month, 15)
                .with(TemporalAdjusters.dayOfWeekInMonth(week, dayOfWeek));
    }
    

    试试看:

        System.out.println(nthWeekdayOfMonth(DayOfWeek.FRIDAY, Month.OCTOBER, 2016, 3));
    

    输出:

    2016-10-21

    还请注意,我传递给方法的参数更有说服力。

    链接: Oracle tutorial: Date Time 解释如何使用 java.time。

    【讨论】:

      【解决方案5】:

      这是一个有效的 Java 8 实现。 KayV 的示例在 2017 年 9 月不起作用,但它帮助我朝着正确的方向前进。

      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());
          }
      }
      

      也许我们还应该提到,这段代码是计算一个期权到期日,以便搜索引擎能够提取到它。

      【讨论】:

      • 是的,你是对的,我也到达了这个线程搜索期权到期日。
      【解决方案6】:

      Java 8 的做法如下:

      LocalDate thirdFriday = LocalDate
                                  .now()
                                  .with(lastDayOfMonth())
                                  .with(previous(DayOfWeek.FRIDAY)).minusDays(7);
      

      【讨论】:

      • import static java.time.temporal.TemporalAdjusters.lastDayOfMonth; import static java.time.temporal.TemporalAdjusters.previous;
      【解决方案7】:

      采取不同的方法。如果该月的第一天是星期六,则第三个星期五是该月的 21 日。将其延长 7 天:

      • 星期六 1 日 -> 星期五 21 日。
      • 周日 1 日 -> 周五 20 日
      • 周一 1 日 -> 周五 19 日
      • 星期二 1 日 -> 星期五 18 日
      • 周三 1 日 -> 周五 17 日
      • 星期四 1 号 -> 星期五 16 号
      • 星期五 1 日 -> 星期五 15 日

      您只需要检查每月的第一天是星期几。

      【讨论】:

        【解决方案8】:

        以下函数可用于使用 joda 时间计算每月的第三个星期五。为了逻辑清晰,函数很冗长。

           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();
            }
        

        【讨论】:

          【解决方案9】:

          使用 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);
          

          【讨论】:

            猜你喜欢
            • 2021-12-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-02-12
            • 1970-01-01
            相关资源
            最近更新 更多