Lies mal hier: #7
... z.B. 243/22 Bedeutet Tag 243, Jahr 2022 = 31.08.2022.
Meine Aufgabe ist es nun aus dem 243 ein Datum zu ermitteln.
...
Ja, das hab ich glatt überlesen. Vlt. kann man das ja trotzdem umstellen???
Entgegen der Überschrift, will er es aber umgekehrt berechnen, also aus dem Tag des Jahres das zugehörige Datum:
FUNCTION "CalDay_To_Date" : Void
{ S7_Optimized_Access := 'FALSE' }
VERSION : 0.1
VAR_INPUT
CalDay : String;
END_VAR
VAR_OUTPUT
"Date" : Date;
DateTime : Date_And_Time;
END_VAR
VAR_TEMP
tmp_dayString : String[3];
tmp_yearString : String[2];
tmp_dayInt : Int;
tmp_yearInt : Int;
tmp_pointer : Int;
tmp_retval : Int;
tmp_dateTime : Date_And_Time;
tmp_dateTimeStruct : Struct
year : Byte;
month : Byte;
day : Byte;
hour : Byte;
minute : Byte;
second : Byte;
milliSecon : Word;
END_STRUCT;
tmp_date : Date;
i : Int;
END_VAR
BEGIN
//parse input
#tmp_pointer:=FIND(IN1:=#CalDay, IN2:='/');
#tmp_dayString := LEFT(IN := #CalDay, L := #tmp_pointer - 1);
#tmp_yearString := RIGHT(IN := #CalDay, L := 2);
//convert input to int
#tmp_dayInt := STRING_TO_INT(#tmp_dayString);
#tmp_yearInt := STRING_TO_INT(#tmp_yearString);
//set up Date_And_Time to the first day of specified year
#tmp_dateTimeStruct.year := INT_TO_BCD16(#tmp_yearInt);;
#tmp_dateTimeStruct.month := 1;
#tmp_dateTimeStruct.day := 1;
#tmp_retval:=BLKMOV(SRCBLK:=#tmp_dateTimeStruct, DSTBLK=>#tmp_dateTime);
//add n - 1 days to set up Date_And_Time
IF #tmp_dayInt > 1 THEN
FOR #i := 1 TO #tmp_dayInt - 1 DO
#tmp_dateTime := T_ADD(IN1 := #tmp_dateTime, IN2 := t#1d);
END_FOR;
END_IF;
// write outputs
#DateTime := #tmp_dateTime;
#Date := DT_TO_DATE(#tmp_dateTime);
END_FUNCTION
Nicht ganz. Es ist ein 16 Bit Word (UINT) 0 = D#1990-1-1 bis 65378 (W#16#FF62) = D#2168-12-31Ohne es geprüft zu haben, aber ist der Datentyp "Date" nicht eigentlich ein DINT mit der Anzahl Tagen seit dem 01.01.1970?
Also könnte es reichen einfach die Tage bis zum 01.01.2022 + die Anzahl Tage im Jahr zu summieren und in "Date" zu wandeln/kopieren (in AWL)?
D#jjjj-01-01 - 1 + x
berechnen, allerdings müsste man dafür erst noch die Tagnummer D#jjjj-01-01 (das "DateSerial" des 1. Januar des Jahres) berechnen oder als vorberechnete Tabelle hinterlegen.Und was sollst Du mit dem Datum machen? Nur auf einem HMI anzeigen? Da gibt es vielleicht schon DateSerial- und DateAdd-Funktionen?Meine Aufgabe ist es nun aus dem 243 ein Datum zu ermitteln.
leider sind die Operatoren + und - zwischen Date und Int/DInt nicht gültig.Das Datum des x-ten Tages eines Jahres läßt sich tatsächlich einfach durchD#jjjj-01-01 - 1 + x
berechnen,
FUNCTION "DayYearStr_to_Date" : Date
{ S7_Optimized_Access := 'FALSE' }
AUTHOR : PN_DP
VERSION : 0.1
VAR_INPUT
DayYearStr : String; // Tag/Jahr-String in der Art 'ddd/yy'
END_VAR
VAR_TEMP
tmp_dayString : String[3];
tmp_yearString : String[2];
tmp_dayInt : Int;
tmp_yearInt : Int;
tmp_pointer : Int;
tmp_DT : Date_And_Time;
tmp_DTstruct AT tmp_DT : Struct
YEAR : Byte;
MONTH : Byte;
DAY : Byte;
HOUR : Byte;
MINUTE : Byte;
SECOND : Byte;
MSEC12 : Byte;
MSEC3WEEKDAY : Byte;
END_STRUCT;
tmp_DateSerial : DInt;
END_VAR
BEGIN
//DATE aus Tag/Jahr-String in der Art 'ddd/yy' berechnen
//die Nummer des Tages ist max dreistellig: '1'..'366'
//das Jahr ist immer zweistellig: '00'..'89', '90'..'99' entsprechend 2000..2089 und 1990..1999
//parse input
#tmp_pointer := FIND(IN1 := #DayYearStr, IN2 := '/');
#tmp_dayString := LEFT(IN := #DayYearStr, L := #tmp_pointer - 1);
#tmp_yearString := RIGHT(IN := #DayYearStr, L := 2);
//convert input to int
#tmp_dayInt := STRING_TO_INT(#tmp_dayString); //1..366
#tmp_yearInt := STRING_TO_INT(#tmp_yearString); //0..99
//add n - 1 days to year
#tmp_DT := DT#1990-01-01-00:00:00.000; //DATE_AND_TIME-Variable initialisieren
#tmp_DTstruct.YEAR := WORD_TO_BYTE(INT_TO_BCD16(#tmp_yearInt));
#tmp_DateSerial := DATE_TO_DINT(DT_TO_DATE(#tmp_DT)) + #tmp_dayInt - 1;
//write return value
#DayYearStr_to_Date := DINT_TO_DATE(#tmp_DateSerial);
END_FUNCTION
hier eine umfachreiche DateInfo Funktion.
liefert folgende Daten zu einem S7-Date
iYYYY : INT; // Year : [1990..2168]
iMM : INT; // Month : [1..12]
iDD : INT; // Day : [1..31]
WeekDayISO : INT; // Weekday ISO 8601 [1..7] = [Mo..Su]
WeekDayNA : INT; // Weekday Nothern Amerika [1..7] = [Su..Sa]
iWeek_ISO : INT; // Week ISO 8601, [1..53], EU, start on Monday
iWeek_NA : INT; // Week Northern America, [1..54], start on Sunday
iDayOfYear : INT; // Day No in the year [1..366]
iDaysInMonth : INT; // No of days in month [28..31]
xLeapYear : BOOL; // Year is leap year / Schaltjahr
xIso53WeekYear: BOOL; // Year contains 53 weeks according to ISO 8601
Da der Code das Limit von 1000 Zeichen überschreitet, kann ich ihn nicht direkt posten, sondern
muss ihn als Anhang anfügen. Geschrieben ist der Code in SCL unter Step7 Classic V5.5
FUNCTION "m7_CreateDate" : DATE
TITLE = 'Create DATE-Format from Year/Month/Day'
// ==============================================================================
//
// Erezugt das Date-Format aus den Angaben Year/Month/Day
//
// Die Berechung macht sich die Integerrundung zu nutze, um die Schalttage korrekt
// zu berechnen. Alle Divisionen müssen Integerdivisionen sein (immer abgerundet).
// Berechnet wird die Anzahl der Tage nach dem Gregorinischen Kalender seit
// Christi Geburt.
//
// Bedingung für ein Schaltjahr (mit 29.Feb)
// - ein Schaltjahr ist alle 4 Jahre (Jahreszahl ist durch 4 teilbar)
// - das Schaltjahr fällt alle volle 100 Jahre aus
// - das Schaltjahr fällt alle volle 400 Jahre nicht aus (findet also statt)
//
// function CrateDate(y,m,d) // Calculates the Daynumber from Date
//
// Die Berechnung erfolgt nach folgender Formel
// zuerst werden die Monats-Nummern verschoben:
// 0=März bis 11=Februar (wegen Schalttagberechnung)
//
// m = (m + 9) Mod 12 // verschiebt die Monate 0=März bis 11=Februar
//
// Wenn Monat = Januar oder Februar, dann 1 von Jahren abziehen, dies wird
// wegen der Verschiebung der Monate nötig. Für die Schaltjahresberechung
// ist das ebenfalls notwendig, da im Falle eines Schaltjahres der Februar
// noch nicht vorbei ist und ein evtl. Schalttag (29.Feb.) noch nicht
// eingefügt sein kann. Die fehlenden Tage werden bei der Berechnung der Montastage
// mit (m*306 +5)/10 wieder korrekt draufgerechnet. Zum Schluss muss 1 Tag abgezogen
// werden, da Christi Geburt Tag 0 ist!
//
// mit dem Trick (m*306+5)/10 erreicht man durch die Integerrundung, dass alle Monate mit der
// korrekten Tageszahl 30 oder 31 berechnet werden (selbst die doppelte 31 von Juli, August wird
// korrekt abgebildet. Der Februar als einziger Monat mit weniger Tagen steht am Schluss (Nr.11) und
// ist somit für die 30/31 Tage Berechnung irrelevant, da die Berechnung nur die Tage der
// vollständig vergangenen Vormonate abbilden muss. Die Tage des akt. Monats werden über +d addiert.
//
// y = y - m/10 // m/10 =1 für Monate Jan. & Feb. (Monats-Nr. 10 & 11)
//
// return (365*y + y/4 - y/100 + y/400 + (m*306 + 5)/10 + d - 1 )
// ==============================================================================
//
// AUTHOR: S.Maag
// DATE: 10/2008
// CHANGELOG:
// ------------------------------------------------------------------------------
// DATE NAME DESCRIPTION
// ------------------------------------------------------------------------------
// 26.02.2020 S.Maag getestet und Fehler "-dd" behoben, muss "+dd" sein
// 31.07.2017 S.Maag Coverted AWL TO SCL version
// ------------------------------------------------------------------------------
VERSION : '3.0'
AUTHOR : 'S.Maag'
FAMILY : 'Maagic7'
VAR_INPUT
iYear : INT ; // Year
iMonth : INT ; // Month
iDay : INT ; // Day
END_VAR
VAR_TEMP
yy : DINT ;
mm : DINT ;
dd : DINT ;
END_VAR
BEGIN
mm := (INT_TO_DINT(iMonth) + 9) MOD 12; // Jan..Dez/1..12 => März..Feb/0..11
yy := INT_TO_DINT(iYear) - mm/10; // -1, wenn Monat = Jan. oder Feb. Anzahl Tage >306 (SummeTage[März..Dez]=306)
dd := INT_TO_DINT(iDay);
// L#726773 = "Anzahl Tage bis 31.12.1989" + 306 = 726467 + 306; in Step 7 ist 0 = 01.01.1990
// Dass hier nochmals eine Korrektur von 306 Tagen drin ist liegt an der Verschiebung der Monate 0..11/März..Feb
// Klar ist mir das nicht, da die Korrektur bereits über YY-mm/10 erfolgt sein sollte! Aber es funktioniert korrekt!
m7_CreateDate := DINT_TO_DATE(365*yy + yy/4 - yy/100 + yy/400 +(mm*306 +5)/10 + dd -(1+726773));
END_FUNCTION
//Jahr von Zeichen zu Int wandeln
IF #in_Jahr_X0 = ' ' AND #in_Jahr_0X = ' ' THEN
#Jahr_int := 00;
ELSE
#Jahr_int := 10 * (BYTE_TO_INT(#in_Jahr_X0) - 48) + (BYTE_TO_INT(#in_Jahr_0X) - 48);
END_IF;
IF (#Jahr_int MOD 4) = 0 THEN
#Schaltjahr := TRUE;
ELSE
#Schaltjahr := FALSE;
END_IF;
// Tag des Jahres von Zeichen zu Integer wandeln
IF #in_TdJ_X00 = ' ' AND #in_TdJ_0X0 = ' ' AND #in_TdJ_00X = ' ' THEN
#TdJ_int := 0;
ELSE
#TdJ_int := 100 * (BYTE_TO_INT(#in_TdJ_X00) - 48) + 10 * (BYTE_TO_INT(#in_TdJ_0X0) - 48) + (BYTE_TO_INT(#in_TdJ_00X) - 48);
END_IF;
IF NOT #Schaltjahr THEN
CASE #TdJ_int OF
1..31: // Januar
#out_Monat_X0 := '0';
#out_Monat_0X := '1';
#Tag_int := #TdJ_int;
32..59: // Februar
#out_Monat_X0 := '0';
#out_Monat_0X := '2';
#Tag_int := #TdJ_int - 31;
60..90: // März
#out_Monat_X0 := '0';
#out_Monat_0X := '3';
#Tag_int := #TdJ_int - 59;
91..120: // April
#out_Monat_X0 := '0';
#out_Monat_0X := '4';
#Tag_int := #TdJ_int - 90;
121..151: // Mai
#out_Monat_X0 := '0';
#out_Monat_0X := '5';
#Tag_int := #TdJ_int - 120;
152..181: // Juni
#out_Monat_X0 := '0';
#out_Monat_0X := '6';
#Tag_int := #TdJ_int - 151;
182..212: // Juli
#out_Monat_X0 := '0';
#out_Monat_0X := '7';
#Tag_int := #TdJ_int - 181;
213..243: // August
#out_Monat_X0 := '0';
#out_Monat_0X := '8';
#Tag_int := #TdJ_int - 212;
244..273: // September
#out_Monat_X0 := '0';
#out_Monat_0X := '9';
#Tag_int := #TdJ_int - 243;
274..304: // Oktober
#out_Monat_X0 := '1';
#out_Monat_0X := '0';
#Tag_int := #TdJ_int - 273;
305..334: // November
#out_Monat_X0 := '1';
#out_Monat_0X := '1';
#Tag_int := #TdJ_int - 304;
335..365: // Dezember
#out_Monat_X0 := '1';
#out_Monat_0X := '2';
#Tag_int := #TdJ_int - 334;
ELSE
#out_Monat_X0 := ' ';
#out_Monat_0X := ' ';
#Tag_int := 0;
END_CASE;
ELSE
CASE #TdJ_int OF
1..31: // Januar
#out_Monat_X0 := '0';
#out_Monat_0X := '1';
#Tag_int := #TdJ_int;
32..60: // Februar
#out_Monat_X0 := '0';
#out_Monat_0X := '2';
#Tag_int := #TdJ_int - 31;
61..91: // März
#out_Monat_X0 := '0';
#out_Monat_0X := '3';
#Tag_int := #TdJ_int - 60;
92..121: // April
#out_Monat_X0 := '0';
#out_Monat_0X := '4';
#Tag_int := #TdJ_int - 91;
122..152: // Mai
#out_Monat_X0 := '0';
#out_Monat_0X := '5';
#Tag_int := #TdJ_int - 121;
153..182: // Juni
#out_Monat_X0 := '0';
#out_Monat_0X := '6';
#Tag_int := #TdJ_int - 152;
183..213: // Juli
#out_Monat_X0 := '0';
#out_Monat_0X := '7';
#Tag_int := #TdJ_int - 182;
213..244: // August
#out_Monat_X0 := '0';
#out_Monat_0X := '8';
#Tag_int := #TdJ_int - 212;
245..274: // September
#out_Monat_X0 := '0';
#out_Monat_0X := '9';
#Tag_int := #TdJ_int - 244;
275..305: // Oktober
#out_Monat_X0 := '1';
#out_Monat_0X := '0';
#Tag_int := #TdJ_int - 274;
306..335: // November
#out_Monat_X0 := '1';
#out_Monat_0X := '1';
#Tag_int := #TdJ_int - 305;
336..366: // Dezember
#out_Monat_X0 := '1';
#out_Monat_0X := '2';
#Tag_int := #TdJ_int - 335;
ELSE
#out_Monat_X0 := ' ';
#out_Monat_0X := ' ';
#Tag_int := 0;
END_CASE;
END_IF;
// Tag von Int zu Zeichen wandeln
CASE #Tag_int OF
1..9:
#out_Tag_X0 := '0';
#out_Tag_0X := INT_TO_BYTE(#Tag_int + 48);
10..19:
#out_Tag_X0 := '1';
#out_Tag_0X := INT_TO_BYTE(#Tag_int - 10 + 48);
20..29:
#out_Tag_X0 := '2';
#out_Tag_0X := INT_TO_BYTE(#Tag_int - 20 + 48);
30..31:
#out_Tag_X0 := '3';
#out_Tag_0X := INT_TO_BYTE(#Tag_int - 30 + 48);
ELSE
#out_Tag_X0 := ' ';
#out_Tag_0X := ' ';
END_CASE;
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?