Вопрос по timezone, calendar, date, java – Как справиться с переходом на летнее время с помощью TimeZone в Java

54

Я должен напечатать время EST в моем приложении Java. Я установил часовой пояс на EST, используя:

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("EST"));

Но когда в этом часовом поясе соблюдается переход на летнее время, мой код не печатает правильное время (он печатает на 1 час меньше).

Как заставить код работать так, чтобы он всегда читал правильное время, независимо от того, наблюдается летнее время или нет?

PS: я пытался установить часовой пояс EDT, но это не решает проблему.

"когда в EST соблюдается переход на летнее время"; - Вы имеете в виду «когда летнее время идет по восточному времени». Восточное времяstandard время - гдеstandard противоположностьdaylight. Jon Skeet
С этим я ничего не делаю, кроме того, что я печатаю дату. Но когда я вижу час на выходе, он показывает неправильное значение (на 1 час меньше), когда в EST отслеживается переход на летнее время. Как заботиться о переходе на летнее время - мой вопрос Surya Chandra
Пожалуйста, отредактируйте ваш вопрос с этой информацией. Это может быть упущено в комментариях, но, вероятно, не в вашем вопросе. Также, пожалуйста, отредактируйте и уточните это утверждениеPS: I tried setting the timezone to EDT, but it solve the problem David
Переход на летнее время увеличивает время на час в начале периода перехода на летнее время и в конце сокращает время на ту же величину. Поведение, которое вы видите, на мой взгляд, совершенно нормально. Пожалуйста, пройдитеen.wikipedia.org/wiki/Daylight_saving_time Everyone
Не могли бы вы расширить свой пример кода, показывая именно то, что вы пытаетесь сделать? sebastian

Ваш Ответ

8   ответов
-3

ботится о переходе на летнее время.

java.util.TimeZone представляет смещение часового пояса, а также вычисляет летнее время.

образец кода:

TimeZone est_timeZone = TimeZoneIDProvider.getTimeZoneID(TimeZoneID.US_EASTERN).getTimeZone();
Calendar enteredCalendar = Calendar.getInstance();
enteredCalendar.setTimeZone(est_timeZone);
являетсяTimeZoneIDProvider пользовательский класс? в этом случае вам необходимо обеспечить его реализацию.
0

public static float calculateTimeZone(String deviceTimeZone) {
    float ONE_HOUR_MILLIS = 60 * 60 * 1000;

    // Current timezone and date
    TimeZone timeZone = TimeZone.getTimeZone(deviceTimeZone);
    Date nowDate = new Date();
    float offsetFromUtc = timeZone.getOffset(nowDate.getTime()) / ONE_HOUR_MILLIS;

    // Daylight Saving time
    if (timeZone.useDaylightTime()) {
        // DST is used
        // I'm saving this is preferences for later use

        // save the offset value to use it later
        float dstOffset = timeZone.getDSTSavings() / ONE_HOUR_MILLIS;
        // DstOffsetValue = dstOffset
        // I'm saving this is preferences for later use
        // save that now we are in DST mode
        if (timeZone.inDaylightTime(nowDate)) {
            Log.e(Utility.class.getName(), "in Daylight Time");
            return -(ONE_HOUR_MILLIS * dstOffset);
        } else {
            Log.e(Utility.class.getName(), "not in Daylight Time");
            return 0;
        }
    } else
        return 0;
}
К вашему сведению, эти ужасно неприятные старые классы были вытеснены годами назад современнымиjava.time классы.
14

тот, который Джон Скит, но устарела.

java.time

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

Если вы просто хотите узнать текущее время в UTC, используйтеInstant учебный класс.

Instant now = Instant.now();

EST это не часовой пояс, как объяснено вправильный ответ Джон Скит, Такие 3-4-буквенные коды не являются ни стандартизированными, ни уникальными, и это еще больше сбивает с толку переход на летнее время (DST). Используйте правильное имя часового пояса в & quot; континент / регион & quot; формат.

Возможно, вы имели в виду восточное стандартное время на восточном побережье Северной Америки? Или стандартное время Египта? Или европейское стандартное время?

ZoneId zoneId = ZoneId.of( "America/New_York" );
ZoneId zoneId = ZoneId.of( "Africa/Cairo" );
ZoneId zoneId = ZoneId.of( "Europe/Lisbon" );

Используйте любой такойZoneId объект, чтобы получить текущий момент, настроенный на определенный часовой пояс, чтобы произвестиZonedDateTime объект.

ZonedDateTime zdt = ZonedDateTime.now( zoneId ) ;

Настройте этот ZonedDateTime в другой часовой пояс, создав первый объект ZonedDateTime из первого. Фреймворк java.time используетнеизменяемые предметы вместо того, чтобы изменять (мутировать) существующие объекты.

