Проблема с часовым поясом в Android

#java #android #timezone

#java #Android #Часовой пояс

Вопрос:

У меня есть время в миллисекундах, и я показываю это время в своем приложении в "MM/dd/yyyy HH:mm:ss" формате, оно работает нормально.

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

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

 Locale locale = new Locale("en", "IN");

TimeZone tz = TimeZone.getDefault();
System.out.println("Default timezon id :: "   tz.getID());
tz.setID("Asia/Calcutta");
String timezon = tz.getDisplayName(false, TimeZone.SHORT, locale);
System.out.println("Timezon id :: "   tz.getID()   " Timezon name :: "   timezon);
Calendar cal = Calendar.getInstance(tz, locale);

System.out.println("TImezon :: "   tz);
// "1319084400775" is the milliseconds of 10/20/2011 05:20:00 in MM/dd/yyyy HH:mm:ss format 
Date date = new Date(Long.parseLong("1319084400775"));
System.out.println("Date :: "   date.toGMTString());
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", locale);

System.out.println("Start date :: "   format.format(date));
// "1319084400775" is the milliseconds of 10/20/2011 05:20:00 in MM/dd/yyyy HH:mm:ss format 
cal.setTimeInMillis(Long.parseLong("1319084400775"));

timezon = cal.getTimeZone().getDisplayName(false, TimeZone.SHORT, locale);
System.out.println("Calender's timezon :: "   timezon);
System.out.println("Start date :: yyyy-mm-dd hh:mm:ss "   cal.get(Calendar.YEAR)   "-"   cal.get(Calendar.MONTH)   "-"   cal.get(Calendar.DAY_OF_MONTH)   " "   cal.get(Calendar.HOUR_OF_DAY)   ":"   cal.get(Calendar.MINUTE));
// "1319084700776" is the milliseconds of 10/20/2011 05:25:00 in MM/dd/yyyy HH:mm:ss format 
cal.setTimeInMillis(Long.parseLong("1319084700776"));
System.out.println("End date :: "   cal.getTime());
  

Вывод ::

Если я установлю часовой пояс для «Тихого океана / Фиджи»;

 10-07 17:03:40.392: INFO/System.out(1193): Default timezon id :: Pacific/Fiji
10-07 17:03:40.392: INFO/System.out(1193): Timezon id :: Asia/Calcutta Timezon name :: GMT 05:30
10-07 17:03:40.406: INFO/System.out(1193): TImezon :: org.apache.harmony.luni.internal.util.ZoneInfo@7b42d3a7
10-07 17:03:40.422: INFO/System.out(1193): Date :: 20 Oct 2011 04:20:00 GMT
10-07 17:03:40.442: INFO/System.out(1193): Start date :: 2011-10-20 16:20:00
10-07 17:03:40.442: INFO/System.out(1193): Calender's timezon :: GMT 05:30
10-07 17:03:40.442: INFO/System.out(1193): Start date :: yyyy-mm-dd hh:mm:ss 2011-9-20 16:20
10-07 17:03:40.452: INFO/System.out(1193): End date :: Thu Oct 20 16:25:00 Pacific/Fiji 2011
  

Если я установлю часовой пояс для «Америка / Тихуана»;

 10-06 22:05:20.702: INFO/System.out(1193): Default timezon id :: America/Tijuana
10-06 22:05:20.712: INFO/System.out(1193): Timezon id :: Asia/Calcutta Timezon name :: GMT 05:30
10-06 22:05:20.712: INFO/System.out(1193): TImezon :: org.apache.harmony.luni.internal.util.ZoneInfo@1294e658
10-06 22:05:20.733: INFO/System.out(1193): Date :: 20 Oct 2011 04:20:00 GMT
10-06 22:05:20.742: INFO/System.out(1193): Start date :: 2011-10-19 21:20:00
10-06 22:05:20.742: INFO/System.out(1193): Calender's timezon :: GMT 05:30
10-06 22:05:20.752: INFO/System.out(1193): Start date :: yyyy-mm-dd hh:mm:ss 2011-9-19 21:20
10-06 22:05:20.752: INFO/System.out(1193): End date :: Wed Oct 19 21:25:00 America/Tijuana 2011
  

Редактировать

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

Комментарии:

1. можете ли вы добавить (cal.get(Calendar. МЕСЯЦ) 1) в строке печати? и все еще не понимаю, о чем ваш запрос?

