Расчет даты по порядковому номеру дня недели в месяце


Я пишу некоторые современные методы полезности для проекта. Один из методов ответить на следующие вопросы (например):

'When is the (3rd) (Monday) of (February) in the year (2018)'
'When is the (1st) (Wednesday) of (October) in the year (2020)'

Метод принимает 4 инт параметров значения в качестве аргументов, и возвращает дату.

Вот метод, как написано:

/**
 * Example usage:
 * find the 3rd Monday of February, in the year 2018 getDayOfMonth(3, Calendar.MONDAY, Calendar.FEBRUARY, 2018)
 * find the 1st Tuesday of October, in the year 2017 getDayOfMOnth(1, Calendar.TUESDAY, Calendar.OCTOBER, 2017)
 * @param n occurrence count
 * @param dayOfWeek day of week to find
 * @param month month to use
 * @param year year to use
 * @return Date that the nth dayOfWeek occurs
 */
public static Date getDate(int n, int dayOfWeek, int month, int year){
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.YEAR, year);
    calendar.set(Calendar.MONTH, month);
    calendar.set(Calendar.DAY_OF_MONTH, 1);

    int matchCount = 0;

    while(true){
        if(calendar.get(Calendar.DAY_OF_WEEK) == dayOfWeek) {
            matchCount++;
        }
        if(matchCount == n){
            break;
        }
        calendar.add(Calendar.DATE, 1);
        if(calendar.get(Calendar.MONTH) != month){
            break;
        }
    }

    if(matchCount != n){
        throw new RuntimeException("error");
    }

    return calendar.getTime();
}

Я изо всех сил пытаюсь придумать хорошее название для метода и 1-го параметра.



732
3
задан 25 февраля 2018 в 02:02 Источник Поделиться
Комментарии
3 ответа

Для параметра, я могу предложить nthOccurrence? Кроме того, что общается, что именно это означает, должно быть хорошо, учитывая, что он на довольно содержащихся месте - даже nthTimeDayOfWeekOccursInMonth не было бы страшно, особенно с dayOfWeek и month также являются параметрами.

Этот метод сложнее, в основном потому, что вы вычисляете не пользуются большой популярностью. "Возвращение наступлении энного дня недели в заданном месяце заданного года" не поддается краткости. Я бы взял один из двух маршрутов:

Выполняет задание / класс / профессор есть термин для этой функции? "Будний день оракул" или что-то столь же непонятных прекрасно работает, если это так, что все остальные, кто увидит этот код знает сослаться на эту вещь.

Если нет, я бы назвал его тем, чем он является; что-то вроде getDateOfNthTimeDayOfWeekOccursInMonth - это пары хорошо с указанием, что первый параметр nthOccurrence. В данном случае, я думаю, что информацию (что именно я могу ожидать этого делать) козыри краткость, потому что она делает это не очень распространенный и интуитивный.

2
ответ дан 25 февраля 2018 в 05:02 Источник Поделиться

В дополнение к @MyStackRunnethOver ноты, вот что я думаю, что можно улучшить:

Проверка параметров

Во-первых, функция не проверяет обоснованность его ввода. Это может вызвать ошибки в приложении. Практический случай-это когда пользователь вводит 1 для обозначения января и заканчивается по плаванию в феврале, потому что первый месяц года-январь, то есть 0.

while() цикл оптимизации

В случае, если мы устанавливаем N, чтобы быть 29, например, while() цикл будет повторен столько. Вы можете легко оптимизировать, что к началу проверки n в набор (1, 2, 3, 4, 5) потому что 5-это максимальное число раз в день может вновь появиться в том же месяце.

Думаю, что настойчивости

В случае, если один день вы хотите использовать эту программу, чтобы сохранить дату в базу данных, то может быть вы должны иметь дело с Григорианским календарем (Calendar calendar = GregorianCalendar.getInstance();), а не как это обычно используется SGBDR.

1
ответ дан 25 февраля 2018 в 07:02 Источник Поделиться

Меньше итераций


public static Date getDate(int n, int dayOfWeek, int month, int year){
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.DAY_OF_MONTH, 1);

