Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Алгоритм перехода на летнее время.
Форум разработчиков электроники ELECTRONIX.ru > Цифровая обработка сигналов - ЦОС (DSP) > Алгоритмы ЦОС (DSP)
SpiritDance
Во-первых поздравляю всех с переходом на летнее время. Хорошего всем самочувствия.

Вопрос в следующем, кто-нибудь собственно алгоритм перехода на летнее время и обратно для часов встроенных систем? Если да то помогите либо подробным алгоритмом, либо исходниками пжалста. Надеюсь это не коммерческая тайна. smile.gif
rezident
Не нужно автоматически переводить время. Оставьте эту функцию на усмотрение пользователя. Иначе вохникают большие проблемы в случае когда используется журналирование данных с автоматическим восстановлением при сбоях и поиском по журналу.
А алгоритм при этом очень простой получается: при выводе времени на индикацию, прибавляйте один час к показаниям, если пользователем установлен флаг перехода на летнее время. В моем мобильнике, например, реализовано именно так.
acex2
Цитата(SpiritDance @ Mar 31 2008, 09:19) *
Во-первых поздравляю всех с переходом на летнее время. Хорошего всем самочувствия.

Вопрос в следующем, кто-нибудь собственно алгоритм перехода на летнее время и обратно для часов встроенных систем? Если да то помогите либо подробным алгоритмом, либо исходниками пжалста. Надеюсь это не коммерческая тайна. smile.gif


Вот тут подробно, по странам: http://www.worldtimezone.com/daylight.html
Вкратце: "В России и в Европе переход на летнее время осуществляется в последнее воскресенье марта в 2:00 переводом часовых стрелок на 1 час вперед, а обратный переход осуществляется в последнее воскресенье октября в 3:00 переводом стрелок на 1 час назад."
SpiritDance
Вот алгоритм вычисление собственно последнего дня недели в месяце в текущем году и интересует.

Журналирование данных ведется и временной поиск есть, думал избежать проблем с запретом перевода времени пока с последней журнальной записи не пройдет час. Еще подумаю.
на откуп пользователю отдать не могу, так как во-превых по времени определяется валидность sms? во вторых может возникнуть путаница с пониманием что в устройстве всегда записывается "зимнее" время.
Andrew2000
Цитата(SpiritDance @ Mar 31 2008, 12:36) *
Вот алгоритм вычисление собственно последнего дня недели в месяце в текущем году и интересует.

Для учета летнего/зимнего времени можно определить следующие переменные:

char saving-starts[3] = {p1,p2,p3};
char saving-ends[3] = {p1,p2,p3};
char time-offset = p4;
char saving-starts-time = p5;
char saving-ends-time = p6;

Параметры: p1 – какой день: 1 – первый, -1 – последний день недели месяца; p2 – день недели: 0 – воскресенье; p3 – месяц; p4 – разница во времени в минутах при переходе; p5, p6 – число минут после полуночи, когда переводить стрелки.

Переход на летнее время - Последнее воскресенье марта 2 часа ночи.
Переход на зимнее время - Последнее воскресенье октября 3 часа ночи.

saving-starts[3] = {1,0,4}; // последнее воскресенье марта
saving-ends[3] = {-1,0,10}; //последнее воскресенье октября
time-offset = 60; //1 час
saving-starts-time = 120; //2 часа ночи
saving-ends-time = 180; //3 часа ночи

Алгоритм перевода стрелок осенью:
1. На основании системных переменных знаем время перехода (tm_sec, tm_min, tm_hour);
2. Найдем (mktime) номер дня недели (tm_wday) для даты <сего года>.10.31 00:00:00 (последний день месяца);
3. dD := <номер дня недели <сего года>.10.31> – <номер дня недели перехода (из системной переменной)>; (учесть переход через 0);
4. ЧИСЛО ПЕРЕХОДА (tm_mday) = 31- dD;
5.Зная число (см. п.4) месяц (tm_mon) и год (tm_year) перехода (из системной переменной) и время перехода (см. п.1) определяем (time_t mktime(struct tm* )) точное время этого события в time_t формате.
Затем сверяем его с текущим временем.

Время перехода определяем при включении питания и при коррекции времени.

Примечание: в п.2,3,4 жестко записано 31, но нужно учитывать 30/31, если, вдруг, будет не октябрь и не март.

