Подтвердить что ты не робот

Java SimpleDateFormat всегда возвращает январь за месяц

Я работаю над тем, чтобы присвоить значение даты (createWhen) из Active Directory и перевести его на дату Java, чтобы получить список учетных записей, созданных между двумя датами. Все работает нормально, за исключением одного метода: метод, по которому я перехожу от даты AD к дате Java. Метод выглядит следующим образом:

private Date getParsedDate(String givenString) {
    System.out.println("Value from AD is: " + givenString);
    Date parsedDate = null;
    String formattedString = this.formatDateString(givenString);
    System.out.println("Formatted String is: " + formattedString);
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/DD");
    try {
        parsedDate = sdf.parse(formattedString);
        System.out.println("Final date string is: " + parsedDate.toString());
    } catch (ParseException ex) {
        ex.printStackTrace();
    }
    return parsedDate;
}

И, для одного куска произвольных данных из AD:

Value from AD is: 20050912190509.0Z

Formatted String is: 2005/09/12

Final date string is: Wed Jan 12 00:00:00 EST 2005

Очевидно, что он правильно подбирает день и год (и если я предпочитаю включать часы/минуты/секунды, он включает их также правильно), но каждая дата помещается в январе по какой-либо причине.

Теперь я уверен, что моя ошибка довольно простая, но я перепроверяла свое форматирование примерно десять раз, и я нахожусь в точке, где я просто не могу ее больше увидеть. Может ли вторая пара глаз, надеюсь, просмотреть мой код и указать, где я ошибаюсь, чтобы сделать месяц настолько грубо неправильным?

Спасибо.

4b9b3361

Ответ 1

Измените строку шаблона с "yyyy/MM/DD" на "yyyy/MM/dd"

SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");

Ответ 2

Убедитесь, что не используйте 'мм' вместо "ММ" или "МММ". Поскольку малый m обозначает минуты, а колпачки M обозначает месяц.

Ответ 3

TL; DR

    LocalDate parsedDate = OffsetDateTime
            .parse("20050912190509.0Z", DateTimeFormatter.ofPattern("uuuuMMddHHmmss.SX"))
            .toLocalDate();

Это дает a LocalDate of 2005-09-12.

java.time

Я вношу свой вклад в современный ответ. Ответ Сухаса Фарталес является правильным и был хорошим ответом, когда он был написан 7 лет назад. Теперь пресловутый проблемный класс SimpleDateFormat устарел, и мы намного лучше в java.time, современном Java-интерфейсе даты и времени. Я настоятельно рекомендую вам использовать это вместо старых классов времени.

Подробнее

Кажется, из вашего кода вы переформатируете свою строку из AD до ее разбора. В этом нет необходимости, строка из AD может быть проанализирована напрямую. Мы могли бы проанализировать его непосредственно в LocalDate, но я рекомендую разбить его на OffsetDateTime, чтобы захватить время и смещение от строки; как вы можете видеть, это может быть напрямую преобразовано в LocalDate. A LocalDate - это дата без времени суток, поэтому она соответствует вашим требованиям лучше, чем старый класс Date.

Строка находится в формате UTC (в конце обозначается символом Z). Вышеприведенный дает вам дату из строки, то есть дату в UTC. Если бы вы хотели, чтобы дата была в вашем местном часовом поясе, когда было 12 сентября 19:05 в UTC:

    LocalDate parsedDate = OffsetDateTime.parse(givenString, adDateTimeFormatter)
            .atZoneSameInstant(ZoneId.of("America/Coral_Harbour"))
            .toLocalDate();

Я предположил, что мы объявили форматирование статическим полем:

private static final DateTimeFormatter adDateTimeFormatter
        = DateTimeFormatter.ofPattern("uuuuMMddHHmmss.SX");

В этом случае результат будет таким же, для других часовых поясов это не будет. Пожалуйста, замените свой собственный часовой пояс для America/Coral_Harbour. Чтобы использовать настройку часового пояса JVM, укажите ZoneId.systemDefault(). Однако обратите внимание, что настройка может быть изменена другими частями вашей программы или другими программами, запущенными в одной JVM, поэтому это хрупкое.

И точка ответа Suhas Phartales справедлива и в java.time: форматирование строк шаблона чувствительно к регистру, и мне нужно было использовать строчный dd для дня месяца.

Учебник

Подробнее о java.time в учебнике Oracle и/или найти другие ресурсы в сети.