Вопрос-ответ

Illegal pattern character 'T' when parsing a date string to java.util.Date

Недопустимый символ шаблона 'T' при анализе строки даты в java.util.Date

У меня есть строка даты, и я хочу разобрать ее до обычной даты, используя java Date API, ниже приведен мой код:

public static void main(String[] args) {
String date="2010-10-02T12:23:23Z";
String pattern="yyyy-MM-ddThh:mm:ssZ";
SimpleDateFormat sdf=new SimpleDateFormat(pattern);
try {
Date d=sdf.parse(date);
System.out.println(d.getYear());
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

Однако я получил исключение: java.lang.IllegalArgumentException: Illegal pattern character 'T'

Итак, я задаюсь вопросом, должен ли я разделить строку и разобрать ее вручную?

Кстати, я попытался добавить символ одинарной кавычки по обе стороны от буквы T:

String pattern="yyyy-MM-dd'T'hh:mm:ssZ";

Это также не работает.

Переведено автоматически
Ответ 1

Обновление для Java 8 и выше

Теперь вы можете просто выполнить Instant.parse("2015-04-28T14:23:38.521Z") и получить правильную вещь, тем более что вы должны использовать Instant вместо сломанного java.util.Date в самых последних версиях Java.

Вы также должны использовать DateTimeFormatter вместо SimpleDateFormatter.

Оригинальный ответ:


Приведенное ниже объяснение все еще актуально в отношении того, что представляет формат. Но оно было написано до повсеместного распространения Java 8, поэтому в нем используются старые классы, которые вам не следует использовать, если вы используете Java 8 или выше.


Это работает с вводом в концеZ, как показано:


В шаблоне T экранируется с помощью ' с обеих сторон.


Шаблон для Z в конце на самом деле XXX такой, как задокументировано в JavaDoc для SimpleDateFormat, просто не очень понятно, как его использовать, поскольку Z также является маркером для старой TimeZone информации.


Q2597083.java

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

public class Q2597083
{
/**
* All Dates are normalized to UTC, it is up the client code to convert to the appropriate TimeZone.
*/

public static final TimeZone UTC;

/**
* @see <a href="http://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations">Combined Date and Time Representations</a>
*/

public static final String ISO_8601_24H_FULL_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";

/**
* 0001-01-01T00:00:00.000Z
*/

public static final Date BEGINNING_OF_TIME;

/**
* 292278994-08-17T07:12:55.807Z
*/

public static final Date END_OF_TIME;

static
{
UTC = TimeZone.getTimeZone("UTC");
TimeZone.setDefault(UTC);
final Calendar c = new GregorianCalendar(UTC);
c.set(1, 0, 1, 0, 0, 0);
c.set(Calendar.MILLISECOND, 0);
BEGINNING_OF_TIME = c.getTime();
c.setTime(new Date(Long.MAX_VALUE));
END_OF_TIME = c.getTime();
}

public static void main(String[] args) throws Exception
{

final SimpleDateFormat sdf = new SimpleDateFormat(ISO_8601_24H_FULL_FORMAT);
sdf.setTimeZone(UTC);
System.out.println("sdf.format(BEGINNING_OF_TIME) = " + sdf.format(BEGINNING_OF_TIME));
System.out.println("sdf.format(END_OF_TIME) = " + sdf.format(END_OF_TIME));
System.out.println("sdf.format(new Date()) = " + sdf.format(new Date()));
System.out.println("sdf.parse(\"2015-04-28T14:23:38.521Z\") = " + sdf.parse("2015-04-28T14:23:38.521Z"));
System.out.println("sdf.parse(\"0001-01-01T00:00:00.000Z\") = " + sdf.parse("0001-01-01T00:00:00.000Z"));
System.out.println("sdf.parse(\"292278994-08-17T07:12:55.807Z\") = " + sdf.parse("292278994-08-17T07:12:55.807Z"));
}
}

Выдает следующий результат:

sdf.format(BEGINNING_OF_TIME) = 0001-01-01T00:00:00.000Z
sdf.format(END_OF_TIME) = 292278994-08-17T07:12:55.807Z
sdf.format(new Date()) = 2015-04-28T14:38:25.956Z
sdf.parse("2015-04-28T14:23:38.521Z") = Tue Apr 28 14:23:38 UTC 2015
sdf.parse("0001-01-01T00:00:00.000Z") = Sat Jan 01 00:00:00 UTC 1
sdf.parse("292278994-08-17T07:12:55.807Z") = Sun Aug 17 07:12:55 UTC 292278994
Ответ 2

tl; dr

Используйте java.time.Instant класс для разбора текста в стандартном формате ISO 8601, представляющем момент времени в UTC.

Instant.parse( "2010-10-02T12:23:23Z" )

ISO 8601

Этот формат определен в стандарте ISO 8601 для форматов строк даты и времени.

Оба:

... используйте форматы ISO 8601 по умолчанию для синтаксического анализа и генерации строк.

Обычно вам следует избегать использования старого java.util.Date/ .Классы Calendar и java.text.SimpleDateFormat, как известно, являются хлопотными, запутанными и некорректными. Если требуется для взаимодействия, вы можете выполнять преобразования туда и обратно.

java.time

В Java 8 и более поздних версиях встроен новый фреймворк java.time. Вдохновлен Joda-Time, определен в JSR 310 и расширен в проекте ThreeTen-Extra.

Instant instant = Instant.parse( "2010-10-02T12:23:23Z" );  // `Instant` is always in UTC.

Преобразовать в старый класс.

java.util.Date date = java.util.Date.from( instant );  // Pass an `Instant` to the `from` method.

Часовой пояс

При необходимости вы можете назначить часовой пояс.

ZoneId zoneId = ZoneId.of( "America/Montreal" ); // Define a time zone rather than rely implicitly on JVM’s current default time zone.
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId ); // Assign a time zone adjustment from UTC.

Преобразовать.

java.util.Date date = java.util.Date.from( zdt.toInstant() );  // Extract an `Instant` from the `ZonedDateTime` to pass to the `from` method.

Joda-Time

ОБНОВЛЕНИЕ: проект Joda-Time теперь находится в режиме обслуживания. Команда рекомендует перейти на классы java.time.

Вот несколько примеров кода в Joda-Time 2.8.

org.joda.time.DateTime dateTime_Utc = new DateTime( "2010-10-02T12:23:23Z" , DateTimeZone.UTC );  // Specifying a time zone to apply, rather than implicitly assigning the JVM’s current default.

Преобразовать в старый класс. Обратите внимание, что назначенный часовой пояс теряется при преобразовании, поскольку j.u.Date не может быть назначен часовой пояс.

java.util.Date date = dateTime_Utc.toDate(); // The `toDate` method converts to old class.

Часовой пояс

При необходимости вы можете назначить часовой пояс.

DateTimeZone zone = DateTimeZone.forID( "America/Montreal" );
DateTime dateTime_Montreal = dateTime_Utc.withZone ( zone );

Таблица типов даты и времени в Java, как современной, так и устаревшей.


О java.time

Платформа java.time встроена в Java 8 и более поздние версии. Эти классы вытесняют старые, устаревшие классы даты и времени, такие как java.util.Date, Calendar, & SimpleDateFormat.

Проект Joda-Time, который сейчас находится в режиме обслуживания, рекомендует перейти на классы java.time.

Чтобы узнать больше, ознакомьтесь с Руководством по Oracle. И найдите в Stack Overflow множество примеров и пояснений. Спецификация - JSR 310.

Вы можете обмениваться объектами java.time непосредственно со своей базой данных. Используйте драйвер JDBC, совместимый с JDBC 4.2 или более поздней версии. Нет необходимости в строках, нет необходимости в java.sql.* классах.

Где получить классы java.time?


  • Java SE 8, Java SE 9 и более поздние версии

    • Встроенный.

    • Часть стандартного Java API с комплексной реализацией.

    • Java 9 добавляет некоторые незначительные функции и исправления.


  • Java SE 6 и Java SE 7

    • Большая часть функций java.time перенесена обратно на Java 6 и 7 в ThreeTen-Backport.


  • Android

    • Более поздние версии Android bundle реализуют классы java.time.

    • Для более ранних версий Android (<26) проект ThreeTenABP адаптирует ThreeTen-Backport (упомянутый выше). Смотрите Как использовать ThreeTenABP ....


Таблица того, какую библиотеку java.time использовать с какой версией Java или Android.

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является испытательным полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти несколько полезных классов, таких как Interval, YearWeek, YearQuarter и больше.

Ответ 3

Вы можете разобрать строку до метки времени следующим методом:

public static void main(String[] args) {

String timeStr = "2021-11-11T10:25:35+00:00";
System.out.println(convertStringToTimestamp(timeStr));

}

static Timestamp convertStringToTimestamp(String dateAsString) {
OffsetDateTime offsetDateTime = OffsetDateTime.parse(dateAsString);
final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
return Optional.ofNullable(offsetDateTime.toString())
.map(value -> LocalDateTime.parse(value, dateTimeFormatter))
.map(Timestamp::valueOf)
.orElse(null);
}
Ответ 4

На данный момент выше есть два ответа, и оба они длинные (и tl; dr слишком короткие, ИМХО), поэтому я пишу краткое изложение своего опыта использования новой библиотеки java.time (применимо, как указано в других ответах, к Java версии 8+). ISO 8601 устанавливает стандартный способ записи дат: YYYY-MM-DD поэтому формат даты-времени такой, как показано ниже (может быть 0, 3, 6 или 9 цифр для миллисекунд), и форматирование строки не требуется:

import java.time.Instant;
public static void main(String[] args) {
String date="2010-10-02T12:23:23Z";
try {
Instant myDate = Instant.parse(date);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

Мне это не было нужно, но поскольку получение year находится в коде из вопроса, то:

это сложнее, не может быть выполнено из Instant напрямую, может быть сделано через Calendar в виде вопросов Получить целочисленное значение текущего года в Java и преобразовать java.time в Calendar но ИМХО, поскольку формат фиксирован, подстрока более проста в использовании:

myDate.toString().substring(0,4);
java date