Подтвердить что ты не робот

Java: как получить дату x дня в месяц (например, третий понедельник февраля 2012 года)

Я немного борюсь с этим.

Я хочу настроить свой календарь, чтобы сказать: Третий понедельник февраля 2012 года. И я не нашел способа сделать это с помощью Java.

Например, если бы я хотел установить календарь на Рождество 2011 года, я могу сделать это легко:

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

Но я теряюсь относительно того, как настроить его для того, чтобы сказать "День памяти 2012", который является последним понедельником мая. Это мой код, но это явно неправильно, потому что я просто не могу предположить, что последний понедельник мая будет на 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);

Любые предложения относительно того, как я могу программно узнать, в какую неделю мая 2012 года (в примере выше) последний понедельник? Предполагая, что я могу получить эту информацию, я должен получить код выше, чтобы работать.

Мне нужно что-то, что в основном будет работать для любых других примеров. То, что может дать точный день для тех же сценариев. Примеры:

Какая дата:

  • 3-й четверг мая 2015 года
  • 1-й понедельник июня 2050 года.
  • Четвертый вторник декабря 2012 года.
  • 2-я среда июля 2000 года

Мне действительно нужно это для моего проекта, и я уверен, что это просто, но я ломаю голову на этом без каких-либо реальных результатов, чтобы показать:) И также не мог найти ничего в сети.


Добавлено:

Хорошо, это я получил в последний понедельник месяца:

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

Но я не уверен, как мне заняться, например, секундами в понедельник в том же месяце, вроде этого?

when.set (GregorianCalendar.DAY_OF_WEEK_IN_MONTH, 2);

Любые предложения?

4b9b3361

Ответ 1

Сделать арифметику дат в 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);
}

Изменить: поскольку Java 8 (2014) должен быть предпочтительным новый API даты (пакет java.time), который вдохновлен/похож на Jodatime, .

Ответ 2

Следующий код был успешно протестирован на все праздники в 2013 и 2014 годах. Я понимаю, что на самом деле это не отвечает на исходный вопрос, но я думаю, что это может быть полезно для людей, которые попадают на этот пост, в надежде выяснить, как для работы с праздниками с использованием Calendar.

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

    // check if New Year 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 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;

}

Ответ 3

Я не знаю "легкий" способ, но могу предложить вам следующее.

  • Установите календарь в первый день месяца.
  • Получить свой день недели
  • Рассчитать дату первого понедельника месяца.
  • Добавить 14 дней с использованием метода calendar.add(). Вы получите третий понедельник.

Ответ 4

Все, что вам нужно, это цикл:

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

}

}

Ответ 5

Любые шансы, что вы используете Quartz scheduler?

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

Этот простой код печатает правильные (?) результаты:

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

Требуемый CronExpression не имеет никаких зависимостей от остальной части кварца, поэтому вы можете подумать о его копировании в свой проект (смотреть для лицензии!)

Боковое примечание: внутренняя реализация getNextValidTimeAfter() - это 400 строк кода...

Ответ 6

TL;DR

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

... и...

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

java.time

Очень легко сделать, используя классы java.time, которые теперь вытесняют Joda-Time и неприятные старые классы времени, связанные с самыми ранними версиями Java.

Сначала нам нужно указать желаемый месяц. Класс YearMonth может сделать это. Оттуда мы получаем a LocalDate, дату без времени суток и без часового пояса.

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

Интерфейс TemporalAdjuster обеспечивает корректировку значения даты и времени в другое значение даты. Реализации, предоставляемые классом TemporalAdjusters (обратите внимание на множественное число). Укажите день недели, используя удобный DayOfWeek enum.

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

Совет. Вместо того, чтобы передавать целые числа за год и месяц на основе кода, передайте объекты, такие как YearMonth, Year, Month, и DayOfWeek. Это устраняет двусмысленность, делает ваш код более самодокументированным, обеспечивает типы-безопасность и обеспечивает достоверные значения.

О java.time

Структура java.time встроена в Java 8 и более поздние версии. Эти классы вытесняют неприятные старые классы времени, такие как java.util.Date, .Calendar и java.text.SimpleDateFormat.

Проект Joda-Time, теперь режим обслуживания, советует перейти на java.time.

Чтобы узнать больше, см. Учебник Oracle. И поиск Qaru для многих примеров и объяснений.

Большая часть функций java.time возвращается на Java 6 и 7 в ThreeTen-Backport и далее адаптируется к Android в ThreeTenABP (см. Как использовать...).

Проект ThreeTen-Extra расширяет java.time с помощью дополнительных классов. Этот проект является доказательством возможных будущих дополнений к java.time. Здесь вы можете найти полезные классы, такие как Interval, YearWeek, YearQuarter и больше.

Ответ 7

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

Ответ 8

Вот альтернатива. Что он делает: Получите, какую неделю вы хотите (n), и другие параметры, и верните дату дня на этой неделе. Поскольку календарь дает дату предыдущего месяца (например, 29 февраля, а не 7 марта, так как первая неделя марта сталкивается с прошлой неделей февраля), функция вычисляет вторую неделю, если дата выходит за пределы 7 или кратных это за каждую неделю. Надеюсь, что это поможет.

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