2. @jazz Вы можете видеть вывод, когда я меняю часовой пояс, вывод отличается от того, что я не хочу, означает, что я хочу ту же дату и время, что и при вводе

3. У меня возникла проблема, у меня есть время, полученное с сервера, которое мне нужно отобразить в часовом поясе устройства, которое может динамически меняться. Я использовал новый SimpleDateFormat(«HH: mm», Locale.getDefault()); Но это было неправильное форматирование, когда часовой пояс изменен и приложение уже запущено. Поэтому я устанавливаю часовой пояс каждый раз перед форматированием с использованием экземпляра как <code> HOUR_MINUTE_FORMAT = new SimpleDateFormat(«ЧЧ: мм», Locale.getDefault()); format.setTimeZone(TimeZone.getDefault()); </code>

Ответ №1:

Дата — это всего лишь мгновение в универсальном времени. Он не имеет понятия о часовом поясе. Думайте об этом как «когда Кеннеди был убит».

Когда вы отображаете это время с помощью a SimpleDateFormat , этот формат даты имеет часовой пояс, и вы отображаете этот момент времени, используя этот часовой пояс. Итак, если часовой пояс формата даты является центральным стандартным временем, это время будет отображаться как 12:30. Если часовой пояс UTC, он будет отображаться как 18:30.

Если вы хотите, чтобы какая-то дата отображалась одинаково, независимо от часового пояса, вам просто нужно выбрать определенный часовой пояс (например, UTC) и всегда отображать дату с этим часовым поясом. Таким образом, вы должны вызвать setTimeZone DateFormat перед форматированием даты.

Комментарии:

1. Но если я хочу использовать календарь, то как я могу решить эту проблему? Пожалуйста, помогите мне

2. Календарь — это оболочка вокруг даты. Вызовите getTime(), и вы получите дату.

3. Я только благодарю, когда они спасли меня от часов безумия. Это один из них 😉 большое спасибо.

Ответ №2:

В стандартной Java:

 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
sdf.setTimeZone(TimeZone.getTimeZone(<your timezone here>);

long millis = <your timestamp here>; //timestamps are not TZ dependent.
Date d = new Date(millis);
String toDisplay = sdf.format(d);
  

Часовой пояс в SimpleDateFormat — это фиксированный часовой пояс, который вы хотите использовать для каждой отображаемой даты, а не для устройства по умолчанию.
Также убедитесь, что столбец временных меток в вашей базе данных начинает отсчет в тот же момент времени, что и Java (1/1/1970, он ЖЕ эпоха Unix), и имеет ту же точность (миллисекунды).

Есть еще один android.text.format.Класс DateFormat, но я не вижу смысла его использовать.

Комментарии:

1. SimpleDateFormat использует часовой пояс. Я проверил ваш путь, но не решил свою проблему

2. Это должно работать. Вы должны установить фиксированный часовой пояс (всегда один и тот же). Например, для отображения дат в Индии используйте India TZ. При изменении TZ устройства выходные данные должны быть одинаковыми.

3. Да, это работает, но если я хочу использовать Календарь, то как я могу решить эту проблему

4. Используется Calendar.getInstance(<your timezone>) для получения Calendar экземпляра.

Ответ №3:

Я получаю решение, подобное приведенному ниже методу

 /**
     * Date time must be in milliseconds  
     * return Time in milliseconds
     */
    public static String getTimeInMilli(Context ctx, String datetime) {
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(Long.parseLong(datetime));
        //This will return daylight savings offset in milliseconds.You have to Subtract  this milliseconds from calendar
        int dayLightSaving  = cal.get(Calendar.DST_OFFSET);

        cal.setTimeInMillis(cal.getTimeInMillis() - dayLightSaving);

        TimeZone z = cal.getTimeZone();
        int offset = z.getRawOffset();
        int offsetHrs = offset / 1000 / 60 / 60;
        int offsetMins = offset / 1000 / 60 % 60;

        // Subtract offset of your current TimeZone
        cal.add(Calendar.HOUR_OF_DAY, (-offsetHrs));
        cal.add(Calendar.MINUTE, (-offsetMins));

        cal.setTimeZone(TimeZone.getTimeZone("GMT"));

        //add offset of your TimeZone
        cal.add(Calendar.HOUR_OF_DAY, 5);
        cal.add(Calendar.MINUTE, 30);

        return String.valueOf(cal.getTimeInMillis());
    }
  

Теперь, если я изменю часовой пояс на своем устройстве, дата моего приложения останется прежней.