2

Я использую SimpleDateFormat, чтобы превратить мои GregorianCalendar экземпляры в красивые строки. У меня странная проблема, когда в определенных датахвремя строка отключена одним, но не всегда.SimpleDateFormat часовая строка по-одному на определенные * даты *. Как? Зачем?

Обычно, если мой GregorianCalendar имеет значения, такие как HOUR_OF_DAY=0,MINUTE=11, тогда я получаю строку типа «1:11 AM». Но затем я меняю YEAR, MONTH, или DAY, и теперь HOUR_OF_DAY=0,MINUTE=11 дает мне строку «2:11».

Это мое время функции форматирования строк (даты и времени является GregorianCalendar):

public String toTimeString() { 
    Log.i(TAG, "Datetime: "+ datetime.toString() + "Formatted as: " + SimpleDateFormat.getTimeInstance(SimpleDateFormat.SHORT).format(datetime.getTime())); 
    return SimpleDateFormat.getTimeInstance(SimpleDateFormat.SHORT).format(datetime.getTime()); 
} 

Это дает мне эти журналы:

Работа хорошо первый:

Datetime: java.util.GregorianCalendar[time=1426637512725,areFieldsSet=true,lenient=true,zone=GMT,firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2015,MONTH=2,WEEK_OF_YEAR=12,WEEK_OF_MONTH=3,DAY_OF_MONTH=18,DAY_OF_YEAR=77,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=3,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=11,SECOND=52,MILLISECOND=725,ZONE_OFFSET=0,DST_OFFSET=0] 
Formatted as: 1:11 AM 

я изменить месяц с марта по апрель (год и день делают то же самое), а теперь это:

Datetime: java.util.GregorianCalendar[time=1429315912725,areFieldsSet=true,lenient=true,zone=GMT,firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2015,MONTH=3,WEEK_OF_YEAR=16,WEEK_OF_MONTH=3,DAY_OF_MONTH=18,DAY_OF_YEAR=108,DAY_OF_WEEK=7,DAY_OF_WEEK_IN_MONTH=3,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=11,SECOND=52,MILLISECOND=725,ZONE_OFFSET=0,DST_OFFSET=0] 
Formatted as: 2:11 AM 

Как это возможно?

Такое поведение по отдельности происходит только в следующих месяцах, а не в этом месяце или в прошлом. 2015 и 2016 годы прекрасны, но 2017 тоже вызывает проблему. Фактическая дата, похоже, вызывает ее, когда наступает неделя или больше в будущем (независимо от года).

Я могу изменить год, месяц и дату в разных виджетах пользовательского интерфейса, переключая форматирование строки времени от нормального к офлайновому и обратно. Я управляю часом с TimePicker, который вызывает форматирование строк на TimePicker.OnTimeChangedListener(). Я не думаю, что это актуально, так как оно работает, когда месяц и день установлены на некоторые значения, но вот этот код на всякий случай. Как вы можете видеть, есть некоторая обработка по отдельности, так как GregorianCalendar хранит HOUR_OF_DAY как значение 0-23, а TimePicker использует значения 1-24, соответствующие фактическому отображению виджета. Я думаю, что я сделал это правильно, но был бы рад узнать, что проблема - ошибка здесь.

private void setUpTimePicker() { 
    timePicker.setCurrentHour(schedule.getHourOfDay() + 1); 
    timePicker.setCurrentMinute(schedule.getMinute()); 

    timePicker.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() { 
     public void onTimeChanged(TimePicker view, int hourOfDay, int minute) { 
      schedule.setHourOfDay(hourOfDay - 1); 
      schedule.setMinute(minute); 
      timeText.setText(schedule.toTimeString()); 
     } 
    }); 
} 

Время суток отформатированных в строку всегда права (0 = 1 утра, 17 = 5 вечера, и т.д. в течение каждого часа дня) или всегда так (0 = 2 утра, 17 = 6 вечера, ЭСТ для каждого час дня) на основе других полей календаря. Согласованность заставляет меня думать, что это не проблема нити.

Не может быть проблема с часовым поясом как и любой другой подобный вопрос? Я не представляю, как. Мои GregorianCalandar экземпляры всегда создаются с помощью этой функции:

