Java:如何获得一个月中 x 天的日期(例如 2012 年 2 月的第三个星期一)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7946129/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 22:08:06  来源:igfitidea点击:

Java: How do I get the date of x day in a month ( e.g. Third Monday in February 2012)

javadatecalendar

提问by jjj

I am somewhat struggling with this.

我对此有些挣扎。

I want to setup my Calendar to let's say: Third Monday in February 2012.And I didn't find any way of doing this using Java.

我想设置我的日历,让我们说:2012 年 2 月的第三个星期一。我没有找到任何使用 Java 执行此操作的方法。

For example, if I wanted to set my calendar for Christmas 2011, I can do this easily, this way:

例如,如果我想为 2011 年圣诞节设置日历,我可以通过以下方式轻松完成:

Calendar when = Calendar.getInstance();
when.set (Calendar.MONTH, Calendar.DECEMBER);
when.set (Calendar.DAY_OF_MONTH, 25)
when.set (Calendar.YEAR, 2011);

But I am lost as to how to set it up for let's say Memorial Day 2012, which is the last Monday of May. This is my code, but it's obviously wrong, because I simply can't assume that the last Monday of May will be in the 4th week of May that year:

但我不知道如何为 2012 年阵亡将士纪念日设置它,这是五月的最后一个星期一。这是我的代码,但它显然是错误的,因为我根本无法假设 5 月的最后一个星期一是当年 5 月的第 4 周:

Calendar when = Calendar.getInstance ();
when.set (Calendar.DAY_OF_WEEK,Calendar.MONDAY);
when.set (Calendar.MONTH, Calendar.MAY);
when.set (Calendar.WEEK_OF_MONTH, 4)
when.set (Calendar.YEAR, 2012);

Any suggestions as to how I can programatically find out, in which week of the month of May 2012 (in example above) is the last Monday? Assuming I can get that information, I should be able to get my code above to work.

关于如何以编程方式找出 2012 年 5 月的哪一周(在上面的示例中)是最后一个星期一的任何建议?假设我能得到这些信息,我应该能让上面的代码工作。

I need something which would basically work for any other examples. Something which could give an exact day for the same scenarios. Examples:

我需要一些基本上适用于任何其他示例的东西。可以为相同场景提供确切日期的东西。例子:

Which date is:

哪个日期是:

  • 3rd Thursday of May 2015
  • 1st Monday of June 2050
  • 4th Tuesday of December 2012
  • 2nd Wednesday of July 2000
  • 2015 年 5 月的第三个星期四
  • 2050 年 6 月的第一个星期一
  • 2012 年 12 月的第四个星期二
  • 2000 年 7 月的第二个星期三

I really need this for my project and I am sure it's simple, but I am breaking my head on this without any real results to show for :) And also couldn't find anything on the net.

我的项目真的需要这个,我相信这很简单,但是我在没有任何实际结果可以显示的情况下打破了我的头脑:) 而且在网上也找不到任何东西。



Added:

添加:

Ok, this is where I've got for the last Monday in a month:

好的,这是我一个月内最后一个星期一的情况:

when.set (GregorianCalendar.MONTH, GregorianCalendar.MAY);
when.set (GregorianCalendar.DAY_OF_WEEK, Calendar.MONDAY);
when.set (GregorianCalendar.DAY_OF_WEEK_IN_MONTH, -1);
when.set (Calendar.YEAR, 2012);

But I am not sure how would I go about doing for example seconds Monday in the same month, like this?

但我不确定我将如何在同月的星期一进行例如几秒钟的工作,像这样?

when.set (GregorianCalendar.DAY_OF_WEEK_IN_MONTH, 2);

Any suggestions?

有什么建议?

采纳答案by leonbloy

To do date arithmetic in Java (and in general, to do anything with datetimes, except for the most trivial things) Joda-Timeis the answer:

在 Java 中进行日期算术(一般来说,对日期时间做任何事情,除了最琐碎的事情)Joda-Time是答案:

