Каков наилучший способ преобразования java.util.Date
объекта в новый JDK 8 / JSR-310 java.time.LocalDate
?
Date input = new Date();
LocalDate date = ???
Короткий ответ
Date input = new Date();
LocalDate date = input.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
объяснение
Несмотря на свое название, java.util.Date
представляет собой момент времени, а не «дату». Фактические данные, хранящиеся в объекте, представляют собой long
количество миллисекунд с 1970-01-01T00: 00Z (полночь в начале 1970 года по Гринвичу / UTC).
Класс, эквивалентный классу java.util.Date
в JSR-310, является Instant
, таким образом, существует удобный метод toInstant()
для обеспечения преобразования:
Date input = new Date();
Instant instant = input.toInstant();
java.util.Date
Экземпляр не имеет понятия о времени зоны. Это может показаться странным , если вы звоните toString()
на java.util.Date
, потому что toString
это по отношению к часовому поясу. Однако этот метод на самом деле использует часовой пояс Java по умолчанию на лету для предоставления строки. Часовой пояс не является частью фактического состояния java.util.Date
.
Instant
Также не содержит никакой информации о часовом поясе. Таким образом, чтобы преобразовать Instant
дату в местную, необходимо указать часовой пояс. Это может быть зона по умолчанию ZoneId.systemDefault()
- или это может быть часовой пояс, которым управляет ваше приложение, например часовой пояс из пользовательских настроек. Используйте atZone()
метод, чтобы применить часовой пояс:
Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
ZonedDateTime
Содержит состояние , состоящее из локальной даты и времени, временной зоны и смещение от GMT / UTC. Таким образом, дата - LocalDate
может быть легко извлечена с помощью toLocalDate()
:
Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
LocalDate date = zdt.toLocalDate();
Java 9 ответ
В Java SE 9 был добавлен новый метод , который немного упрощает эту задачу:
Date input = new Date();
LocalDate date = LocalDate.ofInstant(input.toInstant(), ZoneId.systemDefault());
Эта новая альтернатива является более прямой, создает меньше мусора и, следовательно, должна работать лучше.
LocalDate.from(Instant.ofEpochMilli(date.getTime()))
думаю, что это эквивалентно вашему, но более прямолинейно.Date
не имеет понятия часового пояса, аInstant
также не содержит информацию о часовом поясе.LocalDate
API говорит «датировать без часового пояса». Тогда почему преобразование отDate
доInstant
кLocalDate
потребностямatZone(ZoneId.systemDefault())
?LocalDate
иLocalDateTime
не «хранить или представлять время или часовой пояс» (ref: javadocs). Хотя они не хранят его - классы действительно представляютLocal
дату и / или время, поэтому преобразование в локальную дату / время подразумевает часовой пояс.Лучший способ это:
Преимущества этой версии:
работает независимо от того, является ли вход экземпляром
java.util.Date
или подклассомjava.sql.Date
(в отличие от способа @ JodaStephen). Это часто встречается в данных, созданных JDBC.java.sql.Date.toInstant()
всегда выдает исключение.то же самое для JDK8 и JDK7 с бэкпортом JSR-310
Я лично использую служебный класс (но он не совместим с backport):
asLocalDate()
Здесь метод нуль-безопасна, используетtoLocalDate()
, если входjava.sql.Date
(он может быть переопределен драйвером JDBC к проблемам избежать часовых поясов или ненужных вычислений), в противном случае использует вышеупомянутый метод.источник
DateConvertUtils
.Date.toInstant()
.источник
SimpleDateFormat
экземпляр ограничен текущим потоком. Он используется потокобезопасным способом. ТеперьSimpleDateFormat
считается, что он «дорогостоящий для создания экземпляра» (из-за всех необходимых ему внутренних структур данных), но вы не можете использовать его как «синглтон» (без синхронизации доступа к нему), потому что он действительно не является потоковым безопасно. (ThreadLocal
Решение может сработать, если код, «загрязняющий»Thread
этот объект, отвечает за жизненный цикл потока ... но это случается редко). Неловко. ИзбежаниеSimpleDateFormat
является причиной использования .javax.time
SimpleDateFormat
(который отбрасывается), промежуточная строка (которая отбрасывается) и стоимость синтаксического анализа. Это решение, но не рекомендуется.Если вы используете Java 8, ответ @ JodaStephen, очевидно, самый лучший. Однако, если вы работаете с бэкпортом JSR-310 , вам, к сожалению, нужно сделать что-то вроде этого:
источник
источник
Вы можете конвертировать в одну строку:
источник
во-первых, легко конвертировать дату в мгновение
Затем вы можете преобразовать Instant в любую дату api в jdk 8, используя метод ofInstant ():
источник
import java.sql.Date
в вашем файле:toInstant()
методjava.sql.Date
всегда бросает.Date
Экземпляр действительно содержит время тоже вместе с датой покаLocalDate
не делает. Таким образом, вы можете сначала преобразовать его вLocalDateTime
метод, аofInstant()
затем, если хотите, без времени, затем преобразовать экземпляр вLocalDate
.источник
этот формат из
Date#tostring
источник
У меня были проблемы с реализацией @ JodaStephen в JBoss EAP 6. Итак, я переписал преобразование в соответствии с Java Tutorial Oracle в http://docs.oracle.com/javase/tutorial/datetime/iso/legacy.html .
источник
Что не так с этой простой строкой?
источник
Я решил этот вопрос с решением ниже
В этом случае localDate выведите вашу дату в формате «гггг-мм-дд»
источник
java.time
классов в JDK8, а не с Joda Time.