public static TimeZone TIMEZONE = TimeZone.getTimeZone("GMT"); 

private static GregorianCalendar makeCalendar(){ 
    GregorianCalendar now = (GregorianCalendar) GregorianCalendar.getInstance(TIMEZONE); 
    now.setFirstDayOfWeek(Calendar.SUNDAY); 
    return now; 
} 

Любые мысли были бы очень признательны! Я исчерпал все, о чем я могу думать, в том числе спать на нем в течение нескольких дней. Спасибо заранее всем, кто отвечает!

UPDATE

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

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

return SimpleDateFormat.getTimeInstance(SimpleDateFormat.SHORT).format(datetime.getTime()); 

к этому:

SimpleDateFormat sdf = new SimpleDateFormat("hh:mm a", LOCALE); 
     sdf.setTimeZone(TIMEZONE); 
     return sdf.format(datetime.getTime()); 

Затем я удалил +1 и -1 от TimePicker и это работает!

+0

я сомневаюсь это, но, возможно, это имеет какое-то отношение к летней экономии? – Felk

+2

Почти наверняка летнее время. Если дата/время конвертируется в ваш язык во время печати, а вы в Великобритании, с ноября по март (более или менее), ваше местное время совпадает с GMT. Но с апреля по октябрь (более или менее) ваше местное время на один час раньше GMT. – jas

+0

@jas и @Felk - Я не в Великобритании, я в Италии. Но да! Я не знал, что мне нужно установить часовой пояс в 'SimpleDateFormat'. Я чувствую себя глупо, потому что не видел этого сейчас (один из раздражающих двух месяцев года, когда США сделали летнее сбережение, но в Италии нет, и это влияет на мой календарь весь месяц). Наверное, мне просто было в голове, что я использую GMT, а timezones/DST - не моя проблема. И я был так уверен * мой вопрос не был другим часовым поясом! Ну что ж! По крайней мере, вы были очень хороши в этом :) –

ответ

2

Вы настройка часового пояса в календаре вы используете, но это не то, что вы передаете в SimpleDateFormat - вы используете только системное время пояс по умолчанию при форматировании здесь:

SimpleDateFormat.getTimeInstance(SimpleDateFormat.SHORT).format(datetime.getTime()) 

Я хотел бы предложить:

  • в идеале, перейти к Joda времени или java.time из Java 8. java.util классы ужасно. Я понимаю, что вы работаете на Android, поэтому java.time отсутствует, но является ли время Joda для вас?
  • Возьмите сборщик данных из уравнения: старайтесь придумать короткую, но полную программу, демонстрирующую проблему - просто консольное приложение, которое (скажем) пытается отформатировать 5 утра 1-го числа каждого месяца с начала 2010 года до конца 2019 года. (Попробуйте воспроизвести его за пределами Android, для простоты.)
  • Всякий раз, когда вы форматируете или разбираете (или делаете что-либо в основном), точно определяйте, в каком часовом поясе вы заинтересованы, и укажите его явно , (Я рекомендую использовать UTC вместо GMT чтобы указать «не смещение от UTC», как в противном случае некоторые люди будут думать, что означает, часовой пояс Великобритании.)
+0

Они не такие ужасные, хотя они требуют больше знаний, чем вам хотелось бы. Но в первую очередь это сложный вопрос. В конце ошибка является обычной, но простой: использование SimpleDateFormat с часовым поясом по умолчанию. –

+1

@SebastiaanvandenBroek: Это гораздо более простой способ понять, когда API подходит.Например, в Noda Time мы никогда ничего не делаем * ничего * используя часовой пояс по умолчанию неявно - вы должны * сказать *, когда хотите часовой пояс системы по умолчанию, потому что тогда, даже когда вы этого захотите, всем, кто читает код. Количество способов, в которых «Календарь» и «Дата» плохие, огромны ... Я мог бы надолго прокомментировать это * –

+0

'datetime' в: –

0

попробуйте использовать этот метод

Date date = new Date();  
System.out.println(new SimpleDateFormat("yyyy.MM.dd HH:mm").format(date)); 
Смежные вопросы