public static LocalDate getNDayOfMonth(int dayweek,int nthweek,int month,int year)  {
   LocalDate d = new LocalDate(year, month, 1).withDayOfWeek(dayweek);
   if(d.getMonthOfYear() != month) d = d.plusWeeks(1);
   return d.plusWeeks(nthweek-1);
}

public static LocalDate getLastWeekdayOfMonth(int dayweek,int month,int year) {
   LocalDate d = new LocalDate(year, month, 1).plusMonths(1).withDayOfWeek(dayweek);
   if(d.getMonthOfYear() != month) d = d.minusWeeks(1);
  return d;
}

public static void main(String[] args) {
   // second wednesday of oct-2011
   LocalDate d = getNDayOfMonth( DateTimeConstants.WEDNESDAY, 2, 10, 2011);
   System.out.println(d);
   // last wednesday of oct-2011
   LocalDate dlast = getLastWeekdayOfMonth( DateTimeConstants.WEDNESDAY,  10, 2011);
   System.out.println(dlast);
}


Edit: Since Java 8 (2014) the new Date API (package java.time), which is inspired by/similar to Jodatime, should be preferred.

编辑:自 Java 8 (2014) 以来java.time,受 Jodatime 启发/类似于 Jodatime的新 Date API (package )应该是首选

回答by Ross Mills

The following code was successfully tested for all holidays in 2013 and 2014. I realize that this doesn't really answer the original question, but I think it might be useful for people who come across this post in hopes of figuring out how to work with holidays using Calendar.

以下代码已在 2013 年和 2014 年的所有假期中成功测试。我意识到这并没有真正回答最初的问题,但我认为它可能对看到这篇文章的人有用,希望弄清楚如何使用使用日历的假期。

public static boolean isMajorHoliday(java.util.Date date) {
    Calendar cal = Calendar.getInstance();
    cal.setTime(date);

    // check if New Year's Day
    if (cal.get(Calendar.MONTH) == Calendar.JANUARY
        && cal.get(Calendar.DAY_OF_MONTH) == 1) {
        return true;
    }

    // check if Christmas
    if (cal.get(Calendar.MONTH) == Calendar.DECEMBER
        && cal.get(Calendar.DAY_OF_MONTH) == 25) {
        return true;
    }

    // check if 4th of July
    if (cal.get(Calendar.MONTH) == Calendar.JULY
        && cal.get(Calendar.DAY_OF_MONTH) == 4) {
        return true;
    }

    // check Thanksgiving (4th Thursday of November)
    if (cal.get(Calendar.MONTH) == Calendar.NOVEMBER
        && cal.get(Calendar.DAY_OF_WEEK_IN_MONTH) == 4
        && cal.get(Calendar.DAY_OF_WEEK) == Calendar.THURSDAY) {
        return true;
    }

    // check Memorial Day (last Monday of May)
    if (cal.get(Calendar.MONTH) == Calendar.MAY
        && cal.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY
        && cal.get(Calendar.DAY_OF_MONTH) > (31 - 7) ) {
        return true;
    }

    // check Labor Day (1st Monday of September)
    if (cal.get(Calendar.MONTH) == Calendar.SEPTEMBER
        && cal.get(Calendar.DAY_OF_WEEK_IN_MONTH) == 1
        && cal.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) {
        return true;
    }

    // check President's Day (3rd Monday of February)
    if (cal.get(Calendar.MONTH) == Calendar.FEBRUARY
        && cal.get(Calendar.DAY_OF_WEEK_IN_MONTH) == 3
        && cal.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) {
        return true;
    }

    // check Veterans Day (November 11)
    if (cal.get(Calendar.MONTH) == Calendar.NOVEMBER
        && cal.get(Calendar.DAY_OF_MONTH) == 11) {
        return true;
    }

    // check MLK Day (3rd Monday of January)
    if (cal.get(Calendar.MONTH) == Calendar.JANUARY
        && cal.get(Calendar.DAY_OF_WEEK_IN_MONTH) == 3
        && cal.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) {
        return true;
    }

    return false;

}

回答by AlexR