!!! аппаратные часы _всегда_ должны считать время в UTC, а учет летнего времени можно учитывать для отображения, журналов, и т.д.
rezident
Цитата(Andrew2000 @ Mar 31 2008, 16:35) *
!!! аппаратные часы _всегда_ должны считать время в UTC, а учет летнего времени можно учитывать для отображения, журналов, и т.д.
Угу. Я об этом же выше и толкую. Только в журнал тогда нужно писать лишь флаг-признак перехода на летнее время, а не собственно "летнее" время. Чтобы избежать глюков при индексировании и поиске почасовых записей.
SpiritDance
Спасибо.
umup
я делал (в программных часах на Меге 8) просто таблицу чисел марта/октября, соответствующих переходу (с 2000 по 203x год - всего 64 байта, думаю само вычисление числа займет больше).

Функция rtc_increment вызывается каждую секунду в обработчике прерывания часового кварца.
Флаги flag_rtc_sec_pass, flag_rtc_min_pass, flag_rtc_hr_pass используются в других частях программы для синхронизации с секундными, минутными, часовыми событиями (в конце основного цикла обнуляются).
Флаги flag_rtc_corrected и flag_rtc_corrected_forw - для улавливания события коррекции.

ul_rtc.h :

Код
/** \addtogroup group_rtc RTC structure/functions (структура и функции для работы с часами реального времени)
  */

#if ((!defined(ul_c_rtc_included)) || (defined __DOXYGEN__))

#define ul_c_rtc_included 1    /**< \brief module inclusion flag<br />флаг включения модуля \ingroup group_rtc */

#include "ul_misc.h"         /*include misc definitions/functions types*/

/** \brief RTC structure<br />структура часов \ingroup group_rtc */
typedef struct
{u8 sec;      /**< \brief seconds (0..59)   <br />секунды (0..59)       \ingroup group_rtc */
u8 min;      /**< \brief minutes (0..59)   <br />минуты (0..59)        \ingroup group_rtc */
u8 hr;       /**< \brief hours (0..23)     <br />часы (0..23)          \ingroup group_rtc */
u8 date;     /**< \brief date (1..31)      <br />дата (1..31)          \ingroup group_rtc */
u8 month;    /**< \brief month (1..12)     <br />месяц (1..12)         \ingroup group_rtc */
u16 year;    /**< \brief year (1900..2100) <br />год (1900..2100)      \ingroup group_rtc */
u8 flags;    /**< \brief RTC flags         <br />флаги RTC             \ingroup group_rtc */
u16 crc;     /**< \brief crc of structure  <br />контр.сумма структуры \ingroup group_rtc */
}struct_rtc;

#define flag_rtc_sec_pass       0x01 /**< \brief =1 every second passed <br />=1 каждую секунду \ingroup group_rtc */
#define flag_rtc_min_pass       0x02 /**< \brief =1 every minute passed <br />=1 каждую минуту \ingroup group_rtc */
#define flag_rtc_hr_pass        0x04 /**< \brief =1 every hour passed   <br />=1 каждый час \ingroup group_rtc */
#define flag_rtc_corrected      0x20 /**< \brief =1 if was time correction <br />=1 если была коррекция на летнее/зимнее время \ingroup group_rtc */
#define flag_rtc_corrected_forw 0x40 /**< \brief =1 if was hour-forward time correction (otherwise hour-backward)<br />=1 если была коррекция на час вперед (иначе на час назад) \ingroup group_rtc */
#define flag_rtc_correction     0x80 /**< \brief =1 for auto-correction <br />=1 для автоматического перехода на зимнее/летнее время \ingroup group_rtc */

/** \brief increment time of RTC structure by 1 second<br />увеличить время в структуре часов на 1 секунду \ingroup group_rtc */
inline void rtc_increment(void *rtc_data);

#endif



ul_rtc.c :

Код
#include "ul_rtc.h"  /*include RTC header*/

#if (defined(ul_c_use_gccavr))
#include <avr/pgmspace.h>     /*Program memory usage for AVR-GCC*/
#endif

