Как строго разбирать дату всего за год и неделю, когда первый день этой недели в прошлом году?

Моя цель - иметь строгий синтаксический анализ (и, например, запретить даты типа "98/99" ). Однако следующий код вызывает сообщение java.text.ParseException с сообщением Unparseable date: "98/01":

SimpleDateFormat sdf = new SimpleDateFormat("yy/ww");
sdf.setLenient(false);
sdf.parse("98/01");

Это действительно для первая неделя 1998 года, которая начинается в четверг. Однако синтаксический анализ недели всегда возвращает дату первого дня этой недели. В этом случае это будет 12/29/1997. И поэтому возникает исключение.

Кажется, эта проблема исходит из класса GregorianCalendar и, более конкретно, из метода computeTime(), который проверяет, соответствуют ли исходные поля полям, установленным извне, когда синтаксический анализ не снижен:

if (!isLenient()) {
  for (int field = 0; field < FIELD_COUNT; field++) {
    if (!isExternallySet(field)) {
      continue;
    }

    if (originalFields[field] != internalGet(field)) {
      // Restore the original field values
      System.arraycopy(originalFields, 0, fields, 0, fields.length);
      throw new IllegalArgumentException(getFieldName(field));
    }
  }
}

Это ошибка? Я считаю, что анализ 1998/01 должен действительно вернуться 12/29/1997 и не приводить к каким-либо исключениям. Однако, знаете ли вы, как сделать результирующий вывод 01/01/1998 вместо этого (который будет первым днем ​​недели в указанном году)?

Ответ 1

Я думаю, что это должно сработать для вас (для этого вам нужно время для библиотеки):

public static Date parseYearWeek(String yearWeek) {
    DateTime dateTime = DateTimeFormat.forPattern("yy/ww").parseDateTime(yearWeek);

    if (dateTime.getWeekOfWeekyear() == 1 && dateTime.getMonthOfYear() == 12) {
        dateTime = DateTimeFormat.forPattern("yyyy/mm").parseDateTime((dateTime.getYear() + 1) + "/01");
    }

    return dateTime.toDate();
}

Ответ 2

Вы можете использовать четверг в качестве ссылки, вычесть 3 дня для расчета даты понедельника. Определение ИСО 8601 1-й недели - первая неделя, где происходит четверг. Это устранит компенсирующий код. Код ниже найдет понедельник в неделю, даже если понедельник находится в "предыдущем" году.

String yearWeek = "201301";
DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyywwEEE").withLocale(Locale.US);
DateTime mondayInWeek= fmt.parseDateTime(yearWeek + "Thu").minusDays(3);// ISO 8601 def of week 1 is first week where Thursday occurs
System.out.println(mondayInWeek);