Усечение Apache DateUtils для WEEK

Я использую Apache commons-lang3 DateUtils.truncate(Calendar calendar, int field) способ "обрезать" ненужные поля объекта Calendar. Теперь, когда field параметр получает значение Calendar.WEEK_OF_MONTHКидает

java.lang.IllegalArgumentException: The field 4 is not supported

truncate() Документация метода гласит:

/**
 * <p>Truncates a date, leaving the field specified as the most
 * significant field.</p>
 *
 * <p>For example, if you had the date-time of 28 Mar 2002
 * 13:45:01.231, if you passed with HOUR, it would return 28 Mar
 * 2002 13:00:00.000.  If this was passed with MONTH, it would
 * return 1 Mar 2002 0:00:00.000.</p>
 * 
 * @param date  the date to work with, not null
 * @param field  the field from {@code Calendar} or <code>SEMI_MONTH</code>
 * @return the different truncated date, not null
 * @throws IllegalArgumentException if the date is <code>null</code>
 * @throws ArithmeticException if the year is over 280 million
 */

Поэтому я предполагаю, что это должно работать, но это явно не так. Есть ли способ урезать даты до первого дня недели, используя DateUtils?


ОБНОВЛЕНИЕ:

Я посмотрел в исходном коде и обнаружил, что modify() метод (tuncate() использует это внутренне), перебирает кучу предопределенных полей, чтобы найти данный параметр. Теперь эти поля:

private static final int[][] fields = {
        {Calendar.MILLISECOND},
        {Calendar.SECOND},
        {Calendar.MINUTE},
        {Calendar.HOUR_OF_DAY, Calendar.HOUR},
        {Calendar.DATE, Calendar.DAY_OF_MONTH, Calendar.AM_PM 
            /* Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK, Calendar.DAY_OF_WEEK_IN_MONTH */
        },
        {Calendar.MONTH, DateUtils.SEMI_MONTH},
        {Calendar.YEAR},
        {Calendar.ERA}};

Как видите, ничего общего с Calendarполя WEEK-ish, так что я думаю, что я должен сделать это вручную... Любые другие мысли / рекомендации приветствуются!

2 ответа

Решение

На самом деле невозможно урезать на неделю разумным способом. Рассмотрим следующую дату:

2014-11-01 12:01:55

2014-11-01 12:01:00 // truncate minute
2014-11-01 00:00:00 // truncate day
2014-11-00 00:00:00 // truncate month

Первоначальная дата - суббота. Так что же означает усечение недели в этом случае? Должны ли мы урезать до предыдущего понедельника? Если так, то это будет:

2014-10-27 00:00:00 // truncate week?

Это не кажется мне правильным. Мы изменили месяц в этом случае; иногда даже год меняется. Если вы можете придумать разумный способ описать это (и некоторые варианты использования), пожалуйста, сообщите о проблеме, и мы рассмотрим ее. Но это кажется мне областью, которая не имеет смысла для усечения.

Вы можете найти некоторые идеи для вашей первоначальной проблемы здесь: Получить дату текущей недели в понедельник

ТЛ; др

LocalDate.now( 
    ZoneId.of( "Africa/Tunis" )
).with( 
    TemporalAdjuster.previousOrSame​( DayOfWeek.MONDAY )
)

java.time

Нет необходимости во внешней библиотеке, такой как DateUtils, Используйте классы java.time, встроенные в Java 8 и более поздние версии.

Похоже, ваш реальный вопрос в том, как получить первый день недели для конкретной даты.

Часовой пояс

Часовой пояс имеет решающее значение при определении даты. В любой момент времени дата меняется по всему земному шару в зависимости от зоны. Например, через несколько минут после полуночи в Париже Франция - новый день, а в Монреале-Квебеке все еще "вчера".

Укажите правильное название часового пояса в формате continent/region, такие как America/Montreal, Africa/Casablanca, или же Pacific/Auckland, Никогда не используйте 3-4-буквенные псевдозоны, такие как EST или же IST поскольку они не являются истинными часовыми поясами, не стандартизированы и даже не уникальны (!).

ZoneId z = ZoneId.of( "America/Montreal" ) ;

LocalDate класс представляет значение только для даты без времени суток и без часового пояса.

LocalDate today = LocalDate.now( z );

Чтобы получить первый день недели для этой даты, мы должны определить первый день недели. Это определение зависит от культуры. В Соединенных Штатах мы обычно имеем в виду воскресенье. Значительная часть остального мира означает понедельник. Что когда-либо для ваших пользователей, укажите с DayOfWeek Перечислить объект.

Чтобы перейти от нашей даты к этой дате, используйте TemporalAdjuster реализация найдена в TemporalAdjusters учебный класс.

LocalDate firstOfWeek = today.with( 
    TemporalAdjuster.previousOrSame​( DayOfWeek.MONDAY ) 
) ;
Другие вопросы по тегам