На форуме обязательно:
  1. Заполнить свой профиль НА РУССКОМ ЯЗЫКЕ КИРИЛИЦЕЙ. См. Правила, п.2.d.
  2. Не писать свой вопрос в первую попавшуюся тему, а вместо этого создать свою. См. Правила, п.3.a.

Рекламу мы не размещаем ни на каких условиях.

Си и ST: Перевод из GMT в MSK

Модератор: специалисты по PLC

Ответить

Автор темы
leon78
завсегдатай
завсегдатай
Сообщения: 597
Зарегистрирован: 25 июл 2008, 09:06
Имя: U.L.A.
Благодарил (а): 2 раза
Поблагодарили: 8 раз
Контактная информация:

Си и ST: Перевод из GMT в MSK

Сообщение leon78 » 09 фев 2011, 09:34

Отмене перехода на "зимнее" время посвящается.
Блоки для Concept на EFB Toolkit.
Работает только в текущем веке!

Код: Выделить всё


///////////////////////////////////////////////////////////////////////////////
//Конвертация времени формата МЭК (по Гринвичу) в формат Concept (по Москве)
static BOOL TimeConvert_IEC_GMT_to_Concept_MSK(
                PTR_UDINT      T_IEC,       //Время в формате МЭК
                PTR_WORD       YEAR,        //Год
                PTR_aWORD_1x8  Calend)      //Дата

{
    UINT    i;
    UINT    days;
    UINT    days_add;
    UINT    days_in_month;
    UINT    ColichVisGod;
    UINT    PoslVoskrMarta;
    UINT    PoslVoskrOktyabrya;
    UDINT   ostatok;
    UDINT   T_IEC_MSK;
    UDINT   PoslVoskrMarta02_00;
    UDINT   PoslVoskrOkt02_00;
    int     arYDays [12];

    arYDays [0] = 0;
    arYDays [1] = 31;
    arYDays [2] = 59;
    arYDays [3] = 90;
    arYDays [4] = 120;
    arYDays [5] = 151;
    arYDays [6] = 181;
    arYDays [7] = 212;
    arYDays [8] = 243;
    arYDays [9] = 273;
    arYDays [10] = 304;
    arYDays [11] = 334;

    //MSK = GMT+3
    T_IEC_MSK = (* T_IEC)+3*MS100_PER_SEC*SECS_PER_HOUR;
    //Високосный год
    if ((* YEAR & 3) == 0)
        days_add = 1;
    else
        days_add = 0;

    //Определяем ситуацию, когда в москве уже новый год, а по гринвичу нет
    if (T_IEC_MSK>=((365+days_add)*MS100_PER_SEC*SECS_PER_DAY))
    {
        (*Calend)[Calend_Year] = * YEAR+1;
        T_IEC_MSK -= ((UDINT)(365+days_add))*MS100_PER_SEC*SECS_PER_DAY;
        if (((* YEAR+1) & 3) == 0)
            days_add = 1;
        else
            days_add = 0;
    }
    else
    {
        (*Calend)[Calend_Year] = * YEAR;
    }
    //Переход на летнее время
    ColichVisGod=((*Calend)[Calend_Year]-1)/4;
    PoslVoskrMarta=90-((*Calend)[Calend_Year]+ColichVisGod+5)%7;
    if ((((*Calend)[Calend_Year]+4)%28)==0) PoslVoskrMarta+=7;
    PoslVoskrOktyabrya=304-((*Calend)[Calend_Year]+ColichVisGod+2)%7;
    if ((((*Calend)[Calend_Year]+24)%28)==0) PoslVoskrOktyabrya+=7;
    PoslVoskrMarta02_00=((UDINT)(PoslVoskrMarta-1))*MS100_PER_SEC*SECS_PER_DAY+2*MS100_PER_SEC*SECS_PER_HOUR;
    PoslVoskrOkt02_00=((UDINT)(PoslVoskrOktyabrya-1))*MS100_PER_SEC*SECS_PER_DAY+2*MS100_PER_SEC*SECS_PER_HOUR;
    if (PoslVoskrMarta02_00<T_IEC_MSK && T_IEC_MSK<PoslVoskrOkt02_00) T_IEC_MSK += 1*MS100_PER_SEC*SECS_PER_HOUR;

    //Месяц
    days = T_IEC_MSK/MS100_PER_SEC/SECS_PER_DAY;

    for (i = 0; i <= 10; i++)
    {
        days_in_month = arYDays [i + 1] - 1;
        if (i > 1)
            days_in_month = days_in_month + days_add;
        if ( days <= days_in_month)
            break;
    }
    (*Calend)[Calend_Month] = i + 1;
    //День
    days_in_month = arYDays [i];
    if (i > 1)
        days_in_month = days_in_month + days_add;
    (*Calend)[Calend_Day] = days + 1 - days_in_month;
    ostatok = T_IEC_MSK / MS100_PER_SEC - (days * SECS_PER_DAY);
    //Час
    (*Calend)[Calend_Hour] = ostatok/SECS_PER_HOUR;
    ostatok = ostatok - (*Calend)[Calend_Hour] * SECS_PER_HOUR;
    //Минуты
    (*Calend)[Calend_Min] = ostatok/SECS_PER_MIN;
    ostatok = ostatok - (*Calend)[Calend_Min] * SECS_PER_MIN;
    //Секунды
    (*Calend)[Calend_Sec] = ostatok;
    return TRUE;
}
Кусок кода на ST.
Работает только в текущем веке!