#if (!defined(rtc_corr_dates_table))
#if (defined(ul_c_use_gccavr))
  u8 rtc_corr_dates_table[][32] PROGMEM = {{29,28,27,26,31,30,29,28,26,25,31,30,28,27,26,25,30,29,28,27,25,31,30,29,27,26,
25,31,29,28,27,26},
  {26,25,31,30,28,27,26,25,30,29,28,27,25,31,30,29,27,26,25,31,29,28,27,26,31
,30,29,28,26,25,31,30}
};
#else
  u8 rtc_corr_dates_table[][32]         = {{29,28,27,26,31,30,29,28,26,25,31,30,28,27,26,25,30,29,28,27,25,31,30,29,27,26,
25,31,29,28,27,26},
  {26,25,31,30,28,27,26,25,30,29,28,27,25,31,30,29,27,26,25,31,29,28,27,26,31
,30,29,28,26,25,31,30}
};
#endif
#endif

inline void rtc_increment(void *rtc_data)
{u8 u8_01, u8_02;
u8_01 = (*((struct_rtc *)rtc_data)).month;
u8_02 = (*((struct_rtc *)rtc_data)).date;
(*((struct_rtc *)rtc_data)).flags |= flag_rtc_sec_pass;  /*set second passed flag*/
if (++((*((struct_rtc *)rtc_data)).sec) == 60)          /*process seconds overflow*/
{(*((struct_rtc *)rtc_data)).sec = 0;
  (*((struct_rtc *)rtc_data)).flags |= flag_rtc_min_pass; /*set minute passed flag*/
  if (++((*((struct_rtc *)rtc_data)).min) == 60)         /*process minutes overflow*/
  {(*((struct_rtc *)rtc_data)).min = 0;
   (*((struct_rtc *)rtc_data)).flags |= flag_rtc_hr_pass; /*set hour passed flag*/
   if (++((*((struct_rtc *)rtc_data)).hr) == 24)         /*process hours overflow*/
   {(*((struct_rtc *)rtc_data)).hr = 0;
    u8_02++; /*calculate next date*/
    if (u8_02 == 32) {u8_01++; u8_02 = 1;}
    else if (u8_02 == 31)
    {if ((u8_01 == 4) || (u8_01 == 6) || (u8_01 == 9) || (u8_01 == 11))
     {u8_01++;
      u8_02 = 1;
     }
    }else if (u8_02 == 30)
     {if (u8_01==2) {u8_01++; u8_02 = 1;}
     }else if (u8_02 == 29)
      {if ((u8_01 == 2) && (((*((struct_rtc *)rtc_data)).year) & 3))
       {u8_01++;
        u8_02 = 1;
       }
      }
    /*month overflow*/
    if (u8_01 == 13)
    {u8_01 = 1;
     ((*((struct_rtc *)rtc_data)).year)++;
    }
   }
  }
}
(*((struct_rtc *)rtc_data)).month = u8_01;
(*((struct_rtc *)rtc_data)).date = u8_02;

/*if needed, do time auto correction*/
if ((*((struct_rtc *)rtc_data)).flags & flag_rtc_correction)
{/*every last sunday of march (hour++) and october (hour--) at 4 a.m.*/
  if (((u8_01 == 10) || (u8_01 == 3)) && (u8_02 > 24) &&
      ((*((struct_rtc *)rtc_data)).hr == 4) && ((*((struct_rtc *)rtc_data)).min == 0) &&
      ((*((struct_rtc *)rtc_data)).sec == 0))
  {u8 u8_03;
   /*get correction date*/
   u8_03 = ((u8)((*((struct_rtc *)rtc_data)).year)) & 0x1f; /*table index*/
   #if (defined(ul_c_use_gccavr))
    u8_03 = pgm_read_byte(&(rtc_corr_dates_table[u8_01 & 1][u8_03]));
   #else
    u8_03 = rtc_corr_dates_table[u8_01 & 1][u8_03];
   #endif
   /*if date is correct, do time correction*/
   if (u8_02 == u8_03)
   {(*((struct_rtc *)rtc_data)).flags |= flag_rtc_corrected; /*set correction flag*/
    if (u8_01 == 3)
    {(*((struct_rtc *)rtc_data)).hr++;
     (*((struct_rtc *)rtc_data)).flags |= flag_rtc_corrected_forw; /*forward correction*/
    }else (*((struct_rtc *)rtc_data)).hr--;
   }
  }
}
}
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.