ZonedDateTime zdtGuam = zdt.withZoneSameInstant( ZoneId.of( "Pacific/Guam" ) ) ;
К счастью, преобразование легко -Instant.now().atZone(ZoneOffset.UTC)
Добавление секунды действительно останавливает часы с точки зрения даты и времени суток. Мы берем дополнительный момент, прежде чем перейти к следующей дате в календаре. И поэтому наш календарь поглощает високосную секунду. Как я уже сказал, в этом и заключается смысл високосных секунд: замедляйте наши часы, чтобы замедлить отслеживание календаря. Хотя ваша точка зрения об игнорировании високосных секунд технически правильна с точки зрения внутреннего представления классов java.time, с практической точки зрения ваша точка зрения не имеет значения, педантична и излишне запутывает многих программистов, пытающихся научиться представлять даты и время.
Instant это не то же самое, что время в UTC. Например, последний может иметь дополнительные секунды.
Нет Временная секунда UTC не «останавливает часы», она добавляет еще одну секунду (2016-12-24T23: 23: 60Z является самой последней). Время Java представленоInstant часы также не останавливаются - в этот день у них одинаковое количество миллисекунд, но все они были немного длиннее. Даже если вы не хотите думать об этом таким образом, это все равно так, как это было реализовано, вот почему, например. Вы не можете отформатироватьInstant с помощьюISO_DATE_TIME.
@OrangeDog КогдаInstant воспринимается как дата и время суток, тогда високосные секунды становятся неактуальными. В этом весь смысл високосных секунд, чтобы на мгновение остановить наши часы, чтобы позволить нашему календарю синхронизироваться с обычно замедляющим астрономическим положением Земли. Хотя это верно внутреннее представлениеInstant Короче количество високосных секунд, которые были объявлены до сих пор (по одной каждые пару лет или около того), это различие не имеет значения при обсуждении даты и времени суток. Эти подробности обсуждаются в классе для тех, кто заботится. Апшот: практически говоря,Instant это UTC.
-2

чтобы избежать перехода на летнее время (DST), вам нужно сделать трюк вручную,
сначала вы должны получить смещение DST, т. е. сколько миллисекунд применяется DST, например, где-то DST также составляет 45 минут, а в некоторых местах - 30 минут.
но в большинстве случаев летнее время составляет 1 час
Вы должны использовать объект Timezone и проверить с датой, подпадает ли он под DST или нет, а затем вы должны вручную добавить смещение DST в него. например:

 TimeZone tz = TimeZone.getTimeZone("EST");
 boolean isDST = tz.inDaylightTime(yourDateObj);
 if(isDST){
 int sec= tz.getDSTSavings()/1000;// for no. of seconds
 Calendar cal= Calendar.getInstance();
 cal.setTime(yourDateObj);
 cal.add(Calendar.Seconds,sec);
 System.out.println(cal.getTime());// your Date with DST neglected
  }
104

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("EST"));

Следует полностью избегать трехбуквенных сокращений в пользу идентификаторов зон TZDB. Восточное времяStandard Время иStandard время никогда не соблюдает летнее время; на самом деле это не полное название часового пояса. Это имя используется дляpart часового пояса. (К сожалению, я не нашел подходящего термина для этой концепции «половины часового пояса».)

Вы хотитеfull Название часового пояса. Например,America/New_York находится в восточном часовом поясе:

TimeZone zone = TimeZone.getTimeZone("America/New_York");
DateFormat format = DateFormat.getDateTimeInstance();
format.setTimeZone(zone);

System.out.println(format.format(new Date()));
Извините за путаницу @Jon, я просто сделал то, что вы предложили:SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss:ms MM/dd/yyyy"); System.out.println(format.format(new Date())); ... заменяя последнюю строку кода из ответа, чтобы получить желаемый результат. Спасибо вам за помощь.
@ maximus: я не уверен, что ты имеешь в виду. Результатnew Date() не зависит от системного часового пояса. Если вы имеете в виду, что вы используетеSimpleDateFormat с системным часовым поясом, то да, звонитsdf.format(new Date()); а потом сразуsdf.format(new Date()); несколько миллисекунд спустя могут привести к строковым представлениям, которые выглядят с интервалом в один час.
Спасибо Джон Скит. Это работает отлично. Surya Chandra
@IanCampbell: не совсем понятно, что вы ожидаете от этого - это статический метод, поэтому вы обычно просто используетеDateFormat format = DateFormat.getDateTimeInstance(), Это статический метод, поэтому он не имеет ничего общего с существующим экземпляром. Действительно непонятно, что вы пытаетесь сделать, но вам, вероятно, следует задать новый вопрос.
Спасибо @Jon, можно ли затем изменить формат с чем-то вродеDateFormat format = new SimpleDateFormat("HH:mm:ss:ms MM/dd/yyyy").getDateTimeInstance()? Мой пример генерирует предупреждение & quot;The static method getDateTimeInstance() from the type DateFormat should be accessed in a static way& Quot ;.
2

естве таких. Как вы заметили, просто "EDT" не работает. Это будет учитывать проблему перехода на летнее время. Строка кода выглядит следующим образом:

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("EST5EDT"));
0

ответ:

TimeZone tz = TimeZone.getTimeZone("EST");
boolean inDs = tz.inDaylightTime(new Date());
0

private static Long DateTimeNowTicks(){
    long TICKS_AT_EPOCH = 621355968000000000L;
    TimeZone timeZone = Calendar.getInstance().getTimeZone();
    int offs = timeZone.getRawOffset();
    if (timeZone.inDaylightTime(new Date()))
        offs += 60 * 60 * 1000;
    return (System.currentTimeMillis() + offs) * 10000 + TICKS_AT_EPOCH;
}
Для Java 6 & amp; Java 7, большая частьjava.time функциональность портирована с почти идентичным API вThreeTen-Backport проект. Так что на самом деле нет необходимости когда-либо использовать ужасные устаревшие классы даты и времени, такие какDate, Calendar, SimpleDateFormat.
Иногда разработчик вынужден попадать в ужасную старую унаследованную ситуацию без бэкпорта, и поэтому у него нет выбора, кроме как использовать ужасные унаследованные классы даты и времени, но приятно знать, спасибо!
Иногда разработчик попадает в ужасную старую унаследованную ситуацию, но приятно знать, спасибо.
Эти ужасные старые классы даты и времени были вытеснены годы назадjava.time классы с принятием JSR 310. Эти устаревшие классы больше не должны использоваться вообще.

Похожие вопросы