Код: Выделить всё

 			IF (CM_stat.Stat & CM_Stat_time_master) = CM_Stat_time_master THEN
                	(*Получена установка времени от мастера *)
				New_Time := TRUE;
				(*Конвертация времени формата МЭК (по Гринвичу) в формат Concept (по Москве)*)
    				(*MSK = GMT+3*)
    				T_IEC_MSK := IEC_Time+3*MS100_PER_SEC*SECS_PER_HOUR;
    				(*Високосный год*)
    				IF (INT_TO_WORD(BCD_TO_INT(WORD_TO_INT(INT_TO_WORD(%SW53) AND 16#00FF))) & 3) = 0 THEN
        				days_add := 1;
    				ELSE
        				days_add := 0;
				END_IF;

    				Calend_Year := INT_TO_UINT(BCD_TO_INT(WORD_TO_INT(INT_TO_WORD(%SW53) AND 16#00FF)));
				(*Определяем ситуацию, когда в москве уже новый год, а по гринвичу нет*)
    				IF T_IEC_MSK>=(UINT_TO_UDINT(365+days_add)*MS100_PER_SEC*SECS_PER_DAY) THEN
					IF BCD_TO_INT(WORD_TO_INT(SHR_WORD (IN := INT_TO_WORD(%SW52) AND 16#FF00, N := 8))) = 12 THEN
						Calend_Year := Calend_Year +1;
					END_IF;
        				T_IEC_MSK := T_IEC_MSK -(UINT_TO_UDINT(365+days_add))*MS100_PER_SEC*SECS_PER_DAY;
    					IF (INT_TO_WORD(BCD_TO_INT(WORD_TO_INT(INT_TO_WORD(%SW53) AND 16#00FF))) & 3) = 0 THEN
        					days_add := 1;
    					ELSE
        					days_add := 0;
					END_IF;
    				END_IF;
    				(*Переход на летнее время*)
    				ColichVisGod:=(Calend_Year-1)/4;
				PoslVoskrMarta:=90-MOD (IN1 := (Calend_Year+ColichVisGod+5),IN2 := 7);   				
    				IF (MOD(IN1 :=Calend_Year+4,IN2 :=28))=0 THEN
					PoslVoskrMarta:=PoslVoskrMarta+7;
				END_IF;
    				PoslVoskrOktyabrya:=304-MOD(IN1 :=Calend_Year+ColichVisGod+2,IN2 :=7);
    				IF MOD(IN1 :=Calend_Year+24,IN2 :=28)=0 THEN
					PoslVoskrOktyabrya:=PoslVoskrOktyabrya+7;
				END_IF;
    				PoslVoskrMarta02_00:=(UINT_TO_UDINT(PoslVoskrMarta-1))*MS100_PER_SEC*SECS_PER_DAY+2*MS100_PER_SEC*SECS_PER_HOUR;
    				PoslVoskrOkt02_00:=(UINT_TO_UDINT(PoslVoskrOktyabrya-1))*MS100_PER_SEC*SECS_PER_DAY+2*MS100_PER_SEC*SECS_PER_HOUR;
    				IF PoslVoskrMarta02_00<T_IEC_MSK & T_IEC_MSK<PoslVoskrOkt02_00 THEN
					T_IEC_MSK := T_IEC_MSK +1*MS100_PER_SEC*SECS_PER_HOUR;
				END_IF;

    				(*Месяц*)
    				days := UDINT_TO_UINT(T_IEC_MSK/MS100_PER_SEC/SECS_PER_DAY);

				FOR i := 0 TO 10 DO
        				days_in_month := arYDays [i + 1] - 1;
        				IF i > 1 THEN
            					days_in_month := days_in_month + days_add;
					END_IF;
        				IF days <= days_in_month THEN
            					EXIT;
	    				END_IF;
				END_FOR;
    				Calend_Month:= i + 1;
    				(*День*)
    				days_in_month := arYDays [i];
    				if i > 1 THEN
        				days_in_month := days_in_month + days_add;
				END_IF;
    				Calend_Day:= days + 1 - days_in_month;
    				ostatok := T_IEC_MSK / MS100_PER_SEC - (UINT_TO_UDINT(days) * SECS_PER_DAY);
    				(*Час*)
    				Calend_Hour:= UDINT_TO_UINT(ostatok/SECS_PER_HOUR);
    				ostatok := ostatok - UINT_TO_UDINT(Calend_Hour) * SECS_PER_HOUR;
    				(*Минуты*)
    				Calend_Min:= UDINT_TO_UINT(ostatok/SECS_PER_MIN);
    				ostatok := ostatok - UINT_TO_UDINT(Calend_Min) * SECS_PER_MIN;
    				(*Секунды*)
    				Calend_Sec:= UDINT_TO_UINT(ostatok);

  	          		New_Time_C[1] := WORD_TO_UINT(BYTE_AS_WORD (LOW := UINT_TO_BYTE(Calend_Year),HIGH := UINT_TO_BYTE(Calend_Month))); 
				New_Time_C[2] := WORD_TO_UINT(BYTE_AS_WORD (LOW := UINT_TO_BYTE(Calend_Day),HIGH := UINT_TO_BYTE(Calend_Hour))); 
				New_Time_C[3] := WORD_TO_UINT(BYTE_AS_WORD (LOW := UINT_TO_BYTE(Calend_Min),HIGH := UINT_TO_BYTE(Calend_Sec))); 
			END_IF;
Хард - это то, что можно швырнуть об стенку, а софт - это то, что можно лишь обматерить.


Автор темы
leon78
завсегдатай
завсегдатай
Сообщения: 597
Зарегистрирован: 25 июл 2008, 09:06
Имя: U.L.A.
Благодарил (а): 2 раза
Поблагодарили: 8 раз
Контактная информация:

Re: Си: Перевод из GMT в MSK

Сообщение leon78 » 09 фев 2011, 12:50

:)
Ну не очень у меня уровень английского, что поделать :)
Могу заменить всё на a1, a2, ..., a999
Хард - это то, что можно швырнуть об стенку, а софт - это то, что можно лишь обматерить.

Ответить

Вернуться в «F.A.Q. по языкам программирования»