БлогNot. По поводу "неправильного" времени в мидлетах и перевода времени в Windows Mobile...

По поводу "неправильного" времени в мидлетах и перевода времени в Windows Mobile...

Итак, 25 октября в 03:00 по местному мы опять на час провалимся в прошлое. И мне на полгода перестанут иногда писать о мидлетах, где есть встроенные часы, что они показывают "неверное время"...

Начнём с того, что на практике Java работает с "абсолютным" временем, отсчитанным как число миллисекунд, прошедших с полуночи по Гринвичу 1 января 1970 года (класс java.util.Date).

Апплеты и мидлеты могут лишь отобразить это время или поменять его интерпретацию, связанную с часовым поясом или иными факторами. Более того, изменить системное время устройства средствами Java нельзя, а методы, предназначенные для работы с часовыми поясами и учёта летнего/зимнего времени (например, метод useDaylightTime класса java.util.TimeZone в Java2ME) зачастую абстрактные, то есть, объявлены, но не реализованы в библиотеках языка, программист должен написать их сам.

Кстати, по умолчанию Java2ME "обязана" поддерживать только одну временную зону - GMT.

Поэтому корректный учёт времени - это непростая задача, и для прикладных приложений - всё-таки забота Java-машины, а программисту вполне достаточно уметь вызвать методы, возвращающие дату/время для часового пояса по умолчанию.

Из выложенных на сайте мидлетов время отображают в разных видах Alcometr, ServerTime, DateCalc, TimeReminder, Расписания 1 и 2, anClock.

В большинстве телефонов есть настройки часового пояса и учёта летнего/зимнего времени, так что ява-приложение всегда получит нужное время, как и было на Siemens S75, Nokia 6100 и Sony Ericsson К320i, служивших в разное время "тестерами" моих мидлетов.

А вот под Windows Mobile, к примеру, проблемы возможны.

На коммуникаторе E-Ten X500+ с операционкой Windows Mobile 6.1 и ява-машиной IBM MIDP20 (VGA) перечисленные выше мидлеты летом показывают время "на час меньше". Проблема, очевидно, связана с тем, что ява-машина от IBM реализована для американской локали, где перевода часов нет. Таким образом, для корректной работы "алкометра" на этой платформе достаточно выставить поле коррекции времени всегда равным 6. При этом летом часы в поле ввода будут показывать время, на час меньшее, зимой - нормальное. Но на самом деле это одно и то же время. Второй выход - найти ява-машину с локалью, имеющей летнее и зимнее время.

Если мидлет вводит временные данные в режиме "только время" (DateField.TIME) возможны странные вещи - возвращаемое время как бы всегда интерпретируется по Гринвичу, даже если выставить в ява-машине другой часовой пояс.

При этом в документации написано "The date object is constructed according the rules of locale specific calendaring system and defined time zone."

Рисунок показывает, что возвращает в "Алкометре" код

DateField t;
...
t= new DateField ("Заголовок",DateField.TIME);
...
mathFunc = new mathFunc ();
Date dt = mathFunc.getFieldTime(-1);
t.setDate (dt);
...
t0=mathFunc.getTime0 (); //Начало суток в мс
t1=mathFunc.getTime();   //Текущее время в мс
Date d2=t.getDate();     //"Только время" и зформы
t2=t0+d2.getTime();      //Введённое время в мс
if (options.correction!=0) { //Коррекция введенного времени на options.correction часов
 t2+=options.HOURS_1*options.correction;
}

где вызываемые методы класса mathFunc имеют вид

 public Date getFieldTime (int delta) {
  cal = Calendar.getInstance();
  cal.set (Calendar.DAY_OF_MONTH,1);
  cal.set (Calendar.MONTH,Calendar.JANUARY);
  cal.set (Calendar.YEAR,1970);
  long newTime=cal.getTime().getTime()+delta*options.MINUTE_1;
  cal.setTime (new Date (newTime));
  return cal.getTime();
 } 
 public long getTime0 () { //время начала суток в мс
  cal=Calendar.getInstance();
  cal.set (Calendar.HOUR_OF_DAY,0);
  cal.set (Calendar.MINUTE,0);
  cal.set (Calendar.SECOND,0);
  cal.set (Calendar.MILLISECOND,0);
  return cal.getTime().getTime();
 }
 public long getTime () { //текущее время в мс
  return Calendar.getInstance().getTime().getTime();
 }

Время из DateField.TIME в разных часовых поясах
Время из DateField.TIME в разных часовых поясах

Вообще говоря, ввод времени в Shedule 2 и Timereminder сделан не по спецификации, то есть, поля ввода DateField в режиме TIME не инициализируются датой 1 января 1970 г.

Поэтому встроенный в WTK эмулятор показывает их как null, но реальные телефоны время отображают.

К сожалению, если сделать всё по спецификации, то есть,

  DateField df = new Datefield ("Время",DateField.TIME);
  Date dt = new Date ();
  Calendar cal = Calendar.getInstance();
  cal.set (Calendar.DAY_OF_MONTH,1);
  cal.set (Calendar.MONTH,Calendar.JANUARY);
  cal.set (Calendar.YEAR,1970);
  dt=cal.getTime();
  df.setDate(dt);

то придётся, как и в алкометре, отдельной опцией учитывать возможное смещение полученного времени из-за часового пояса.

Получается, что в настройках таких мидлетов целесообразно сделать поле для "коррекции времени", которая будет применяться к метке времени, прочитанной из поля ввода даты с форматом Datefield.TIME. Именно так и сделано в Alcometr 1.0.1. Для Новосибирска, например (GMT+6), коррекция будет 6 часов при "зимнем" времени и 7 - при "летнем".

Вообще, в Windows Mobile 6 нет галочки "переход на зимнее/летнее время". Будет ли он совершён, определяется двумя настройками:

  • региональная настройка КПК (Пуск - Настройки - вкладка Система - Язык и стандарты - вкладка Регион);
  • часовой пояс, указанный в системе (Пуск - Настройки - вкладка Система - Часы и сигналы - вкладка Время). Имеет значение и город, выбранный из списка. Например, Каир (GMT+2) переводить на летнее время не будет, т.к. в Египте его нет.

В некоторых менеджерах мобильной Windows, например, Advanced Configuration Tool, есть настройка Daylight Saving (переход на летнее/зимнее время).

 Отправлено на постоянное хранение сюда

18.10.2009, 01:37 [13338 просмотров]


теги: время коммуникатор java java2me winmobile

К этой статье пока нет комментариев, Ваш будет первым