I do not know the "easy" way but I can suggest you the following.

我不知道“简单”的方法,但我可以建议你以下。

  1. Set calendar to the first day of the month.
  2. Retrieve its day of the week
  3. Calculate the date of the first Monday of the month.
  4. Add 14 days using calendar.add() method. You will get the third Monday.
  1. 将日历设置为每月的第一天。
  2. 检索它的星期几
  3. 计算该月的第一个星期一的日期。
  4. 使用 calendar.add() 方法添加 14 天。你会得到第三个星期一。

回答by Basil Bourque

tl;dr

tl;博士

LocalDate thirdMondayInFebruary2012 = 
    YearMonth.of( 2012 , Month.FEBRUARY )
             .atDay( 1 )
             .with( TemporalAdjusters.dayOfWeekInMonth( 3 , DayOfWeek.MONDAY ) );

…and…

…和…

LocalDate lastMondayInMay2012 = 
    YearMonth.of( 2012 , Month.MAY )
             .atDay( 1 );
             .with( TemporalAdjusters.lastInMonth( DayOfWeek.MONDAY ) );

java.time

时间

Very easy to do using the java.time classes that now supplant both Joda-Time and the troublesome old date-time classes bundled with the earliest versions of Java.

使用 java.time 类很容易做到,这些类现在取代了 Joda-Time 和与最早版本的 Java 捆绑在一起的麻烦的旧日期时间类。

First we need to specify the desired month. The YearMonthclass can do that. From there we get a LocalDate, a date without a time-of-day and without a time zone.

首先,我们需要指定所需的月份。本YearMonth类可以做到这一点。从那里我们得到一个LocalDate没有时间和时区的日期。

YearMonth ym = YearMonth.of( 2012 , Month.FEBRUARY ); // Or pass '2' for 'February'.
LocalDate ld = ym.atDay( 1 );

The TemporalAdjusterinterface provides for adjusting a date-time value into another date-time value. Implementations provided by the TemporalAdjustersclass (notice the plural 's'). Specify a day of week using the handy DayOfWeekenum.

TemporalAdjuster接口用于将日期时间值调整为另一个日期时间值。TemporalAdjusters类提供的实现(注意复数“s”)。使用方便的DayOfWeek枚举指定星期几。

int ordinal = 3 ; // Use '3' for 'third occurrence in month' such as '3rd Monday'.
LocalDate thirdMondayInFebruary2012 = ld.with( TemporalAdjusters.dayOfWeekInMonth( ordinal , DayOfWeek.MONDAY ) );

Tip:Rather than pass mere integers for year and month across your code base, pass objects such as YearMonth, Year, Month, and DayOfWeek. Doing so eliminates ambiguity, makes your code more self-documenting, provides types-safety, and ensures valid values.

提示:而不是在你的代码库,通过对年份和月份仅仅整数,传递对象,例如YearMonthYearMonth,和DayOfWeek。这样做可以消除歧义,使您的代码更具自文档性,提供类型安全,并确保有效值。



About java.time

关于java.time

The java.timeframework is built into Java 8 and later. These classes supplant the troublesome old legacydate-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

The Joda-Timeproject, now in maintenance mode, advises migration to the java.timeclasses.

现在处于维护模式Joda-Time项目建议迁移到java.time类。

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310

You may exchange java.timeobjects directly with your database. Use a JDBC drivercompliant with JDBC 4.2or later. No need for strings, no need for java.sql.*classes.

您可以直接与数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC 驱动程序。不需要字符串,不需要类。java.sql.*

Where to obtain the java.time classes?

从哪里获得 java.time 类?

The ThreeTen-Extraproject extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,和更多

回答by Maurício Linhares

All you need is a loop:

你只需要一个循环:

