Вопрос-ответ

Convert Date/Time for given Timezone - java

Преобразовать дату / время для заданного часового пояса - java

Я хочу преобразовать эту отметку времени GMT в GMT + 13:

2011-10-06 03:35:05

Я перепробовал около 100 различных комбинаций DateFormat, TimeZone, Date, GregorianCalendar и т.д. чтобы попытаться выполнить эту ОЧЕНЬ простую задачу.

Этот код делает то, что я хочу для ТЕКУЩЕГО ВРЕМЕНИ:

Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("GMT"));

DateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");
formatter.setTimeZone(TimeZone.getTimeZone("GMT+13"));

String newZealandTime = formatter.format(calendar.getTime());

Но я хочу установить время, а не использовать текущее время.

Я обнаружил, что каждый раз, когда я пытаюсь установить время следующим образом:

calendar.setTime(new Date(1317816735000L));

используется часовой пояс локального компьютера. Почему это? Я знаю, что когда "new Date ()" возвращает время UTC + 0, так почему же, когда вы устанавливаете время в миллисекундах, оно больше не предполагает, что время указано в UTC?

Возможно ли:


  1. Установка времени для объекта (календарь / Дата / Временная метка)

  2. (Возможно) Установить часовой пояс начальной временной метки (calendar.setTimeZone(...))

  3. Отформатируйте отметку времени с помощью нового часового пояса (formatter.setTimeZone(...)))

  4. Возвращает строку с указанием времени в новом часовом поясе. (formatter.format(calendar.getTime()))

Переведено автоматически
Ответ 1

Для меня самый простой способ сделать это:

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

//Here you say to java the initial timezone. This is the secret
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
//Will print in UTC
System.out.println(sdf.format(calendar.getTime()));

//Here you set to your timezone
sdf.setTimeZone(TimeZone.getDefault());
//Will print on your default Timezone
System.out.println(sdf.format(calendar.getTime()));
Ответ 2

Понимание того, как работает компьютерное время, очень важно. С учетом сказанного я согласен, что если API создан, чтобы помочь вам обрабатывать компьютерное время как реальное, то оно должно работать таким образом, чтобы вы могли обрабатывать его как реальное. По большей части это так, но есть некоторые серьезные упущения, на которые действительно нужно обратить внимание.

В любом случае, я отвлекся!! Если у вас есть смещение UTC (лучше работать со смещением UTC, чем GMT), вы можете рассчитать время в миллисекундах и добавить это к вашей временной метке. Обратите внимание, что временная метка SQL может отличаться от временной метки Java, поскольку способ вычисления истечения из эпохи не всегда одинаков - зависит от технологий баз данных, а также операционных систем.

I would advise you to use System.currentTimeMillis() as your time stamps as these can be processed more consistently in java without worrying about converting SQL Timestamps to java Date objects etc.

To calculate your offset you can try something like this:

Long gmtTime =1317951113613L; // 2.32pm NZDT
Long timezoneAlteredTime = 0L;

if (offset != 0L) {
int multiplier = (offset*60)*(60*1000);
timezoneAlteredTime = gmtTime + multiplier;
} else {
timezoneAlteredTime = gmtTime;
}

Calendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(timezoneAlteredTime);

DateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");

formatter.setCalendar(calendar);
formatter.setTimeZone(TimeZone.getTimeZone(timeZone));

String newZealandTime = formatter.format(calendar.getTime());

I hope this is helpful!

Ответ 3

tl; dr

Instant.ofEpochMilli( 1_317_816_735_000L )
.atZone( ZoneId.of( "Pacific/Auckland" ) )
.format( DateTimeFormatter.ofLocalizedDateTime( FormatStyle.MEDIUM ).withLocale( new Locale( "en" , "NZ" ) ) )

... также…

LocalDateTime.parse( "2011-10-06 03:35:05".replace( " " , "T" ) )
.atZone( ZoneId.of( "Pacific/Auckland" ) )

java.time

В вопросе и большинстве ответов используются устаревшие устаревшие классы даты и времени из самых ранних версий Java. Эти старые классы оказались хлопотными и сбивающими с толку. Избегайте их. Вместо этого используйте классы java.time .

ISO 8601

Ваша входная строка почти соответствует стандартному формату ISO 8601. Просто замените ПРОБЕЛ посередине на T.

String input = "2011-10-06 03:35:05".replace( " " , "T" );

LocalDateTime

Теперь выполняется синтаксический анализ как LocalDateTime поскольку во входных данных отсутствует какая-либо информация о смещении от UTC или часового пояса. В A LocalDateTime нет понятия смещения или часового пояса, поэтому оно не отражает фактический момент на временной шкале.

