Функция чтения Time Stamp (UNIX TIME)






   
    Для журнала потребовалось ставить временные метки. Time Stamp самый лучший вариант. В 4 байта переменной unsigned long влезает полная дата и время. В некоторых источниках указано что, 32-х битная переменной хватит только до 2038 года. Но не сложно проверить, что если используется без знаковая переменная то значения 0хFFFFFFFF хватит до 7 февраля 2106 года.
  Остается не понятным, почему за точку отсчета выбран 1970 год. Чуть более практичным, был бы выбор начала эпохи с високосного года 1968 или 1972.    

Первый вариант. Конвертирование 32-х битного значения в понятные данные.

Обратный вариант. Конвертация понятный значений в переменную UNIX TIME.

Проверялось здесь Unix time конвертер
             
           
            
            
void Value_To_Time_Stamp ( unsigned long value, uint16_t *returned_data, signed int GTM=0 ); 

     void setup() {
                    Serial.begin (9600);
                  }

     void loop() 
                 {
                   uint16_t data[7] ={0,};
                  
                   Value_To_Time_Stamp( 1709613270, data, 0); 
   
                   Serial.print     ("Year : ");
                   Serial.println                 (data[0]);
                   Serial.print     ("Month : "); 
                   Serial.println                 (data[1]);
                   Serial.print     ("Day : ");
                   Serial.println                 (data[2]);
                   Serial.print     ("Hours : ");
                   Serial.println                 (data[3]);
                   Serial.print     ("Minutes : ");
                   Serial.println                 (data[4]);
                   Serial.print     ("Seconds : ");
                   Serial.println                 (data[5]);
                   Serial.print     ("Day Number : ");
                   Serial.println                 (data[6]);
                   Serial.println ("------------------------"); 
                  
                   delay (15000);                   
                 }


                  // Функция для получения данных о дате и времени на основании временной метки UNIX TIME. 
                  // Алгоритм построен вокруг основной формулы, которая считает количество дней прошедших с начала текущего года,
                  // с учетом прошедших високосных дней. Далее значения корректируются, если наступил так называемый лжевисокосный год.
                  //
                  // Получениее дней недели, часов, минут и секунд ни как не связано с остальным кодом и может быть выведено в отдельную функцию. 
                  // Для дат более 32-х битной эпохи UNIX TIME код потребует проверки.        

   void Value_To_Time_Stamp ( unsigned long value, uint16_t *returned_data, signed int GTM )
                  { 
                  //----Первым делом подстроим GTM-----------------------------
                        if (GTM >= 0)
                            {
                              value = value + (GTM * 3600);
                            }
                              else { GTM =~GTM + 1; value = value - (GTM * 3600); } 
                  //-------------------------------------------------------------

                  // "Магические числа" сведены в константные переменные. Такой код будет выполнятся дольше, чем если числа были бы вписаны в код.
                  //-----------------------------------------------------------------------------------------------------------------------------
                    const unsigned long half_vi_era = 68256000;   // Первая "полу-эпоха" с 1.янв.1970г. - 29.фев.1972г.
                                                                  // Необходима для точного определения наступления 
                                                                  // очередного високосного дня (29 фев)
                    const unsigned long one_vi_era  = 0x7861F80;  // Полная високосная эпоха (365+365+365+366) 1461 день.  

                    const unsigned long one_year    =  0x1E13380; // Один полный, обычный год. 365 * 86400
                    const unsigned long one_day     =  86400;     // Один день, 86400 секунд.
                  //---------------------------------------------------------------------------------------------------------------------------- 
                    
                       uint8_t vi_days=0;  // Високосные дни (29 февраля)
                       uint8_t fake_vi=0;  // Лжевисокосные дни (29 февраля в году кратном 4, 100 и не кратном 400)
                                                     
                       boolean vi_year=0;            // Високосный год
                       boolean fake_vi_year=0;       // Лжевисокосный год

                       unsigned long month_comp = 0x11044C;  //  Переменная-массив хранящая данные для окончания месяцев (30,31..29)
                       
                       unsigned long temp;                                            

                                    //--Расчет високосных дней----------------------------------
                                       vi_days = ((value - half_vi_era) / one_vi_era )+1;
                                    // На 1 больше, так как формула пропускает високосный год 1972 года.
                                    // Период до 29 фев. 1972г. просчитывается отдельно

                         // ----Расчет количества пройденых лет с начала эпохи UNIX TIME 
                           unsigned int years = (value - (vi_days * one_day)) / one_year; 

                               //--- Проверка года на високосность.-----------------------
                                unsigned int i = years + 1970;  // Текущий, календарный год. (Для следующих 2-х блоков),
                                 
                                   if ( ((years + 2) % 4)==0 ) // 1970-й не является високосным, поэтому (years + 2)
                                        { 
                                           vi_year = true;                                        
                                         
                                            //month_comp = month_comp - 4; // Корректировка переменной-массива хранящей окончание месяцев,
                                              month_comp = 0x110448;                          // для 29 февраля.
                                           
                                                 if ( (!(i%100)) && (!(i%4)) && (i%400) ) // Лжевисокосный год, описан ниже 
                                                         {
                                                            vi_year = false;
                                                            fake_vi_year = true;  
                                                          //month_comp = month_comp + 4; // Правим обратно, для 28 февраля. 
                                                            month_comp = 0x11044C;      
                                                         }
                                        }                 
                            //-------------------------------------------------------------------------------------------  
                            // Помимо високосных лет, кратных 4, существуют года, с периодичностью 100 лет,
                            // не кратных 400 и которые не являются високосными. В 32-х битной эпохе UNIX TIME таковым
                            // будет 2100 год. Далее 2200, 2300...  2400 уже високосный и так далее.
                            // Их счет ведет переменная fake_vi, такой лжевисокосный если он текущий: fake_vi_year = true.

                                  // Данный блок на перспективу, для работы в периодах более 2100г. и далее.
                                  // Подсчитает количество лжевисокосных годов прошедших с начала эпохи.  
                                  // Первый подобный в 2100 году.
                                  
                                     for ( ; i>2099; i--)
                                          {  
                                             if ( (!(i%100)) && (!(i%4)) && (i%400) )
                                                     {
                                                         fake_vi++;
                                                     }
                                          }
           
             // Просчет обычного високосного года. Для снижения vi_days после 29 фев.
             // Чтобы високосный день данного года не попал в формулу расчета дней текущего года. 
                if (vi_year || fake_vi_year)
                     {                        
                          if ( (value - (one_vi_era * vi_days) ) >= half_vi_era )                       
                                      {
                                        vi_days--;  
                                      }
                     }                    
               
               //   Расчет количества полных пройденых дней с начала текущего года. Основная формула.
               //   Расчет секунд ведется с прошедшего ("Нового Года").
               //---------------------------------------------------------------------------------------------------- 
                     temp  =  ( value  %  ((unsigned long) (one_year * years) + (vi_days * one_day))) / one_day;      
               //----------------------------------------------------------------------------------------------------

                         // Из не вошедшего... Для периода между 1 янв. 1970г. и 29 фев. 1972г. Когда значения лет и високосных дней
                         // принимают нулевые значения, основная формула и более ранние расчеты не работают из-за умножения и деления на 0.
                         // Чтобы не перегружать дополнительными условиями основной блок, которые будут проверятся при каждом обращении к функции, 
                         // условия расчета для данного периода вынесены отдельно, в данный блок. 
                         //------------------------------------------                    
                             if (value <= half_vi_era)
                                   { fake_vi=0; // из-за нулевых значений 1 янв 1972 некорректный расчет лет ранее.
                                     temp = value / one_day;
                                      years = temp / 365;
                                        temp = temp - (365 * years); 
                                   } 
                         //------------------------------------------   
                         
        // Блок корректировки високосных дней на основе полученных данных о ложно-високосных годах. 
        // Изначально заведен в условие наличия данных годов, чтобы до 2100 года не заходить в это ветвление.        
        //================================================================================================ 
                 if (fake_vi)
                     { 
                      int a = temp + fake_vi;
                      
                       if ( fake_vi_year )    //  -------------  Лжевисокосный год 
                            { 
                              a--; 
                                    if (a>364)
                                             {  years++;
                                                a = 365-a;  }                                 
                            }   
                                    if ( !vi_year )    //  -----------------  Обычный год 
                                          {                                         
                                              if (a>364)
                                                       {  years++;
                                                          a = 365-a;  }              
                                          }
                      if ( vi_year )    //   -----------------      Високосный год 
                           {                              
                                  if (a>365)
                                           {   years++;
                                               a = 366-a;   }          
                           } 
                     temp = a;                                             
                   }               
             //=====================================================================================================================
                            uint8_t month = 0;
                            int16_t day;                             
                               // Цикл расчета числа и месяца. month_comp в каждой из 12 пар бит хранит число от 0 до 3.
                               // То число, на которое необходимо сделать меньше 31, чтобы получить правильный размер каждого месяца.
                                 do {
                                      day=temp;                                   
                                      temp = temp - (31-(month_comp & 0x03));
                                      month_comp  = month_comp >> 2;
                                      month++;  
                                    } while ( (int16_t)temp >= 0); // Чтобы не создавать новых переменных приводим temp к знаковой
                                    
                          returned_data[1] = month;                           
                          returned_data[2] = day+1;  // Так как temp в предыдущем цикле это количество полных пройденных дней,
                          returned_data[0] = years + 1970; //  то текущая дата на 1 больше.
                      
                      
                      //  -----------------------------Блок расчета времени и дня недели--------------------------------------------
                      //  Данный блок может работать без всего основного кода.
                          
                          // --- Номер дня недели. ------------        
                              temp = value % 604800;      // Количество дней недели прошедших с начала текущей недели. 
                              day = temp/86400;           // Расчет идет по схеме 0-6. Потому в конце ++;
                              day = day+3;                // Корректировка. Так как начало эпохи (1янв 1970г.) это четверг. 
                                if (day>6){day = 6-day;
                                           day =  ~day;}
                              day++;
                              returned_data[6] = day;   
                           // ---------------------------------------
                             
                              value = value % one_day;          // Расчет секунд прошедших с начала текущих суток.
                              returned_data[3] = value / 3600;  // Количество полных часов прошедших с начала суток.
                              value = value % 3600;
                              returned_data[4] = value / 60;    // Минут
                              returned_data[5] = value % 60;    // Секунд 
                  }             
                  
                  
     



   Функция чтения Time Stamp 05. 03. 2024г. Nord_Air.

  Эта программа является свободным ПО: вы можете распространять и/или модифицировать её согласно условиям Основной Общественной Лицензии GNU, опубликованной Организацией Свободного Программного Обеспечения, 3-ей версии Лицензии, либо любой последующей версией.


   












      Статьи


  
    









   Изготовление рекламы Изготовление мебели  Общестроительные работы 3D моделирование       Статьи
  Благоустройство тер.
   Общее портфолио    Мебель для мастерской   Установка бордюров   Портфолио   Контакты
   Наружняя реклама       Фасадные работы   Модели   Образец договора
   Внутреняя реклама       Утепление гаража   Инфо
   Таблички, наклейки       Косметический ремонт   Фото г.Надым
  Бетонные работы   Фото пригороды г.Надым