2017-01-10 2 views
-1

У меня возникли неприятные проблемы с Java Calendar. Я хочу получить первый день недели как Date, он работает хорошо, пока неделя не будет между годами. Как обойти это?Java calendar начало года

Calendar cal = Calendar.getInstance(); 
cal.set(2017,0,1); 
cal.setFirstDayOfWeek(Calendar.MONDAY); 
Calendar first = (Calendar) cal.clone(); 
first.add(Calendar.DAY_OF_WEEK, 
first.getFirstDayOfWeek() - first.get(Calendar.DAY_OF_WEEK)); 
Calendar last = (Calendar) first.clone(); 
last.add(Calendar.DAY_OF_YEAR, 6); 
System.out.println(first.getTime()); 
System.out.println(last.getTime()); 

Выход

пн 2 января 22:30:26 GMT 2017

Вс 8 января 22:30:26 GMT 2017

Выход должен быть

Пн Дек 26 22:30:26 GMT 2016

Вс 1 января 22:30:26 GMT 2017

+4

Почему вы верите 'first.getFirstDayOfWeek() - first.get (Calendar.DAY_OF_WEEK)' - это способ адаптации к началу недели? Когда firstDayOfWeek равно 2 (MONDAY), а dayOfWeek равно 1 (SUNDAY), вы получаете '2 - 1 = + 1', т. Е. Вы * добавляете * 1 день. Это то, что вы видите.Я оставлю это вам, чтобы выяснить, как настроить эту логику, чтобы исправить проблему. BTW: Просто печать этих значений сказала бы вам об этом. – Andreas

+1

Проблема не из-за изменения года. Ваше понимание чисел DayOfWeek неверно. Даже если вы установите FirstDayOfWeek в понедельник, число понедельников равно 2, а число DayOfWeek с 1 января 2017 года - воскресенье/1. Итак, 2-1 = 1 и 1 января 2017 года +1 = 2 января 2017. И 2 января 2017 года + 6 = 8 января 2017 года. Таким образом, все работает так, как ожидалось. –

+0

Хорошо спасибо за помощь, я буду использовать API Joda Time, потому что он лучше реализован для моих конкретных проблем. – Tuby

ответ

2

Не используйте календарь, это, как известно, очень плохо API для использования (see this answer). Используйте вместо этого время api (если вы не на java8, используйте ThreeTen backport).

При том, что ваш код будет выглядеть следующим образом:

LocalDate ld = LocalDate.of(2017,1,1); 
ld = ld.with(ChronoField.DAY_OF_WEEK, 1); 
System.out.println(ld); 
System.out.println(ld.plusDays(6)); 

Если вам нужно закончить с Date, используйте Date.from(ld.atStartOfDay().atZone(ZoneId.of("UTC")).toInstant()), чтобы преобразовать его (предполагая, что UTC, достаточно легко заменить зону вам нужно)

+0

Нет, это не «очень плохо» API для использования ». Это хороший API, о чем свидетельствует то, как быстро все узнали, что ОП делает неправильно. – VGR

+0

Даже если вы используете Java 6 или 7, нет необходимости в Joda-Time. Большая часть функциональных возможностей java.time была перенесена в проект [ThreeTen-Extra] (http://www.threeten.org/threetenbp/) и дополнительно адаптирована для Android в [ThreeTenABP] (https: // github .com/JakeWharton/ThreeTenABP). Проект Joda-Time теперь находится в режиме обслуживания и советует перейти на java.time. –

+0

@BasilBourque Спасибо, я этого не знал. Адаптированный ответ. –

2

TL; др

accepted Answer by Hendrickx является правильным. Вот альтернатива, которую я считаю немного более читаемой.

LocalDate.of(2017 , Month.JANUARY , 1) 
    .with(TemporalAdjusters.previous(DayOfWeek.MONDAY)) 

TemporalAdjuster

Интерфейс TemporalAdjuster обеспечивает классы, которые манипулируют объекты java.time. Реализации можно найти в классе TemporalAdjusters. Регулятор previousOrSame обнаруживает предыдущее появление дня недели или палочки с той же датой, если это уже тот день недели.

LocalDate target = LocalDate.of(2017 , Month.JANUARY , 1); 
LocalDate ld = target.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)); 

target.toString(): 2017-01-01 | ld.toString(): 2016-12-26

Если вы хотите всегда предыдущий понедельник, даже если дата уже понедельник, а затем использовать регулятор previous.

LocalDate ld = target.with(TemporalAdjusters.previous(DayOfWeek.MONDAY)); 

Чтобы получить конец недели, используйте nextOrSame регулятор.

LocalDate nextOrSameSunday = target.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY)); 

Вы можете увидеть день недели в строке.

ZoneId z = ZoneId.of("America/Montreal"); 
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).withLocale(Locale.CANADA); 
System.out.println("target: " + target.format(f) + " | ld: " + ld.format(f)); 

цель: Воскресенье, 1 Январь 2017 | ld: Понедельник, 26 декабря 2016 года

См. это code live in IdeOne.com.

Также обратите внимание на использование enums, DayOfWeek и Month. См. Tutorials.


О java.time

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

Проект Joda-Time, в настоящее время в maintenance mode, советует перейти на классы java.time.

Чтобы узнать больше, см. Oracle Tutorial. И поиск Stack Overflow для многих примеров и объяснений. Спецификация: JSR 310.

Где получить классы java.time?

  • Java SE 8 и SE 9, а затем
    • Встроенный.
    • Часть стандартного Java API с объединенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и SE 7
    • Большая часть функциональности java.time будет обратно портирован на Java 6 & 7 в ThreeTen-Backport.
  • Android

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

+0

Спасибо за очень подробный ответ, я пробовал использовать Java 8 раз в моем проекте Android, но для этого требуется новейший API. Я действительно решил свою проблему с Joda Time, и это было действительно незначительно, всего одна строка кода. Вы упомянули ThreeTenBackport, я думаю, что в моем конкретном случае не стоит переходить к этой бэкспорт-библиотеке, пока она такая незначительная. – Tuby

+1

Если ваши потребности действительно являются только одной строкой кода, достаточно. Обычно люди, выполняющие работу с датами, делают много. Если это так, более внимательно прочтите последний раздел моего ответа. Back-port для Java 6 & 7 - это один проект (ThreeTen-Backport), и этот проект был адаптирован для Android специально в другом проекте (ThreeTenABP). Старые классы устаревания действительно настолько плохи, что добавление библиотеки, чтобы вытеснить их, стоит того. –

Смежные вопросы