У меня есть этот код:
public static void main(String[] args) throws ParseException {
String fecha = "2022-11-08 10:28:04.282551-06";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ");
Date e = simpleDateFormat.parse(fecha);
SimpleDateFormat newSimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
System.out.println(newSimpleDateFormat.format(e));
}
И эта ошибка:
Exception in thread "main" java.text.ParseException: Unparseable date: "2022-11-08 10:28:04.282551-06"
at java.text.DateFormat.parse(DateFormat.java:366)
at Ejemplos.main(Ejemplos.java:11)
Я хочу, чтобы моя новая дата была такой: 2022-11-08 10:28:04.282551 Это значение после точки *282551 *иногда может быть меньше, например: *282 *или 2825, а иногда точки нет, например: 2022-11-08 10:28:04-06
Я настоятельно рекомендую вам не использовать SimpleDateFormat и Date. Они хлопотны и давно устарели. Также нет способа, которым SimpleDateFormat может разобрать 6 знаков после запятой доли секунды, так что это не сработает. Используйте OffsetDateTime и DateTimeFormatter, возможно также DateTimeFormatterBuilder; все взяты из java.time, современного API даты и времени Java.
Я нашел решение для вашей проблемы. сначала вам нужно разбить строку, а после этого вы можете отформатировать ее. попробуй это
public static void main(String[] args) throws ParseException {
String fecha = "2022-11-08 10:28:04.282551-06";
String[] parts = fecha.split("\\.");
String part1 = parts[0];
String part2 = parts[1];
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(simpleDateFormat.parse(part1));
}
Спасибо за желание внести свой вклад. (1) Использование SimpleDateFormat не рекомендуется (хотя оно также использовалось в вопросе). (2) Это неправильно. Вы игнорируете долю секунды и смещение. Первое приводит к погрешности менее секунды, второе — до 26 часов, что, вероятно, неприемлемо. Ожидаемый результат в моем часовом поясе (Европа/Копенгаген, на 1 час впереди UTC): Tue Nov 08 17:28:04 CET 2022. Наблюдаемый результат: Tue Nov 08 10:28:04 CET 2022. Ошибся на 7 часов.
Настоятельно рекомендуется прекратить использование устаревших классов Date, Calendar, SimpleDateFormat, ... - они были заменены классами из пакета java.time и подпакетов, таких как LocalDateTime, ZonedDateTime, DateTimeFormatter, ...
Поскольку у нас есть дробная часть с переменным размером, нам нужен DateTimeFormatterBuilder, чтобы создать соответствующий модуль форматирования для разбора строки. В нем мы повторно используем существующий ISO_LOCAL_TIME, который обрабатывает требование, принимая от нуля до 9 знаков после запятой доли секунды.
private static final DateTimeFormatter PARSE_FORMATTER =
new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral(' ')
.append(DateTimeFormatter.ISO_LOCAL_TIME) // accepts presence or absence of fraction
.appendOffset("+HHmm", "+00") // accepts -06 and +0530
.toFormatter(Locale.ROOT); // replace as needed
public static OffsetDateTime convert(String str) {
return OffsetDateTime.parse(str, PARSE_FORMATTER);
}
Чтобы иметь строку в формате «2022-11-08 10:28:04.282551», нам нужен дополнительный модуль форматирования:
private static final DateTimeFormatter FORMAT_FORMATTER =
DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSSSSS"); // time zone is IGNORED!!
public static String convertToString(OffsetDateTime dateTime) {
return dateTime.format(FORMAT_FORMATTER);
}
Предыдущие оба метода можно (очевидно) объединить в один метод, но предпочтительнее работать с объектами даты и времени (ZonedDateTime, OffsetDateTime, LocalDateTime, ...) вместо строк - строки должны использоваться только для ввода и вывода !
Вышеупомянутый Formatter не включает информацию о часовом поясе в результат, что может быть очень запутанным (ИМХО) - см. последнюю дату тестового вывода ниже. Пожалуйста, убедитесь, что это действительно необходимо!!! В противном случае мы можем преобразовать OffsetDateTme в ZonedDateTime, как в dateTime.atZoneSameInstant(ZoneId.systemDefault()).format(FORMAT_FORMATTER);. или включите информацию о часовом поясе в средство форматирования вывода, как показано внизу.
Тест для вышеуказанных методов:
public static void main(String[] args) {
// just for testing
Locale.setDefault(Category.DISPLAY, Locale.GERMANY);
Locale.setDefault(Category.FORMAT, Locale.GERMANY);
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Berlin"));
var data = """
2022-11-08 10:28:04.282551-06
2022-11-08 10:28:04.282-06
2022-11-08 10:28:04-06
2022-11-08 10:28:04+02
""".split("\n");
for (var str : data) {
test(str);
}
}
private static void test(String str) {
try {
System.out.printf("%-30s -> %s%n", str, convertToString(convert(str)));
} catch (Exception ex) {
System.err.printf("%-30s -> %s%n", str, ex);
}
}
Вывод:
openjdk version "20-ea" 2023-03-21 OpenJDK Runtime Environment (build 20-ea+12-790) OpenJDK 64-Bit Server VM (build 20-ea+12-790, mixed mode, sharing) 2022-11-08 10:28:04.282551-06 -> 2022-11-08 10:28:04.282551 2022-11-08 10:28:04.282-06 -> 2022-11-08 10:28:04.282000 2022-11-08 10:28:04-06 -> 2022-11-08 10:28:04.000000 2022-11-08 10:28:04+02 -> 2022-11-08 10:28:04.000000
Если мы хотим убедиться, что на выходе указан какой-то конкретный часовой пояс, мы можем, например, указать его в средстве форматирования следующим образом:
private static final DateTimeFormatter FORMAT_FORMATTER =
DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSSSSS")
.withZone(ZoneId.of("Europe/Berlin"));
Теперь вывод будет:
2022-11-08 10:28:04.282551-06 -> 2022-11-08 17:28:04.282551 2022-11-08 10:28:04.282-06 -> 2022-11-08 17:28:04.282000 2022-11-08 10:28:04-06 -> 2022-11-08 17:28:04.000000 2022-11-08 10:28:04+02 -> 2022-11-08 09:28:04.000000
Обновлено: версия средства форматирования синтаксического анализа, впервые представленная в этом ответе, была:
private static final DateTimeFormatter PARSE_FORMATTER =
new DateTimeFormatterBuilder()
.appendPattern("uuuu-MM-dd HH:mm:ss") // date time
.optionalStart()
.appendFraction(ChronoField.MICRO_OF_SECOND, 3, 6, true) // optional fractions
.optionalEnd()
.appendPattern("x") // time zone offset
.toFormatter()
.withLocale(Locale.ROOT); // replace as needed
Попросите производителя даты обеспечить стабильное представление этой даты и времени, лучше всего использовать формат даты и времени ISO8601. Если это невозможно, вы можете использовать java.util.regex.Pattern для определения формата заранее, прежде чем выбрать соответствующий DateTimeFormatter. Не используйте больше SimpleDateFormat или Date, переключитесь на типы из java.time.*