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 и восстанавливаются с помощью текущего часового пояса