Как справиться с разницей в часовых поясах между сервером и собственным приложением для Android?

Предположим, что мой сервер находится в США, а я живу в России. Мы знаем, что у них разные часовые пояса.

Мое приложение получает текст (String) с сервера. И эти текстовые данные имеют столбец Date в базе данных для хранения даты записи.

Когда я получаю данные, я также получаю date знаний. Так что я могу сгруппировать их по времени. Первые вверху, последние внизу. Что бы ни...

Я написал функцию, чтобы показать значение даты, более удобочитаемое, например, «13 часов», «9 минут». Сервер отправляет мне дату в часовом поясе сервера (США).

Когда я рассчитываю время в приложении с часовым поясом России (потому что это текущий часовой пояс в приложении), оно вычисляется неправильно. Так что это не то, что кому-то нужно.

Что нужно сделать, чтобы добиться правильного расчета?

Аннотация: Это приложение будет использоваться гражданами разных стран. Поэтому я не могу сделать расчет статическим.


person JustWork    schedule 11.08.2013    source источник


Ответы (5)


На самом деле не существует таких вещей, как «часовой пояс России» или «часовой пояс США». Обе эти страны имеют несколько разных часовых поясов. См. статьи Википедии о Время в России и Время в США.

Вы всегда должны писать серверный код таким образом, чтобы он не зависел от часового пояса, в котором работает сервер. Обычно это делается путем сохранения всего времени как UTC. Поскольку клиент является устройством Android, просто преобразуйте его в локальное время и из него на клиенте, отправляя только UTC на/с сервера.

Если вы работаете с Java, вам, вероятно, следует использовать для конверсий Joda Time. Он намного чище и проще в использовании, чем класс Calendar.

Обновить

Как указал Василий в комментариях, проект Joda-Time сейчас находится в режиме обслуживания. Команда рекомендует перейти на java.time классы, определенные в JSR 310. Для более ранних версий Android см. ThreeTen-Backport и ThreeTenABP. См. Как использовать….

person Matt Johnson-Pint    schedule 11.08.2013
comment
Обрабатывает ли это преобразование UTC летнее время? - person Vishnu Sureshkumar; 10.05.2016
comment
@vishnu - UTC не имеет летнего времени, но при преобразовании в местное время будет учитываться летнее время (при условии, что вы правильно используете API и не пытаетесь настроить летнее время вручную). ). - person Matt Johnson-Pint; 10.05.2016
comment
Домашняя страница Joda-Time перемещена. Обновил ссылку. - person naXa; 15.12.2017
comment
Проект Joda-Time находится в режиме обслуживания. Команда рекомендует перейти на классы java.time, определенные JSR 310. Для более ранних версий Android см. ThreeTen-Backport и ThreeTenABP. См. Как использовать…. - person Basil Bourque; 15.12.2017

Класс Calendar может преобразовывать время между часовыми поясами, если вы знаете, какой часовой пояс используют сервер и клиент. Чтобы избежать проблем в будущем, если вы когда-нибудь переместите сервер, лучше всего определить, какое время должно быть в базе данных. Я предпочитаю использовать UTC для этого в качестве стандарта, но вы можете использовать любой часовой пояс по своему желанию, если он определен и указан в вашей документации, чтобы вы знали об этом в будущем.

Вот вопрос, который показывает, как это сделать: Дата и преобразование времени в другой часовой пояс в java

person Gabe Sechan    schedule 11.08.2013
comment
Проблемный класс Calendar теперь унаследован, вытеснив несколько лет назад классы java.time. - person Basil Bourque; 15.12.2017
comment
@BasilBourque Java.time — это Android 8, который был добавлен в Android около месяца назад и поддерживается только в v26+. Это не будет безопасно для общего использования на Android в течение как минимум 3, а, скорее всего, 5 лет, в зависимости от того, какую часть рынка вы готовы отказаться от поддержки. - person Gabe Sechan; 15.12.2017
comment
Для более ранних версий Android см. ThreeTen-Backport и ThreeTenABP. См. Как использовать…. - person Basil Bourque; 15.12.2017
comment
@BasilBourque Нет, спасибо. Мне не нужно добавлять в проект больше случайных библиотек, чтобы получить незначительную функциональность, когда есть существующие решения. Я не добавляю угрозы безопасности. - person Gabe Sechan; 15.12.2017