public class CalculateDate {

public static void main( String ... args ) {

    Calendar c = Calendar.getInstance();
    c.set( Calendar.YEAR, 2012 );
    c.set( Calendar.MONTH , Calendar.MAY);
    c.set( Calendar.DAY_OF_MONTH, 0 );
    c.add( Calendar.DAY_OF_MONTH, -1 );

    System.out.println( c.getTime() );

    int mondaysCount = 0;

    while ( mondaysCount != 4 ) {
        c.add( Calendar.DAY_OF_MONTH, 1 );
        if ( c.get( Calendar.DAY_OF_WEEK ) == Calendar.MONDAY ) {
            mondaysCount++; 
        }       
    }

    System.out.printf( "The fourth monday of may is %s", c.getTime() );     

}

}

回答by Tomasz Nurkiewicz

Any chances you are using Quartz scheduler?

您有机会使用Quartz 调度程序吗?

public Date date(String cronExpression) {
    return new org.quartz.CronExpression(cronExpression).
        getNextValidTimeAfter(new Date(0));
}

System.out.println(date("0 0 0 ? May Thu#3 2015"));
System.out.println(date("0 0 0 ? Jun Mon#1 2050"));
System.out.println(date("0 0 0 ? Dec Tue#4 2012"));
System.out.println(date("0 0 0 ? Jul Wed#2 2000"));

This simple code prints correct (?) results:

这个简单的代码打印出正确的 (?) 结果:

Thu May 21 00:00:00 CEST 2015
Mon Jun 06 00:00:00 CEST 2050
Tue Dec 25 00:00:00 CET 2012
Wed Jul 12 00:00:00 CEST 2000

The required CronExpressiondoesn't have any dependencies on the rest of Quartz, so you might consider copying it to your project (watch out for license!)

所需的CronExpression对 Quartz 的其余部分没有任何依赖,因此您可以考虑将其复制到您的项目中(注意许可证!)

Side note: the internal implementation of getNextValidTimeAfter()is 400 lines of code...

旁注:内部实现getNextValidTimeAfter()是400行代码......

回答by Kishore

public String nDow(int year, int month, int nweek, int nday)
{
    Calendar cdt = Calendar.getInstance();
    cdt.set(year, month -1, 1);
    return year + "-" + month + "-" + (getPosOfWeekday(cdt.get(Calendar.DAY_OF_WEEK), nday) + ((nweek - 1) *7));
}

private int getPosOfWeekday(int startday, int nday)
{
    nday = weekDayValue(nday);
    return constructCircularArray(startday).indexOf(nday) + 1;
}

private ArrayList<Integer> constructCircularArray(int weekday)
{
    ArrayList<Integer> circularArray = new ArrayList<Integer>();
    for(int i = 0; i < 7; i++)
    {
        circularArray.add(i, weekDayValue(weekday++));
    }
    return circularArray;
}

private int weekDayValue(int x)
{
    return ((x-1) % 7) + 1;
}

回答by Usha Ravi

Here is an alternative. What it does is: Get which week you want (n), and the other parameters, and return the date of the day in that week. Since Calendar gives the date of the previous month (for example 29th of February instead of 7th of March, since the 1st week of March collides with last week of Feb), the function computes the 2nd week if the date goes beyond 7 or multiples of it for each week thereof. Hope that helps.

这是一个替代方案。它的作用是:获取您想要的周(n)和其他参数,并返回该周的日期。由于 Calendar 给出了上个月的日期(例如,2 月 29 日而不是 3 月 7 日,因为 3 月的第 1 周与 2 月的最后一周相冲突),如果日期超过 7 或 7 的倍数,该函数将计算第 2 周它的每个星期。希望有帮助。

public static int getNthWeekDay (int n, int day, int month, int year) {
    Calendar calendar = Calendar.getInstance();

    calendar.set(Calendar.DAY_OF_WEEK, day);
    calendar.set(Calendar.MONTH, month);
    calendar.set(Calendar.WEEK_OF_MONTH,n);
    calendar.set(Calendar.YEAR, year);
    if (calendar.get(Calendar.DATE) > n * 7) {
        calendar.set(Calendar.DAY_OF_WEEK,day);
        calendar.set(Calendar.MONTH, month);
        calendar.set(Calendar.WEEK_OF_MONTH,day+1);

    }
    return calendar.get(Calendar.DATE);
}