ISO 8601 дата и время

Мне нужен именно этот формат в java, который в С# DateTime.Now.ToString("o"). Пример возвращенной даты для DateTime.Now.ToString("o") -

2016-03-10T11: 24: 59,7862749 + 04: 00

а затем в sql он вставлен как

2016-03-10 11: 24: 59.786

Я пытаюсь вставить тот же формат даты из java. Я использую это:

TimeZone tz = TimeZone.getTimeZone("UTC");
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mmZ");
df.setTimeZone(tz);
String nowAsISO = df.format(new Date());

и он возвращает это

2016-03-10T07: 29 + 0000

Из-за этого формата он идет с ошибкой. Как я могу изменить формат в точности, что хочу?

Ответ 1

Для Java 7 вы можете использовать:

SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
System.out.println(df.format(new Date()));

В этом случае используется символ шаблона XXX, который также печатает двоеточие внутри смещения. Однако для Java-6 эта функция не предлагается. И точность всегда ограничена миллисекундами.

Для Java-8 вы также можете использовать:

DateTimeFormatter dtf = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
System.out.println(OffsetDateTime.now().format(dtf)); // 2016-03-10T08:46:44.849+01:00

Это позволяет наносекундную точность, если такие часы доступны (начиная с Java-9).

Для Java-6 примените хак на основе SimpleDateFormat или используйте внешние библиотеки:

// Java-6 (SimpleDateFormat)
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
String text = sdf.format(new Date());
text = text.substring(0, text.length() - 2) + ":" + text.substring(text.length() - 2);
System.out.println(text);

// Joda-Time
DateTime now = DateTime.now();
System.out.println(DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZZ").print(now));

// Time4J
Moment now = SystemClock.currentMoment();
System.out.println(Iso8601Format.EXTENDED_DATE_TIME_OFFSET.withStdTimezone().format(now));

Ответ 2

используйте этот формат "yyyy-MM-dd'T'HH: mm: ss.SSSZ"

Пример:

SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");

System.out.println(df.format(new Date()));

Ответ 3

Ответ Мено Хохшильда. Я просто добавлю еще несколько комментариев и код, специфичный для SQL.

Избегать старых классов времени

Старые классы времени-времени, java.util.Date/.Calendar и java.text.SimpleDateFormat, плохо разработаны, запутываются и неприятны. Избегайте их.

Старые кланы были вытеснены рамкой java.time, встроенной в Java 8 и более поздних версий.

Для использования перед Java 8 ознакомьтесь с проектом ThreeTen-Backport.

наносекунд

Классы java.time имеют наносекундное разрешение. Таким образом, у вас не будет проблемы с потерей данных, если 2016-03-10T11:24:59.7862749+04:00 будет усечен до 2016-03-10 11:24:59.786 из-за разрешения в миллисекундах, используемого старыми классами.

Получение текущего момента в Java 8 ограничено миллисекундами, три цифры десятичной доли секунды, из-за устаревшей проблемы. Java 9 получит текущий момент в наносекундах, до девяти цифр десятичной доли (если ваши аппаратные часы вашего компьютера могут обеспечить такое точное разрешение).

ISO 8601

Стандарт ISO 8601 определяет разумные текстовые форматы для значений даты и времени. Например, 2016-03-09T23:24:33Z или 2016-03-09T22:24:33-01:00. Классы java.time используют их по умолчанию, поэтому нет необходимости определять шаблоны разбора.

Instant

An Instant - момент на временной шкале в UTC.

Instant instant = Instant.now();

Вызвать Instant::toString для создания строки в стандартном формате.

String output = instant.toString();

2016-03-09T23: 24: 33.123Z

OffsetDateTime

Примените ZoneOffset, чтобы получить OffsetDateTime.

ZoneOffset zoneOffset = ZoneOffset.ofHoursMinutes( -5 , 30 );
OffsetDateTime odt = OffsetDateTime.ofInstant( instant , zoneOffset );

ZonedDateTime

Если вы знаете полный часовой пояс, а не только offset-from-UTC, примените ZoneId, чтобы получить ZonedDateTime.

Используйте правильные названия часовых поясов.

ZoneId zoneId = ZoneId.of( "Asia/Kolkata" ); // "Europe/Paris", "America/Montreal", etc.
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

java.sql.Timestamp

Будем надеяться, что драйверы JDBC будут обновлены, чтобы напрямую использовать типы java.time. До этого мы конвертируем в java.sql типы для передачи данных в/из базы данных.

Как отмечалось выше, java.time может обрабатывать наносекунды. Таким образом, java.sql.Timestamp. Но ваша база данных не может. Некоторые базы данных ограничены целыми секундами, миллисекундами или микросекундами. Когда данные передаются через JDBC в базу данных, база данных может усекаться.

java.sql.Timestamp ts = java.sql.Timestamp.from( instant );

... и идя в другом направлении...

Instant instant = ts.toInstant();

Обратите внимание, что Instant всегда находится в UTC по определению. Поэтому нет необходимости выполнять код, который был предпринят в конце Вопроса.

Рабочий поток

Вы должны минимизировать использование строк при работе с датой. Максимизируйте использование полезных классов/объектов даты и времени, а именно классов java.time. Прекратите думать о строках в качестве значений даты и времени - они представляют собой текстовое представление значения даты и времени.

Не вставлять/извлекать значения даты и времени в/из вашей базы данных в виде строк. Использовать объекты java.sql, такие как java.sql.Timestamp и java.sql.Date. Используйте PreparedStatement и методы "set/get", такие как setTimestamp/getTimestamp. И фактически всегда определяет ваши столбцы в базе данных как TIMESTAMP WITH TIME ZONE, а не "без часового пояса".

При получении данных из базы данных используйте типы java.sql. Но как только это возможно, конвертируйте в типы java.time. Типы java.sql - это беспорядок, грязный взлом и должны использоваться только для передачи данных, а не для бизнес-логики.

Как правило, лучше всего использовать UTC в вашей бизнес-логике, хранении данных, обмене данными, вызовах API и т.д. Отрегулируйте в часовом поясе только тогда, когда это ожидается пользователем или требуется для приемника данных.