Avatar ·

Как получить текущую дату и время в формате ГГГГ-ММ-ДД ЧЧ:ММ:СС.миллисекунды в Java?

Всем привет! Я новичок в Java и пишу небольшое приложение для логирования событий. Мне нужно записывать в файл текущее время с точностью до миллисекунд в формате: `2023-11-15 14:30:25.123`. Пробовал использовать `java.util.Date` и `SimpleDateFormat`, но что-то идёт не так. Вот мой код: ```java import java.util.Date; import java.text.SimpleDateFormat; public class Main { public static void main(String[] args) { Date now = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-DD HH:MI:SS.mmm"); String formattedDate = sdf.format(now); System.out.println(formattedDate); } } ``` На выходе я получаю что-то странное: `2023-11-335 14:09:25.025`. Откуда берётся `335` вместо дня месяца? И почему минуты показываются как `MI`, а не реальные минуты? Я уже перепробовал разные комбинации букв в шаблоне, но документация для меня пока сложновата. Подскажите, пожалуйста, как правильно это сделать? Может, есть более современный способ? Буду очень благодарен за подробное объяснение. <<>>

Проблема в вашем коде

Вы допустили несколько типичных ошибок в шаблоне SimpleDateFormat:

  • YYYY — это "week year" (год по неделям), а не календарный год. Для обычного года используйте yyyy.
  • DD — это день в году (от 1 до 365/366), а не день месяца. Для дня месяца используйте dd.
  • MI — такой паттерн не существует. Минуты обозначаются как mm.
  • SS — секунды, правильно: ss.
  • mmm — миллисекунды, правильно: SSS (заглавные).

Решение №1: Исправленный SimpleDateFormat (старый способ)

Вот корректный код с использованием старого API java.util.Date:

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

public class Main {
    public static void main(String[] args) {
        Date now = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        String formattedDate = sdf.format(now);
        System.out.println(formattedDate); // Вывод: 2023-11-15 14:30:25.123
    }
}

Решение №2: Современный способ (Java 8+)

Начиная с Java 8, рекомендуется использовать пакет java.time. Он гораздо удобнее и потокобезопасен:

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

public class Main {
    public static void main(String[] args) {
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
        String formattedDate = now.format(formatter);
        System.out.println(formattedDate); // Вывод: 2023-11-15 14:30:25.123
    }
}

Подробное объяснение паттернов

Вот таблица самых часто используемых символов форматирования:

  • yyyy — год из 4 цифр (2023)
  • MM — месяц из 2 цифр (01-12)
  • dd — день месяца из 2 цифр (01-31)
  • HH — часы в 24-часовом формате (00-23)
  • mm — минуты (00-59)
  • ss — секунды (00-59)
  • SSS — миллисекунды (000-999)

Важные замечания

1. SimpleDateFormat не потокобезопасен — если вы используете его в многопоточной среде, создавайте новый экземпляр для каждого потока или используйте ThreadLocal.

2. В Java 8+ старый Date и Calendar считаются устаревшими. Новая библиотека java.time решает все проблемы старого API: неизменяемость объектов, потокобезопасность, правильная работа с часовыми поясами.

3. Если вам нужно время с учётом часового пояса, используйте ZonedDateTime:

import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

ZonedDateTime now = ZonedDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS z");
System.out.println(now.format(formatter)); // Вывод: 2023-11-15 14:30:25.123 MSK

Надеюсь, теперь стало понятно! Удачи в изучении Java.

<<>>

Альтернативный подход: использование java.util.Calendar

Если по каким-то причинам вы не можете использовать Java 8+, а старый SimpleDateFormat кажется ненадёжным, можно собрать строку вручную через Calendar:

import java.util.Calendar;

public class Main {
    public static void main(String[] args) {
        Calendar cal = Calendar.getInstance();
        String formattedDate = String.format("%04d-%02d-%02d %02d:%02d:%02d.%03d",
            cal.get(Calendar.YEAR),
            cal.get(Calendar.MONTH) + 1, // Месяцы в Calendar считаются с 0
            cal.get(Calendar.DAY_OF_MONTH),
            cal.get(Calendar.HOUR_OF_DAY),
            cal.get(Calendar.MINUTE),
            cal.get(Calendar.SECOND),
            cal.get(Calendar.MILLISECOND));
        System.out.println(formattedDate);
    }
}

Дополнительный совет: используйте библиотеку Joda-Time

Если вы работаете с Java 7 или более ранней версией, отличной альтернативой является библиотека Joda-Time (она была предшественником java.time):

import org.joda.time.LocalDateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

LocalDateTime now = LocalDateTime.now();
DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS");
System.out.println(fmt.print(now));

Joda-Time также потокобезопасна и имеет более чистый API по сравнению со старыми классами Java. Однако для новых проектов на Java 8+ лучше использовать встроенный java.time.