Недопустимый символ шаблона '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 для форматов строк даты и времени.
Оба:
- фреймворк java.time, встроенный в Java 8 и более поздние версии (Учебное пособие)
- БиблиотекаJoda-Time
... используйте форматы 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.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 ....
Проект 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);