Avatar ·

Преобразование строки в дату Java: как правильно парсить дату из строки?

Всем привет! Я новичок в Java и бьюсь над проблемой уже несколько часов. Мне нужно преобразовать строку "2023-05-15 14:30:00" в объект Date. Я пробовал использовать SimpleDateFormat, но ничего не работает. Вот мой код:
String dateStr = "2023-05-15 14:30:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse(dateStr);
Компилятор ругается на непойманное исключение ParseException. Я добавил throws ParseException в метод main, но теперь программа просто вылетает с ошибкой. Пробовал разные форматы — "dd.MM.yyyy", "MM/dd/yyyy" — всё равно ошибка. Ещё я слышал, что SimpleDateFormat не потокобезопасный, но я пока работаю в одном потоке. Может быть, проблема в том, что у меня Java 8? Читал, что появился новый API java.time, но не знаю, как им пользоваться. Подскажите, пожалуйста, как правильно преобразовать строку в дату в современной Java? И что делать с этим ParseException? Заранее спасибо! P.S. Строка приходит из базы данных в формате "yyyy-MM-dd HH:mm:ss", иногда с миллисекундами, например "2023-05-15 14:30:00.123". Как обработать оба случая? <<>>

Решение: используем современный API java.time (Java 8+)

Привет! Ты столкнулся с классической проблемой, которая мучает многих новичков. В современной Java (8 и выше) не рекомендуется использовать SimpleDateFormat и java.util.Date — они устарели, неудобны и содержат множество подводных камней. Вместо этого используй пакет java.time.

Базовое преобразование строки в дату

Вот как правильно парсить твою строку "2023-05-15 14:30:00":

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class DateParser {
    public static void main(String[] args) {
        String dateStr = "2023-05-15 14:30:00";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime dateTime = LocalDateTime.parse(dateStr, formatter);
        System.out.println(dateTime); // 2023-05-15T14:30
    }
}

Важно: В отличие от SimpleDateFormat, DateTimeFormatter потокобезопасен и не выбрасывает проверяемые исключения (только DateTimeParseException — наследник RuntimeException).

Обработка миллисекунд (два формата в одной строке)

Если строка может быть как с миллисекундами, так и без, используй опциональные секции в паттерне:

String dateStr1 = "2023-05-15 14:30:00";
String dateStr2 = "2023-05-15 14:30:00.123";

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[.SSS]");
// Квадратные скобки делают часть паттерна опциональной

LocalDateTime dt1 = LocalDateTime.parse(dateStr1, formatter);
LocalDateTime dt2 = LocalDateTime.parse(dateStr2, formatter);
System.out.println(dt1); // 2023-05-15T14:30
System.out.println(dt2); // 2023-05-15T14:30:00.123

Если нужно получить java.util.Date (для старого кода)

Иногда требуется совместимость с устаревшими библиотеками. Конвертируй через Instant:

LocalDateTime localDateTime = LocalDateTime.parse(dateStr, formatter);
Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
Date legacyDate = Date.from(instant);

Почему не стоит использовать SimpleDateFormat

  • Не потокобезопасен — разделяемый экземпляр между потоками приведёт к гонке данных
  • Проверяемое исключение ParseException — засоряет код try-catch блоками
  • Проблемы с високосными годами — известны баги при парсинге 29 февраля
  • Не поддерживает ISO-8601 — для стандартных форматов приходится писать ручные паттерны

Распространённые ошибки новичков

  1. Путаница между yyyy и YYYY — y (year) и Y (week-based year) разные вещи. Всегда используй yyyy.
  2. Забывают про часовые пояса — если строка содержит смещение ("+03:00"), используй OffsetDateTime или ZonedDateTime вместо LocalDateTime.
  3. Неправильный паттерн для месяцев — MM (цифры 01-12) vs MMM (текстовое "Jan") vs MMMM (полное "January").

Лучшие практики

  • Храни форматтер как static final поле класса — он потокобезопасен
  • Для стандартных ISO-форматов используй готовые константы: DateTimeFormatter.ISO_LOCAL_DATE_TIME
  • Всегда обрабатывай DateTimeParseException при работе с пользовательским вводом

Теперь твой код будет работать надёжно и в многопоточной среде. Удачи!

<<>>

Альтернативный подход: используем SimpleDateFormat с правильной обработкой ошибок

Если по каким-то причинам ты не можешь перейти на java.time (например, используешь Java 7 или старую библиотеку), то вот рабочий вариант с SimpleDateFormat, но с правильной обработкой:

import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.util.Date;

public class LegacyDateParser {
    public static Date parseDate(String dateStr) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        sdf.setLenient(false); // строгий режим — не позволит парсить "2023-13-01"
        try {
            return sdf.parse(dateStr);
        } catch (ParseException e) {
            System.err.println("Ошибка парсинга даты: " + e.getMessage());
            return null; // или выбросить своё исключение
        }
    }

    public static void main(String[] args) {
        Date date = parseDate("2023-05-15 14:30:00");
        if (date != null) {
            System.out.println(date);
        }
    }
}

Обработка миллисекунд — создавай два форматтера и пробуй по очереди:

SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
try {
    return sdf1.parse(dateStr);
} catch (ParseException e) {
    return sdf2.parse(dateStr); // может снова выбросить ParseException
}

Важно: SimpleDateFormat не потокобезопасен — создавай новый экземпляр для каждого парсинга или используй ThreadLocal. Этот подход — "костыль" для старого кода, в новых проектах всегда используй java.time.