int matchCount = 0;

while(true){
if(calendar.get(Calendar.DAY_OF_WEEK) == dayOfWeek) {
matchCount++;
}
if(matchCount == n){
break;
}
calendar.add(Calendar.DATE, 1);
if(calendar.get(Calendar.MONTH) != month){
break;
}
}

if(matchCount != n){
throw new RuntimeException("error");
}

return calendar.getTime();
}


Рассмотрим

public static Date calculateDateFor(int ordinal, int dayOfWeek, int month, int year) {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.DAY_OF_MONTH, 1);

while (calendar.get(Calendar.DAY_OF_WEEK) != dayOfWeek) {
calendar.add(Calendar.DATE, 1);
}

for (int weekCount = 1; weekCount < ordinal; weekCount++) {
calendar.add(Calendar.DATE, 7);
}

if (calendar.get(Calendar.MONTH) != month || ordinal <= 0) {
throw new RuntimeException("error");
}

return calendar.getTime();
}

Для меня метод с именем get возвращает поля из объекта или класса. Это не. Вместо этого, он вычисляет дату для конкретного ввода. Я хотел бы найти calculateDateFor достаточно, но вы можете написать что-то вроде calculateDateForOrdinalDayOfWeekInMonthYear если вы предпочитаете.

Энной-то это порядковый номер или порядковые для краткости. Можно, конечно, предпочитают ordinalNumber.

В исходном, вы переходите по одной каждый раз. Однако, оказавшись на правильные дни недели, вы можете пройти по семи.

Имя matchCount не указывают на то, что сопоставляется. Поэтому я изменил его на weekCount вместо.

Вы проверяете, после того, что порядковый номер не был слишком большим. Но вы не убедитесь, что он не слишком мал. Я добавил, что проверить до ворот исключение. Исходное поведение было печатать первый день месяца, когда порядковое значение меньше или равное нулю. Эта версия изменения, которые должны быть, а не исключение.

С математикой

Можно использовать циклы, но это не обязательно. Можно получить тот же эффект, только с математикой.

public static final int DAY_COUNT_PER_WEEK = 7;

public static Date calculateDateFor(int ordinal, int dayOfWeek, int month, int year) {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.DAY_OF_MONTH, 1);

int dayCountTo = dayOfWeek - calendar.get(Calendar.DAY_OF_WEEK);

// if the day of the week sought is before the day of the week
// of the first day of the month, we need to add a week
if (dayCountTo < 0) {
dayCountTo += DAY_COUNT_PER_WEEK;
}

dayCountTo += DAY_COUNT_PER_WEEK * (ordinal - 1);

calendar.add(Calendar.DATE, dayCountTo);

if (calendar.get(Calendar.MONTH) != month) {
throw new RuntimeException("error");
}

return calendar.getTime();
}

Обратите внимание, что теперь, если порядковый номер является слишком маленьким или слишком большим, это даст неверный месяц и вызвать исключение. Поэтому мы можем удалить явные проверки на ordinal.

Кроме того, рассмотреть

public static Date calculateDateFor(int ordinal, int dayOfWeek, int month, int year) {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.DAY_OF_MONTH, 1);

int dayCountTo = dayOfWeek - calendar.get(Calendar.DAY_OF_WEEK);
calendar.add(Calendar.DATE, dayCountTo);

// if the day of the week sought is before the day of the week
// of the first day of the month, we need to add a week
// but ordinal is not zero-indexed, so we have to subtract a week
// net result is to sometimes use ordinal and otherwise ordinal - 1
int weekCountTo = (dayCountTo < 0) ? ordinal : (ordinal - 1);

calendar.add(Calendar.WEEK_OF_MONTH, weekCountTo);

if (calendar.get(Calendar.MONTH) != month) {
throw new RuntimeException("error3");
}

return calendar.getTime();
}

Это позволяет вручную устанавливать количество дней в неделю и опирается на Calendar для выполнения математика.

0
ответ дан 26 февраля 2018 в 05:02 Источник Поделиться