Step 7 DT addieren

Ruslan

Level-1
Beiträge
3
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

ich würde gerne in SCL zu einem Datum eine bestimmte Anzahl an Tagen addieren wollen, z.B. 300 Tage. Diese Zahl ist veränderbar.
Leider reicht der Datentyp TIME dafür nicht aus, ansonsten würde ich die Funktion AD_DT_TM nutzen.
Kennt jemand eine elegante Lösung dafür? Genutzt wird CPU319-3PN/DP. Vielen Dank

MfG
 
Zuletzt bearbeitet:
Ich vermute, Du verwendest Step7 "classic" V5.x?

Du könntest in einer Schleife jeweils DT + T#1d addieren, oder z.B. jeweils T#10d oder T#20d und zum Schluß die Rest-Tage.

Oder mit DT_DATE und DT_TOD den DT in Datum + Uhrzeit zerlegen, dann die Tage auf das Datum addieren (z.B. mit der OSCAT Funktion DATE_ADD) und dann mit D_TOD_DT wieder zu DT zusammenfassen. (umständlicher und vermutlich langsamer als T#10d/T#Rest-Additionen)

Wo kommt die Anzahl Tage her? Von einem HMI was (VBS-)Skripte kann? Da könntest Du die DT + Tage Addition im HMI in VBS machen, z.B. mit DateAdd oder DateSerial.

Harald
 
Das wird dann zu folgendem AWL übersetzt.
DINT_TO_DATE und DATE_TO_DINT
braucht nur der SCL Compiler, da dort nur gleiche Typformate
für Berechungen verwendet werden könne.

Code:
      L     D#2020-2-20
      T     #MyDate
      L     L#300
      +D    
      T     #MyDate
 
Ich glaube da hast du recht!

Wenn es aber um Step7 classic geht, dann kann man in SCL
aber auch höchstens mit einer Schleife und einer Zusatzfunktion die das
addieren übernimmt funktionieren.

Wenn ich es genau gelesen hätte! Da stand AD_DT_TM!!! Wer lesen kann ist klar im Vorteil!
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Da mich das interessiert hab ich nochmal die Doku nachgesehn

DateAndTime format beinhaltet die absoluten Werte für: Jahr, Monat, Tag
das ist kein fortlaufender Wert! Wenn man da Tage addieren will,
dann müssen die Überläufe für die Monate mit 30/31 Tagen und Februar 28 Tage
sowie die korrekten Schaljahre mit berücksichtigt werden.

Das geht vernünftig nur, wenn man Jahr, Monat, Tag zuerst wieder in ein DATE verwandelt,
dann die Tage addiert und DATE wieder zurück zu Jahr, Monat, Tag.

d.h. DateAndTime splitten du DATE und TimeOfDay, dann Tage addieren und wieder zusammenfassen.

ich hab zwar eine Formel wie man Jahr, Monat, Tag zu einem DATE verbindet.
Rückwärts: DATE => Jahr, Monat, Tag ist aber schwer was zu finden.

Hab mit mal den FC3 D_TOD_DT intern angesehn! TOD + DATE zu DateAndTime
Das ist ne ganz schöne rechnerei! Da werden die Schaltjahrzyklen rausgerechnet, die Tage
korrigiert, der korrekte Monat zu den Tagen gesucht ...!

Hab mal versucht eine korrekte Berechnungsvorschirft für den gregorianschen Kalender zu finden,
aber irgendwie Fehlanzeige. Irgendwo muss das doch dokumentiert sein wie das geht!

Klar ist noch folgendes!
Schaltjahre alle 4 Jahre, alle 100Jahre fällt es aus und alle 400 Jahre fällt es nicht aus.

1 voller Schaltjahrzyklus 4 Jahre = 4+365Tage + 1 Schalttag = 1461 Tage

Code:
  dDATE: DINT;  // DINT mit Nr. des Tages (DATE)

  YY : DINT;  // Jahreszahl
  MM : DINT; // Monat
  DD : DINT; // TAG

Die Anzahl der Schaltjahreszyklen errechnet sich:

  SchaltJahrZyklen:= dDate/1461;

  RestTage := dDAte MOD 1461;  // Resttage die keinen vollen  Schaltjahrzykls mehr ergeben (max 3 Jahre +365 Tage = 1460 Tage max.)

  AusgefalleneSchaltjahre: SchaltJahrZyklen/25 - SchaltJahrZyklen/100;    // jeden 25 Zyklus fällt ein Schaltjahr aus, jeden 100 Zyklus findet es  statt
 
  // jetzt noch Resttage korriegieren, da die ausgefallen Schalttage bisher bereits abgezogen wurden
  RestTage := RestTage + AusgefalleneSchaltjahre;

  // dann wieviele volle Jahre geben die SchaltjahrZyklen + Resttage noch? 
  // Da bei den Resttagen kein Schaltjahr mehr dabei sein kann können wir fix 365Tage verwenden

  YY:= SchaltjahrZyklen * 4 + Resttage/365;  // Anzahl der Jahre  (wahrscheinlich muss man für die Jahreszahl zu den Anzahl Jahren noch 1  addieren)
  
  Resttage := Resttage MOD 365;  // für Monate verbleibende Tage

  // nun muss man noch korrekten Monat aus Resttagen bestimmen
  // wie ???
  // wenn Rest =0, dann ist man beim 31.12. des Jares,
 // sonst ist man im nächsten Jahr => die Jahreszahl muss nochmals korrigiert werden
  // mein Ansatz wäre jetzt ne Schleife in der ich von den Resttagen  immer die Anzahl der Monate von 1..x abziehe, bis nichts mehr übrig  bleibt!
 
Wenn man gregorianischen Kalender rechnet, d.h. von 0 an, dann muss man für S7_Date noch die
Anzahl der Tage abziehen, die bis 1.1.1990 bereits vergangen sind. Das müssten dan 1989 Jahre sein.

Code:
AnzahlTage1989 := 365 *1989 + 1989/4 - 1989/100 + 1989/400
                           :=  725985     +  497      -  19 + 4
                           :=  726467

// d.h. 726467 müsste der 31.12.1989 sein!
// der 1.1.1990 dann 1 mehr = 726468  das müsste dan S7_DATE =0 sein!
// ganz sicher bin ich mir aber nicht!
 
// ganz sicher bin ich mir aber nicht!
Deine Berechnung ist i.o.
Als Ergänzung
Code:
Anzahl der Schaltjahre berechnen [Y/4] + [Y/400] + [(X-1)/100] - [Y/100] - [(X-1)/4] - [(X-1)/400]
Y steht für das aktuelle Jahr
X steht für das Startjahr
Holger
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich hab's jezt mal reingetippt und getestet, scheint zu funktioniern.
Ist aber noch mit Vorsicht zu behandeln.
Für den Live-Einsatz taugt das evtl. noch nicht!

Code:
// 27.02.2019 scheint zu funktioinieren

FUNCTION m7_SplitDate : VOID

    TITLE = 'Split a S7-Date to Year, Month, Day'

    VERSION : '0.9'
    AUTHOR  : 'Beta!'
    FAMILY  : 'Maagic7'

VAR_INPUT
   IN_S7_DATE : DATE;   // S7-Date Formate (= Day-No. starting at 01.01.1990 = 0)
END_VAR

VAR_OUTPUT
    yy : INT;  // Year  : 1990..2168)
    mm : INT;  // Month : 1..12
    dd : INT;  // Day   : 1..31
END_VAR

VAR_TEMP
    // temporäre Variablen
    dDayNo : DINT;   // Nummer des absoluten Tages im gregorianischen Kalender
    y4     : DINT;   // Anzahl der 4-Jahreszyklen = Zyklen mit Schaltjahr = 4x365+1 Tage = 1461 Tage
    rest   : DINT;   // Resttage
    tmp_yy : DINT;   // Nr. des Jahres
    tmp_mm : DINT;   // Nr. des Monats
    tmp_dd : DINT;   // Nr. des Tages
    IsSchaltJahr : BOOL;   
    Ready : BOOL;    // Berechnung abgeschlossen
    days : ARRAY [1..12] OF DINT;   // Tage pro Monat
END_VAR

  
CONST
   cst_DaysTo1989 := 726467;      // Anzahl Tage bis einschl. 31.12.1989
END_CONST
    // Standard Tage/Monat initialisieren (kein Schaltjahr)
    days[1] := 31;
    days[2] := 28;
    days[3] := 31;
    days[4] := 30;
    days[5] := 31;
    days[6] := 30;
    days[7] := 31;
    days[8] := 31;
    days[9] := 30;
    days[10] := 31;
    days[11] := 30;
    days[12] := 31;
   
    Ready := FALSE;     // Berechnung fertig initialisieren
    
    dDayNo := DATE_TO_DINT(IN_S7_DATE) + cst_DaysTo1989 + 1;   // +1 da in Step7 1.1.1990 = 0 ist, im gregorianischen Kalender 726468
    
    y4 := dDayNo/1461;              // Anzahl der Schaltjahrzyklen
    rest := dDayNo MOD 1461;        // Rest der Tage, die keinen vollen Schaltjahrzyklus mehr ergeben
    
    // Schaltjahre sind alle 4 Jahre: 
    // jedes 100 Jahr   fällt es aus, jedes 400 Jahr   nicht! D.h.
    // jeden  25 Zyklus fällt es aus, jeden 100 Zyklus nicht! Das berechnen wir mit y4/25 und y4/100
    rest := rest + y4/25 - y4/100 ; // Resttage um Anzahl ausgefallener Schaltjahre korrigieren
    
    tmp_yy := y4*4 + rest/365;  // Akt. Jahreszahl := AnzahlJahreVolleSchaltjahrZyklen + GanzeJahreDerResttage
    rest := (rest MOD 365);         // verbleibende Resttage, die kein volles Jahr mehr ergeben
   
   // prüfen ob berechnete Jahreszahl ein Schaltjahr
    IsSchaltjahr := FALSE;
    IF (tmp_yy MOD 4) = 0 THEN
        IsSchaltjahr := TRUE;
        IF (tmp_yy MOD 100) = 0 THEN
            IsSchaltjahr := FALSE;
            IF(tmp_yy MOD 400)=0 THEN
                IsSchaltjahr := TRUE;
            END_IF;
        END_IF;
    END_IF;
    
    IF IsSchaltjahr THEN
    // **********      S C H A L T J A H R     **********
    // wenn Schaltjahr, dann gibt es 3 Möglichkeiten:
    // 1. bei Rest = 0 liegen wir am 30.12, da wir mit 365 das Jahr berechnet haben, das Schaltjahr aber 366 Tage hat
    // 2. bei Rest = 1 liegen wir am 31.12, 
    // 3. bei Rest > 1 geht es ins FolgeJahr, das aktuelle ist also komplett voll
    
        IF rest = 0 THEN     // Rest 0 = 365er Tag im Schaltjahr = 30.12 => Berechnung fertig
            tmp_mm:=12;      
            tmp_dd:=30;
            ready := TRUE;
        ELSIF rest =1 THEN   // Rest 1 = 366 Tag im Schaltjahr = 31.12 => Berechnung fertig
            tmp_mm:=12;      
            tmp_dd:=31;
            ready := TRUE;
        ELSE                        // Rest >1 => 366 Tage gehen ins aktuelle Schaltjahr, der Rest ins nächste Jahr
            rest := rest -1;        // Resttage korrigieren, da Schaltjahr 366 Tage hat, nicht 365
            tmp_yy := tmp_yy +1;    // Jahreszahl auf Folgejahr (kein Schaltjahr, da akt. Jahr = Schaltjahr
        END_IF;

    ELSE
    // ********** K E I N   S C H A L T J A H R **********

        // Wenn kein Schaltjahr, dann gibt es 2 Möglichkeiten
        // 1. bei Rest = 0 liegen wir am 31.12
        // 2. bei Rest > 0 sind wir im Folgejahr
        
        IF rest = 0 THEN    // Wenn Rest=0, 31.12. des Jahres; oder 30.12 des Jahres wenn es ein Schaltjahr ist!
            tmp_mm:=12;     // Wenn die Resttage =0, dann ist das aktuelle Jahr voll
            tmp_dd:=31;     // Wenn aktuelles Jahr <> Schalthjahr, dann ssind 365 = 31.12
            ready := TRUE;
        ELSE
            // FolgeJahr
            tmp_yy := tmp_yy +1;  // erst mal ins nächste Jahr, wir gehen davon aus, es ist kein Schaltjahr
            
            // nun müssen wir das FolgeJahr nochmals auf Schaltjahr prüfen, da das vorherige Jahr kein Schaltjahr war
            IsSchaltjahr := FALSE;
            IF (tmp_yy MOD 4) = 0 THEN
                IsSchaltjahr := TRUE;
                IF (tmp_yy MOD 100) = 0 THEN
                    IsSchaltjahr := FALSE;
                    IF(tmp_yy MOD 400)=0 THEN
                        IsSchaltjahr := TRUE;
                    END_IF;
                END_IF;
            END_IF;
            
            IF IsSchaltjahr THEN // das FolgeJahr in dem die Resttage sind ist ein Schaltjahr
               days[2] := 29;    // dann hat der Februar 29 Tage! in days-Array eintragen, dort stand bisher 28
            END_IF;
        END_IF;
    END_IF; 
   
    // ist die Berechnung noch nicht abgeschlossen, wir haben also noch Resttage im Folgejahr
    // dann müssen wir nun Monat und Tag aus den Resttagen bestimmen
    
    IF NOT Ready THEN
         // Resttage vorhanden, dann Monat und Tag des Monats bestimmen    
         tmp_mm := 0;   // Monat mit 0 intitialisieren
       
         WHILE (rest > 0) AND (tmp_mm <=12) DO
            tmp_mm := tmp_mm + 1;           // nächster Monat
            rest := rest - days[tmp_mm];    // von den Resttagen die TageAktMonat abziehen
         END_WHILE;
        
         IF rest = 0 THEN
            tmp_dd:=days[tmp_mm];  // Wenn Resttage=0, dann ist es der letzte des aktuellen Monats
         ELSE
            tmp_dd:= rest + days[tmp_mm]; // Resttage <0, dann müssen Tage des letzten vollen Monats wieder drauf
        END_IF;
    END_IF;

    yy := DINT_TO_INT(tmp_yy);      // Rückgabewert Jahr
    mm := DINT_TO_INT(tmp_mm);      // Rückgabewert Monat
    dd := DINT_TO_INT(tmp_dd);      // Rückgabewert Tag
END_FUNCTION
 
Zurück
Oben