LocalDateTime ldt = LocalDateTime.parse( input );

ZoneOffset

Вы, кажется, говорите, что из бизнес-контекста вы знаете, что назначение этой строки - представлять момент, который на 13 часов опережает UTC. Итак, мы создаем экземпляр ZoneOffset.

ZoneOffset offset = ZoneOffset.ofHours( 13 ); // 13 hours ahead of UTC, in the far east of the globe.

OffsetDateTime

Примените это для получения OffsetDateTime объекта. Это становится актуальным моментом на временной шкале.

OffsetDateTime odt = ldt.atOffset( offset);

ZoneId

Но затем вы упомянули Новую Зеландию. Значит, вы имели в виду конкретный часовой пояс. Часовой пояс - это смещение от UTC плюс набор правил для обработки аномалий, таких как переход на летнее время (DST). Таким образом, мы можем указать ZoneId в ZonedDateTime, а не просто смещение.

Укажите правильное название часового пояса. Никогда не используйте 3-4-буквенные сокращения, такие как EST или IST, поскольку они не являются настоящими часовыми поясами, не стандартизированы и даже не уникальны (!). Например, Pacific/Auckland.

ZoneId z = ZoneId.of( "Pacific/Auckland" );

ZonedDateTime

Примените ZoneId.

ZonedDateTime zdt = ldt.atZone( z );

Вы можете легко перейти в другую зону в тот же самый момент на временной шкале.

ZoneId zParis = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdtParis = zdt.withZoneSameInstant( zParis ); // Same moment in time, but seen through lens of Paris wall-clock time.

Отсчет от эпохи

Я настоятельно не рекомендую обрабатывать значения даты и времени как отсчет от эпохи, например миллисекунд от начала 1970 года по Гринвичу. Но если необходимо, создайте Instant из такого числа.

Instant instant = Instant.ofEpochMilli( 1_317_816_735_000L );

Затем при желании назначьте часовой пояс, как показано выше, для отклонения от UTC.

ZoneId z = ZoneId.of( "Pacific/Auckland" );
ZonedDateTime zdt = instant.atZone( z );

Ваше значение 1_317_816_735_000L равно:


  • 2011-10-05T12:12:15Z (Ср. 05 окт. 2011 г. 12:12:15 GMT)

  • 2011-10-06T01:12:15+13:00[Pacific/Auckland] (Четверг, 06 октября 2011 г., 01:12:15, Окленд, Новая Зеландия).

Генерация строк

Чтобы сгенерировать строку в стандартном формате ISO 8601, просто вызовите toString. Обратите внимание, что ZonedDateTime разумно расширяет стандартный формат, добавляя название часового пояса в квадратных скобках.

String output = zdt.toString();

Для других форматов выполните поиск в Stack Overflow для DateTimeFormatter class . Это уже обсуждалось много раз.

Укажите FormatStyle и a Locale.

Locale l = new Locale( "en" , "NZ" );
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.MEDIUM ).withLocale( l );
String output = zdt.format( f );

Обратите внимание, что часовой пояс не имеет ничего общего с locale. Вы можете отобразить Europe/Paris дату и время в соответствии с японским языком и культурными нормами или Asia/Kolkata дату и время в соответствии с португальским языком и культурными нормами Бразилии.

О java.time

Платформа java.time встроена в Java 8 и более поздние версии. Эти классы заменяют старые классы даты и времени, такие как java.util.Date, .Calendar, & java.text.SimpleDateFormat.

Проект Joda-Time, который сейчас находится в режиме обслуживания, рекомендует перейти на java.time.

Чтобы узнать больше, ознакомьтесь с Руководством по Oracle. А также найдите в Stack Overflow множество примеров и пояснений.

Большая часть функций java.time перенесена обратно на Java 6 и 7 в ThreeTen-Backport и дополнительно адаптирована для Android в ThreeTenABP (см. Как использовать ...).

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является испытательным полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти несколько полезных классов, таких как Interval, YearWeek, YearQuarter и другие.

Ответ 4

Как всегда, я рекомендую прочитать эту статью о дате и времени в Java, чтобы вы ее поняли.

Основная идея заключается в том, что "под капотом" все выполняется в миллисекундах UTC с момента начала эпохи. Это означает, что проще всего работать вообще без использования часовых поясов, за исключением форматирования строк для пользователя.

Поэтому я бы пропустил большинство предложенных вами шагов.


  1. Установите время для объекта (дата, календарь и т.д.).

  2. Установите часовой пояс для объекта форматирования.

  3. Возвращает строку из форматера.

В качестве альтернативы вы можете использовать Joda time. Я слышал, что это гораздо более интуитивно понятный datetime API.

2023-07-06 22:34 java