Laden...

[erledigt] Byte Array korrekt in Datum bzw. formatierten String umwandeln (Kommunikation mit SPS)

Erstellt von frave vor 6 Jahren Letzter Beitrag vor 6 Jahren 2.750 Views
F
frave Themenstarter:in
5 Beiträge seit 2017
vor 6 Jahren
[erledigt] Byte Array korrekt in Datum bzw. formatierten String umwandeln (Kommunikation mit SPS)

Guten Tag Zusammen,

ich habe folgendes Problem:

Meine SPS speichert das Datum im s.g. DTL format:
Min. DTL#1970-01-01-00:00:00.0
Max.: DTL#2554-12-31-23:59:59.999999999

also 96Bit breit.

Dieses lese ich mittels C# Byte-weise ein (hier im Falle vom Jahr):

 
 private void HexDump(RichTextBox DumpBox, byte[] bytes, int Size)
        {
            if (bytes == null)
                return;
            byte[] tempByteArray0 = new byte[2] { bytes[1], bytes[0] }
            Int16 jahr = BitConverter.ToInt16(tempByteArray0, 0);
}

Im Falle vom Jahr funktioniert das auch wunderbar.

Allerdings bekomme ich es jetzt nicht hin aus den ersten 4 Bytes ein korrektes Datum anzeigen zu lassen.

Ich wäre sehr Dankbar für eine Anregung, oder Hilfestellung!

Beste Grüße
Florian

verwendetes Datenbanksystem: <bitte immer angeben>

D
985 Beiträge seit 2014
vor 6 Jahren

Es ist immer sehr hilfreich wenn man zeigt was man als Eingangsdaten hat und was man als Rückgabewert erwartet.

Also, was für eine Bytefolge hast du und welchen Datum/Zeitwert soll das darstellen?

1.029 Beiträge seit 2010
vor 6 Jahren

Hi,

wenn ich gerade richtig recherchiert habe sind die Bytes die von der SPS kommen "unsigned" - ergo ist Int16 nur fast der richtige Datentyp - eigentlich bräuchtest du UInt16.

Denke dann kommst du auch auf die richtigen Werte.

Für alles weitere wäre die Bytefolge, sowie der daraus zu lesende Wert interessant.

LG

PS: Alles was zu diesem DTL-Format steht scheint in der SPS unsigned zu sein.

F
frave Themenstarter:in
5 Beiträge seit 2017
vor 6 Jahren

Hallo Sir Rufo,

Also ich möchte das in einem Datatable speichern Datum/Uhrzeit getrennt. Im Idealfall natürlich als DateTime Variable.

als String sieht das ganze so aus:

07-E1-09-04-02-0A-26-00-08-7F-C0-30

wobei gilt:
Byte 0&1 = Jahr
Byte 2 = Monat
Byte 3 = Tag
Byte 4 = Wochentag
Byte 5 = Stunde
Byte 6 = Minute
Byte 7 = Sekunde
Byte 8-11=Nanosekunde

@ Taipi88: werde ich probieren

F
frave Themenstarter:in
5 Beiträge seit 2017
vor 6 Jahren

Habe mal weiter geforscht

uint kennt der Bitkonverter nicht...

Hier die Variablendefinition in der SPS:
Byte 0&1 = Jahr = Uint
Byte 2 = Monat = USint
Byte 3 = Tag = USint
Byte 4 = Wochentag = USint
Byte 5 = Stunde = USint
Byte 6 = Minute = USint
Byte 7 = Sekunde = USint
Byte 8-11=Nanosekunde = UDint

Gruß und Danke schonmal

1.029 Beiträge seit 2010
vor 6 Jahren

Hi,

ich sagte ja auch UInt16.

LG

PS: So würde ich das wohl lösen (ohne Nanosekunden):


using System;

namespace ConsoleApp1
{
	internal class Program
	{
		private static void Main(string[] args)
		{
			var data = new byte[] 
			{
				0x07, 0xE1, // 0,1: year
				0x09, // 2: month
				0x04, // 3: days
				0x02, // 4: weekday
				0x0A, // 5: hours
				0x26, // 6: minutes
				0x00, // 7: seconds
				0x08, 0x7F, 0xC0, 0x30 // 8-1: nanoseconds?
			};

			Console.WriteLine(data.FromDlt());
			Console.ReadLine();
		}
	}

	public static class SpsHelper
	{
		public static DateTime FromDlt(this byte[] dltArray)
		{
			if (dltArray == null || dltArray.Length < 8)
				throw new ArgumentException();
			var year = BitConverter.ToUInt16(new[] { dltArray[1], dltArray[0] }, startIndex: 0);
			return new DateTime(year, dltArray[2], dltArray[3], dltArray[5], dltArray[6], dltArray[7]);
		}
	}
}


F
frave Themenstarter:in
5 Beiträge seit 2017
vor 6 Jahren

OK, sorry, wer lesen kann.....

habe jetzt mal versucht mit der beschriebenen Methode den Monat auszulesen:


byte[] tempByteArray3 = new byte[1] {bytes[2]};
monat = BitConverter.ToUInt16(tempByteArray3, 0);

Mit dem Ergebnis: das ich folgende Fehlermeldung erhalte:

Fehlermeldung:
Fehlermeldung:
Additional information: Das Zielarray ist nicht lang genug, um alle Elemente in der Sammlung zu kopieren. Überprüfen Sie Arrayindex und -länge.

1.029 Beiträge seit 2010
vor 6 Jahren

Hi,

siehe dazu auch meinen Edit obendrüber - KP was sich Siemens da mit den Angaben zu Datentypen gedacht hat - aber die ganzen anderen Werte sind ja offenkundig byte und da du ja am Ende sicher ohnehin ein DateTime haben möchtest - kannst du das ja implizit im Konstruktor einfach nehmen als wäre es ein int. (Der Wert zu deinem Hex-String kommt bei mir als 01.09.17 - 10:38 raus, was schon sinnvoll klang)

Falls du die Nanosekunden haben möchtest - schaust du dir mal am besten nachfolgenden Link an, da DateTime eben in Ticks (= 100 Nanosekunden) rechnet.
https://stackoverflow.com/questions/5358860/is-there-a-high-resolution-microsecond-nanosecond-datetime-object-available-f

LG

Edit:
Year ist der einzige UInt16 -der Rest sind Bytes - Nanosekunden sind demzufolge UInt32.
(int ist übrigens Int32)

D
985 Beiträge seit 2014
vor 6 Jahren

Und man muss darauf achten, dass wir es hier mit BigEndian zu tun haben.

Mit einem passenden BinaryReader/Writer (der BigEndian verwendet) kann man so ein Byte-Array dann sehr schön lesen und schreiben.

F
frave Themenstarter:in
5 Beiträge seit 2017
vor 6 Jahren

Super so klappt es.

BigEndian ist in dieser Lösung kein Problem, bei meinem Ansatz musste ich die Bytes tatsächlich noch Umsortieren.
Edit:
Schon wieder nicht richtig hingeschaut... Natürlich werden hier die Bytes umsortiert:

 
BitConverter.ToUInt16(new[] { dltArray[1], dltArray[0] }, startIndex: 0);

Vielen Dank euch!
Gruß
Florian

16.842 Beiträge seit 2008
vor 6 Jahren

Dafür ist eigentlich der Endian (endianness) verantwortlich.