tl;dr

Часовой пояс не имеет значения для прошедших часов-минут-секунд.

Duration.between(
    Instant.parse( "2017-12-14T01:34:56.123456789Z" ) ;
    Instant.now() 
)

Java.время

В современном подходе используются лучшие в отрасли классы java.time. Они заменяют проблемные старые устаревшие классы даты и времени, такие как Date и Calendar.

Серверы обычно должны быть настроены на часовой пояс UTC. И вы никогда не должны зависеть от каких-либо таких настроек. Вместо этого ваш код должен указывать желаемый/ожидаемый часовой пояс.

Ваша бизнес-логика, хранение данных и обмен данными, как правило, должны быть в формате UTC. При сериализации в текст используйте только стандартные форматы ISO 8601.

При необходимости применяйте другие часовые пояса, как того ожидает пользователь в пользовательском интерфейсе. Поэтому, как правило, вы должны думать о часовых поясах, отличных от UTC, как о проблеме локализации.

Instant

Класс Instant представляет момент, точку на временной шкале в формате UTC с разрешением в наносекунды. На получение текущего момента не влияют настройки часового пояса.

Instant instant = Instant.now() ;

Сериализация в текст в стандартном формате с помощью вызова toString.

String output = instant.toString() ;

Вы можете обменять Instant с вашей базой данных.

myPreparedStatement.setObject( … , instant ) ;

…и…

Instant instant = myPreparedStatement.getObject( … , Instant.class ) ;

ZonedDateTime

Примените ZoneId, чтобы получить ZonedDateTime.

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

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

Duration

Чтобы получить количество прошедших часов, минут, секунд, используйте класс Duration. Обратите внимание, что вам не нужны часовые пояса для прошедшего времени; UTC (Instant) дает тот же результат.

Duration d = Duration.between( then , Instant.now() ) ;

Для более ранних версий Android см. ThreeTen-Backport и ThreeTenABP. См. Как использовать….


О java.time

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

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

Чтобы узнать больше, см. учебник по Oracle. И поищите множество примеров и пояснений в Stack Overflow. Спецификация: JSR 310.

Где получить классы java.time?

person Basil Bourque    schedule 15.12.2017

я не знаю, как этого можно добиться программным способом, но я знаю, что это можно сделать :) ... может быть, вам следует попробовать стратегию, при которой вы сохраняете все свои записи в соответствии со временем по Гринвичу, а затем на стороне клиента создаете формулу где он проверяет часовой пояс клиента, тогда, если это был отрицательный часовой пояс, замените эту сумму из текущей записи времени, а если это был положительный часовой пояс, добавьте эту сумму в запись времени, таким образом, она будет отображаться для клиента в соответствии с там часовой пояс ..... (извините за мою грамматику :) хотелось бы)

person Tarek Kanon    schedule 11.08.2013

Если вы работали на Java до Java 8, вам, вероятно, следует использовать Joda Time для своих преобразований. Взгляните на этот вопрос: преобразование даты и времени в другой часовой пояс в java

Если вы работаете с Java 8 и новее (или планируете начать процесс обновления в своей компании), Java 8 включает в себя правильную библиотеку даты/времени, и создатели Joda рекомендуют перейти на ее использование. Взгляните на этот вопрос: Joda Time - преобразование UTC DateTime в Date - использование версии 1.2.1.1 Joda

person naXa    schedule 15.12.2017
comment
Проект Joda-Time годами находился в режиме обслуживания. . Команда рекомендует перейти на классы java.time, определенные JSR 310. Для более ранних версий Android см. ThreeTen-Backport и ThreeTenABP. См. Как использовать…. - person Basil Bourque; 15.12.2017