Разбор строки в java.util.Date - PullRequest
0 голосов
/ 17 мая 2018

Я пытался преобразовать строку ввода даты "2018-09-31" в дату. Я ожидал, что это будет "2018-09-30" или, по крайней мере, "2018-09-30T00: 00: 00Z".Но на удивление это оказалось чем-то другим.Может кто-нибудь объяснить, почему это так?и как сделать так, чтобы она соответствовала только дате ввода?

import org.apache.commons.lang3.time.FastDateFormat;

private static final FastDateFormat dateOnlyFormat = FastDateFormat.getInstance("yyyy-MM-dd");

@Test
public void getSQLDateWithOnlyDate() {
    java.util.Date date = null;
    try {
        String dateString = "2018-09-31";
        date = dateOnlyFormat.parse(dateString);
        System.out.println("input date : " + dateString);
        System.out.println("date.toInstant() : " + date.toInstant());
        System.out.println("date.toString() : " + date.toString());
    } catch (ParseException e) {
        e.printStackTrace();
    }

}

output

input date : 2018-09-31
date.toInstant() : 2018-09-30T14:00:00Z
date.toString() : Mon Oct 01 00:00:00 AEST 2018

1 Ответ

0 голосов
/ 17 мая 2018

Что пошло не так?

О, БОЖИЕ ПАУКИ уже объяснили некоторые из них в комментарии. В сентябре 30 дней. Ваш форматтер экстраполирует: 31 сентября означает день после 30 сентября, то есть 1 октября.

Но время суток, 14:00:00? Это проблема часового пояса. Ваш форматтер, если не указано иное, использует настройку часового пояса JVM. Например, это может быть Австралия / Сидней, по крайней мере, ваш Date отображает его как AEST, что, как я понимаю, означает Австралийское восточное стандартное время. Таким образом, ваша строка анализируется на 1 октября в 00:00:00 по смещению +10: 00 от UTC. Это тот же момент времени, что и 30 сентября, 14:00:00 UTC. Поскольку Instant.toString() отображает момент времени в UTC (обозначается суффиксом Z), вы получаете 2018-09-30T14:00:00Z.

Исправление

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

    String dateString = "2018-09-31";

    try {
        LocalDate.parse(dateString);
    } catch (DateTimeParseException dtpe) {
        System.out.println(dtpe);
    }

Это печатает:

java.time.format.DateTimeParseException: текст «2018-09-31» не может быть проанализировано: неверная дата '31 сентября'

Если вы хотели экстраполирующего поведения, которое вы наблюдали:

    DateTimeFormatter dateFormatter = DateTimeFormatter.ISO_LOCAL_DATE
            .withResolverStyle(ResolverStyle.LENIENT);
    System.out.println(LocalDate.parse(dateString, dateFormatter));

2018-10-01

Вы сказали, что ожидали 2018-09-30, но я не знаю простого способа дать вам это. Мое первое предложение - подумайте еще раз и спросите, действительно ли вам это нужно.

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

Ваше имя метода, getSQLDateWithOnlyDate, может указывать на то, что вы намереваетесь использовать свою дату с базой данных SQL? Одно из преимуществ LocalDate (и других java.time типов) заключается в том, что вы можете передать его непосредственно вашим PreparedStatement setObject методам, при условии, что вы используете как минимум Java 8 и как минимум JDBC 4.2. Ваша реализация JPA тоже должна с радостью принять объект LocalDate.

Ссылка: Обучающее руководство по Oracle: Дата и время , объясняющее, как использовать java.time.

...