Получить значение смещения TimeZone из TimeZone без имени TimeZone

Мне нужно сохранить часовой пояс телефона в формате [+/-] чч: мм

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

PST -05:00
GMT +02:00

Я бы предпочел не подставлять результат, есть ли какой-либо ключ или флаг опции, который я могу установить, чтобы получить только значение, а не имя этого часового пояса (GMT/CET/PST...)?

8 ответов

Решение

Мне нужно сохранить часовой пояс телефона в формате [+/-] чч: мм

Нет, ты не Смещения само по себе недостаточно, вам нужно хранить полное имя / идентификатор часового пояса. Например, я живу в Осло, где мое текущее смещение составляет +02:00, но зимой (из-за dst) это +01:00. Точное переключение между стандартным и летним временем зависит от факторов, которые вы не хотите исследовать.

Так что вместо хранения + 02:00 (или это должно быть + 01:00?) Я храню "Europe/Oslo" в моей базе данных. Теперь я могу восстановить полную конфигурацию, используя:

TimeZone tz = TimeZone.getTimeZone("Europe/Oslo")

Хотите знать, какое у меня смещение часового пояса сегодня?

tz.getOffset(new Date().getTime()) / 1000 / 60   //yields +120 minutes

Однако то же самое в декабре:

Calendar christmas = new GregorianCalendar(2012, DECEMBER, 25);
tz.getOffset(christmas.getTimeInMillis()) / 1000 / 60   //yields +60 minutes

Достаточно сказать: сохраняйте имя или идентификатор часового пояса, и каждый раз, когда вы хотите отобразить дату, проверяйте текущее смещение (сегодня), а не сохраняйте фиксированное значение. Ты можешь использовать TimeZone.getAvailableIDs() перечислить все поддерживаемые идентификаторы часовых поясов.

@MrBean - у меня была похожая ситуация, когда мне приходилось вызывать сторонний веб-сервис и передавать текущее смещение часового пояса устройства Android в формате +/- чч: мм. Вот мое решение:

public static String getCurrentTimezoneOffset() {

    TimeZone tz = TimeZone.getDefault();  
    Calendar cal = GregorianCalendar.getInstance(tz);
    int offsetInMillis = tz.getOffset(cal.getTimeInMillis());

    String offset = String.format("%02d:%02d", Math.abs(offsetInMillis / 3600000), Math.abs((offsetInMillis / 60000) % 60));
    offset = (offsetInMillis >= 0 ? "+" : "-") + offset;

    return offset;
} 

С java8 теперь вы можете использовать

Integer offset  = ZonedDateTime.now().getOffset().getTotalSeconds();

получить текущее смещение системного времени от UTC. Затем вы можете преобразовать его в любой формат, который вы хотите. Нашел это полезным для моего случая. Пример: https://docs.oracle.com/javase/tutorial/datetime/iso/timezones.html

В Java 8 этого можно добиться, выполнив следующий код.

    TimeZone tz = TimeZone.getDefault();
    String offsetId = tz.toZoneId().getRules().getStandardOffset(Instant.now()).getId();

и offsetId будет что-то вроде +01:00

Обратите внимание на функцию getStandardOffset нужен Instantкак параметр. Это конкретный момент времени, в который вы хотите проверить смещение данного часового пояса, поскольку смещение часового пояса может меняться во времени. По причине того, что в некоторых районах действует летнее время.

Я думаю, что это причина, по которой @Tomasz Nurkiewicz рекомендует не сохранять смещение напрямую в формате часов со знаком, а проверять смещение каждый раз, когда оно вам нужно.

ZoneId here = ZoneId.of("Europe/Kiev");
ZonedDateTime hereAndNow = Instant.now().atZone(here);
String.format("%tz", hereAndNow);

даст вам стандартизированное строковое представление, как "+0300"

java.time: современный API даты и времени

Вы можете получить смещение часового пояса, используя ZonedDateTime#getOffset.

Обратите внимание, что смещение часового пояса, в котором наблюдаются изменения DST, согласно изменениям DST. Для других мест (например, в Индии) он остается неизменным. Поэтому рекомендуется указать момент, когда отображается смещение часового пояса. Момент упоминается как Instant.now() и представляет дату и время в формате UTC (представленный Z что означает Zulu и указывает смещение часового пояса +00:00 часы).

Отображение смещения всех часовых поясов, возвращаемых ZoneId.getAvailableZoneIds():

      import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Main {
    public static void main(String[] args) {
        // Test
        Instant instant = Instant.now();
        System.out.println("Timezone offset at " + instant);
        System.out.println("==============================================");
        ZoneId.getAvailableZoneIds()
            .stream()
            .sorted()
            .forEach(strZoneId -> System.out.printf("%-35s: %-6s%n",
                strZoneId, getTzOffsetString(ZoneId.of(strZoneId), instant)));
    }

    static String getTzOffsetString(ZoneId zoneId, Instant instant) {
        return ZonedDateTime.ofInstant(instant, zoneId).getOffset().toString();
    }
}

Выход:

      Timezone offset at 2021-05-05T21:45:34.150901Z
==============================================
Africa/Abidjan                     : Z     
Africa/Accra                       : Z     
Africa/Addis_Ababa                 : +03:00
...
...
...    
W-SU                               : +03:00
WET                                : +01:00
Zulu                               : Z  

Узнайте больше о современном API даты и времени* из Trail: Date Time .


* По любой причине, если вам нужно придерживаться Java 6 или Java 7, вы можете использовать ThreeTen-Backport, который поддерживает большую часть функциональности java.time для Java 6 и 7. Если вы работаете над проектом Android и своим Android API уровень по-прежнему не соответствует Java-8, проверьте API-интерфейсы Java 8+, доступные через десугаринг, и Как использовать ThreeTenABP в Android Project .

Мы можем легко получить миллисекундное смещение TimeZone только с TimeZone экземпляр и System.currentTimeMillis(), Затем мы можем конвертировать из миллисекунд в любую единицу времени, используя TimeUnit учебный класс.

Вот так:

public static int getOffsetHours(TimeZone timeZone) {
    return (int) TimeUnit.MILLISECONDS.toHours(timeZone.getOffset(System.currentTimeMillis()));
}

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

У меня есть объект Building, который включает в себя часовой пояс, используя класс TimeZone, и хотел создать поля zoneId и смещения в новом классе.

Так что я сделал создать:

private String timeZoneId;
private String timeZoneOffset;

Затем в конструкторе я передал объект Building и установил эти поля следующим образом:

this.timeZoneId = building.getTimeZone().getID();
this.timeZoneOffset = building.getTimeZone().toZoneId().getId();

Поэтому timeZoneId может равняться чему-то вроде "EST", а timeZoneOffset может равняться что-то вроде "-05:00"

Я бы не хотел, чтобы вы не

Другие вопросы по тегам