Мне нужно получить дату, передав эти параметры
- год
- номер недели (в месяце) т.е. 1,2,3,4,5
- номер дня (в неделе) от 0 (воскресенье) до 6 (суббота)
- Месяц
Я искал конструктор в классе Calendar
, но не содержит этих параметров.
Мне нужно получить дату, передав эти параметры
Я искал конструктор в классе Calendar
, но не содержит этих параметров.
Чтобы создать дату из года, номера недели и дня недели, используйте экземпляр java.util.Calendar
:
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 2017);
cal.set(Calendar.WEEK_OF_YEAR, 26);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
Чтобы преобразовать из Calendar
в java.util.Date
:
Date date = cal.getTime();
Чтобы преобразовать Date
в java.time.LocalDateTime
, используйте:
LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
Instant
и ZonedDateTime
, а не LocalDateTime
. Нет смысла намеренно отказываться от информации о часовом поясе/смещении. Кроме того, вам следует избегать проблемных старых устаревших классов даты и времени, поскольку java.time был добавлен, чтобы полностью их заменить. В этом 2017 году другие Ответы Оле В.В. или Гюго должен был быть принят, а не этот.
- person Basil Bourque; 04.07.2017
Несмотря на ваши теги, я согласен с комментарием Joe C, вам следует предпочесть современный API даты и времени Java (также известный как java.time
или JSR-310) давно устаревшему Calendar
и друзьям. Современные классы более удобны для программиста и с ними приятнее работать, они преподносят меньше сюрпризов, приводят к более ясному и естественному коду (по крайней мере, когда вы привыкнете к свободному стилю) и их легче отлаживать, если вы допустили ошибку.
Я не знаю, как вы считаете недели в месяце. Я предположил, что первая неделя начинается первого числа месяца и длится 7 дней (поэтому вторая неделя начинается 8-го, а 5-я неделя — 29-го числа месяца). Если вы считаете иначе, см. ответ Хьюго.
Я предлагаю этот метод:
public static LocalDate weekNoAndDayToDate(Year year, Month month, int weekOfMonth, int dayOfWeek) {
// find day of week: convert from 0 (Sunday) to 6 (Saturday)
// to DayOfWeek, from 1 (Monday) to 7 (Sunday)
DayOfWeek dow;
if (dayOfWeek == 0) { // Sunday
dow = DayOfWeek.SUNDAY;
} else {
dow = DayOfWeek.of(dayOfWeek);
}
return year.atMonth(month)
.atDay(1)
.with(TemporalAdjusters.nextOrSame(dow))
.with(ChronoField.ALIGNED_WEEK_OF_MONTH, weekOfMonth);
}
С этим мы можем сделать, например
LocalDate today = weekNoAndDayToDate(Year.of(2017), Month.JULY, 1, 1);
Это дает
2017-07-03
Если вам нужен Date
или GregorianCalendar
, например, для старого API, который вы не можете изменить, выполните одно из следующих действий:
Date oldfashiondDateObject
= Date.from(today.atStartOfDay(ZoneId.systemDefault()).toInstant());
GregorianCalendar oldfashionedCalendarObject
= GregorianCalendar.from(today.atStartOfDay(ZoneId.systemDefault()));
В обоих случаях результат будет разным в разных часовых поясах (одна из присущих старым классам бед). На моем компьютере первый дает Date
из
Mon Jul 03 00:00:00 CEST 2017
Второй дает GregorianCalendar
, равный тому же моменту времени.
Как @Оле В.В. объяснил, вам нужно определить, в какой день начинается неделя, и сколько дней она должна считаться первой неделей.
Например, стандарт ISO-8601 рассматривает:
Месяц делится на периоды, каждый из которых начинается в определенный первый день недели. Самый ранний период в том же месяце называется неделей 0
, если он имеет меньше минимального количества дней, и неделей 1
, если он имеет хотя бы минимальное количество дней.
В зависимости от того, как вы их определяете, вы можете получить разные результаты. Рассмотрим календарь на июль 2017 года:
July 2017
Su Mo Tu We Th Fr Sa
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
Если мы рассмотрим определение ISO, мы имеем:
Если мы рассмотрим первый день недели как воскресенье и минимальное количество дней в первой неделе как 1, мы имеем:
Поскольку решение с Calendar
уже было опубликовано, я напишу его, используя новый API. Если вы используете Java 8, рассмотрите возможность использования нового java. API времени. Это проще, меньше ошибок и менее подвержено ошибкам, чем старые API .
Если вы используете Java ‹= 7, вы можете использовать ThreeTen Backport, отличный бэкпорт для новых классов даты/времени Java 8. А для Android есть ThreeTenABP (подробнее о том, как его использовать здесь).
Код ниже работает для обоих. Единственная разница заключается в именах пакетов (в Java 8 — java.time
, а в ThreeTen Backport (или ThreeTenABP для Android) — org.threeten.bp
), но имена классов и методов одинаковы.
Я использую DateTimeFormatter
, потому что он берет все поля (месяц, год, день недели и неделя месяца) и соответствующим образом разрешает день, создавая LocalDate
(который имеет поля дня/месяца/года). Я также использую класс WeekFields
, который можно настроить для использования разных определений недели (первый день и минимальное количество дней в первую неделю).
Также есть небольшая корректировка, чтобы считать воскресенье нулевым:
public LocalDate getDate(int weekOfMonth, int dayOfWeek, int month, int year) {
// you can customize your week definition (first day of week and mininum days in first week)
WeekFields wf = WeekFields.of(DayOfWeek.SUNDAY, 2);
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// week of month, using week definition from WeekFields
.appendValue(wf.weekOfMonth()).appendPattern(" ")
// day of week
.appendValue(ChronoField.DAY_OF_WEEK)
// month and year
.appendPattern(" M/yyyy")
// create formatter
.toFormatter();
return LocalDate.parse(weekOfMonth + " " +
// Sunday is 0, adjusting value
(dayOfWeek == 0 ? 7 : dayOfWeek) + " " + month + "/" + year, fmt);
}
Используя этот код (неделя начинается в воскресенье, и 2 дня должны считаться первой неделей - иначе неделя будет нулевой, как в первом примере выше):
LocalDate d = getDate(1, 6, 7, 2017);
d
будет 2017-07-08
(суббота на неделе 1 июля 2017 г.).
Если вы хотите использовать определение ISO 8601, используйте константу WeekFields.ISO
вместо метода WeekFields.of()
.
Как @Оле В.В. предложили в комментариях, это можно сделать и без создания форматтера: получить первое dayOfWeek
месяца и настроить его на нужное weekOfMonth
:
public LocalDate getDate(int weekOfMonth, int dayOfWeek, int month, int year) {
// you can customize your week definition (first day of week and mininum days in first week)
WeekFields wf = WeekFields.of(DayOfWeek.SUNDAY, 2);
// Sunday is 0, adjusting value
DayOfWeek dow = DayOfWeek.of(dayOfWeek == 0 ? 7 : dayOfWeek);
// get the first weekday of the month
LocalDate first = LocalDate.of(year, month, 1).with(TemporalAdjusters.nextOrSame(dow));
// check in which week this date is
int week = first.get(wf.weekOfMonth());
// adjust to weekOfMonth
return first.plusWeeks(weekOfMonth - week);
}
Это работает точно так же, но без использования средства форматирования — я тестировал даты с 1600 по 2100 год и получил те же результаты.
PS: Calendar
также имеет аналогичную конфигурацию через методы setFirstDayOfWeek()
и setMinimalDaysInFirstWeek()
. Вы можете проверить конфигурацию по умолчанию, вызвав соответствующие методы get
.
WeekFields
класс, конечно. Спасибо. Нельзя ли это сделать без построения строки и ее разбора? Я думаю, что я бы попытался получить номер недели первого четверга месяца (например, какой день недели требовался), используя WeekFields.weekOfMonth()
. Затем добавьте соответствующее количество недель, используя LocalDate.plusWeeks()
.
- person Ole V.V.; 04.07.2017
java.util.Calendar
, если вы можете избежать его. Вы должны посмотреть на пакетjava.time
и использовать класс, соответствующий вашему варианту использования. - person Joe C   schedule 04.07.2017Calendar
уже давно вытеснены классами java.time. Избегайте этих проблемных, плохо спроектированных и ошибочных устаревших классов даты и времени. - person Basil Bourque   schedule 04.07.2017