JodaTime - как получить текущее время в UTC
Я хочу узнать текущее время в UTC. Пока что я делаю следующее (только для целей тестирования):
DateTime dt = new DateTime();
DateTimeZone tz = DateTimeZone.getDefault();
LocalDateTime nowLocal = new LocalDateTime();
DateTime nowUTC = nowLocal.toDateTime(DateTimeZone.UTC);
Date d1 = nowLocal.toDate();
Date d2 = nowUTC.toDate();
L.d("tz: " + tz.toString());
L.d("local: " + d1.toString());
L.d("utc: " + d2.toString());
-
d1
мое местное время, это хорошо -
d2
- мое местное время + 1, но должно быть местное время - 1...
Мой локальный часовой пояс UTC + 1 (согласно выводу отладки и списку здесь: https://www.joda.org/joda-time/timezones.html)...
Как правильно конвертировать из одного часового пояса в другой (включая представление в миллисекундах)?
РЕДАКТИРОВАТЬ
Мне нужна дата/миллисекунды... Это НЕ о правильном отображении времени....
РЕДАКТИРОВАТЬ 2
Теперь с помощью комментария и ответа я попытался сделать следующее:
DateTimeZone tz = DateTimeZone.getDefault();
DateTime nowLocal = new DateTime();
LocalDateTime nowUTC = nowLocal.withZone(DateTimeZone.UTC).toLocalDateTime();
DateTime nowUTC2 = nowLocal.withZone(DateTimeZone.UTC);
Date dLocal = nowLocal.toDate();
Date dUTC = nowUTC.toDate();
Date dUTC2 = nowUTC2.toDate();
L.d(Temp.class, "------------------------");
L.d(Temp.class, "tz : " + tz.toString());
L.d(Temp.class, "local : " + nowLocal + " | " + dLocal.toString());
L.d(Temp.class, "utc : " + nowUTC + " | " + dUTC.toString()); // <= WORKING SOLUTION
L.d(Temp.class, "utc2 : " + nowUTC2 + " | " + dUTC2.toString());
ВЫХОД
tz : Europe/Belgrade
local : 2015-01-02T15:31:38.241+01:00 | Fri Jan 02 15:31:38 MEZ 2015
utc : 2015-01-02T14:31:38.241 | Fri Jan 02 14:31:38 MEZ 2015
utc2 : 2015-01-02T14:31:38.241Z | Fri Jan 02 15:31:38 MEZ 2015
Я хотел, чтобы местная дата отображала 15 часов, а дата отображала 14 часов... На данный момент, похоже, это работает...
----- EDIT3 - Окончательное решение -----
Надеюсь, это хорошее решение... Я думаю, я уважаю все чаевые, которые я получил...
DateTimeZone tz = DateTimeZone.getDefault();
DateTime nowUTC = new DateTime(DateTimeZone.UTC);
DateTime nowLocal = nowUTC.withZone(tz);
// This will generate DIFFERENT Dates!!! As I want it!
Date dLocal = nowLocal.toLocalDateTime().toDate();
Date dUTC = nowUTC.toLocalDateTime().toDate();
L.d("tz : " + tz.toString());
L.d("local : " + nowLocal + " | " + dLocal.toString());
L.d("utc : " + nowUTC + " | " + dUTC.toString());
Выход:
tz : Europe/Belgrade
local : 2015-01-03T21:15:35.170+01:00 | Sat Jan 03 21:15:35 MEZ 2015
utc : 2015-01-03T20:15:35.170Z | Sat Jan 03 20:15:35 MEZ 2015
Ответы
Ответ 1
Вы делаете это намного сложнее, чем вам нужно:
DateTime dt = new DateTime(DateTimeZone.UTC);
Никакого преобразования не требуется. Если вы обнаружите, что вам действительно нужно преобразовать, вы можете использовать withZone
. Я бы посоветовал вам избегать перехода через LocalDateTime
, тем не менее, так вы можете потерять информацию из-за переходов часовых поясов (два разных момента могут иметь одно и то же местное время в одном и том же часовом поясе, потому что часы возвращаются и повторяются по местному времени.
Сказав все это, ради проверки, мне лично нравится использовать интерфейс Clock
, который позволяет мне получить текущее время (например, как Instant
). Затем вы можете использовать инъекцию зависимостей для ввода реальных системных часов при запуске в производство и поддельные часы с заданным временем тестов. В пакет Java 8 java.time
встроена эта идея, btw.
Ответ 2
Вы также можете использовать статический метод сейчас, что делает его еще более читабельным
DateTime.now(DateTimeZone.UTC)
Ответ 3
Используйте этот
DateTime.now().withZone(DateTimeZone.UTC)
и если вы хотите форматировать, вы можете использовать
DateTime.now().withZone(DateTimeZone.UTC).toString("yyyyMMddHHmmss")
Ответ 4
Отсюда: http://www.joda.org/joda-time/userguide.html#Changing_TimeZone
// get current moment in default time zone
DateTime dt = new DateTime();
// translate to London local time
DateTime dtLondon = dt.withZone(DateTimeZone.forID("Europe/London"));
Результирующее значение dtLondon имеет такое же абсолютное миллисекундровое время, но другой набор значений поля.
Вы можете заменить "Европа/Лондон" на часовой пояс, который вы хотите (UTC). См. этот список правильных имен часовых поясов.
Ответ 5
Попробуйте послушать Jon Skeets, хороший совет и комментарии. Вот дополнительное объяснение. В вашем edit-2 есть ошибка:
DateTimeZone tz = DateTimeZone.getDefault();
DateTime nowLocal = new DateTime();
LocalDateTime nowUTC = nowLocal.withZone(DateTimeZone.UTC).toLocalDateTime();
DateTime nowUTC2 = nowLocal.withZone(DateTimeZone.UTC);
Date dLocal = nowLocal.toDate();
Date dUTC = nowUTC.toDate();
Date dUTC2 = nowUTC2.toDate();
Если вы вызываете toDate()
для объекта nowUTC
типа LocalDateTime
, то вы можете получить сюрпризы - см. javadoc. Joda-Time утверждает, что использует the same fields
в java.util.Date
, как в nowUTC
. Что это значит? Пусть проанализируют:
nowUTC.toString()
создает 2015-01-02T14:31:38.241
Это без часовой пояс (обратите внимание на отсутствующий Z в конце), так что это просто обычная локальная метка времени. В контексте мы знаем, что он был создан в UTC. Однако на следующем шаге вы преобразуете его в java.util.Date
, используя вышеупомянутый метод выше. Этот метод объединяет местную временную метку с системным часовым поясом (Белград) СОХРАНЕНИЕ ПОЛЕЙ, следовательно, ИЗМЕНЕНИЕ момента. Итак, вы, наконец, произвели ошибку. И ваша вторая строка неверна.
Если вы просто хотите
Показания даты utc 14 часов
то не используйте сомнительный и вводящий в заблуждение метод конвертации, предлагаемый Joda-Time. Вместо этого используйте специальный форматировщик с рисунком "EEE MMM dd HH: mm: ss zzz yyyy" или аналогичным (Joda-Time предлагает DateTimeFormatter
). Установите UTC-offset на этот форматтер и распечатайте. Готово. Отбросить полностью любой вызов java.util.Date.toString()
. Таким образом, вам даже не нужно делать какое-либо опасное преобразование вообще.
Ответ 6
SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
// or SimpleDateFormat sdf = new SimpleDateFormat( "MM/dd/yyyy KK:mm:ss a Z" );
sdf.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
System.out.println( sdf.format( new Date() )
);
Вместо System.out.println(sdf.format(new Date()) введите локальную дату
Ответ 7
Я установил это с помощью этого конвертера
public class DateTimeConverter implements AttributeConverter<DateTime, Date> {
@Override
public Date convertToDatabaseColumn(DateTime attribute) {
return attribute == null ? null
: new Date(attribute
.withZone(DateTimeZone.UTC)
.withZoneRetainFields(DateTimeZone.getDefault())
.getMillis());
}
@Override
public DateTime convertToEntityAttribute(Date dbData) {
return dbData == null ? null
: new DateTime(dbData.getTime())
.withZoneRetainFields(DateTimeZone.UTC)
.withZone(DateTimeZone.getDefault());
}
}
Даты сохраняются как UTC и восстанавливаются с помощью текущего часового пояса