S7NetPlus / s7netplus

S7.NET+ -- A .NET library to connect to Siemens Step7 devices
MIT License
1.35k stars 595 forks source link

Date Type Handling - Pull Request #517

Open paviano opened 1 year ago

paviano commented 1 year ago

Hello Dears, I've just wrote a little code to handle the Date Type inside the Siemens PLC (tested on Siemens 1515). Unfortunatly, I've used a DateOnly struct, that's available only from .NET 6+.

internal static class DateOnly
{
    public static readonly System.DateTime SpecMinimumDateTime = new System.DateTime(1990, 1, 1);

    public static readonly System.DateTime SpecMaximumDateTime = new System.DateTime(2169, 06, 06);

    public const int DEFAULT_ADD_YEAR = 1989;

    internal static System.DateOnly FromByteArray(byte[] bytes)
    {
        Int16 dayNumber = (Int16)((bytes[0] << 8) | bytes[1]);

        System.DateOnly dt = System.DateOnly.FromDayNumber(dayNumber).AddYears(DEFAULT_ADD_YEAR);

        return dt;
    }

    internal static byte[] ToByteArray(System.DateOnly dateOnly)
    {
        // Subtract the default year to return the date to the original range

        int yearAdjusted = dateOnly.Year - DEFAULT_ADD_YEAR;

        // the date within the permissible limits

        if (yearAdjusted < 0 || yearAdjusted > 9999)
        {
            throw new ArgumentOutOfRangeException("The year of the date is out of the allowed range after subtracting DEFAULT_ADD_YEAR.");
        }

        // Create a new DateOnly object with the adjusted year and get the day number
        // this will be the actual object that needs to be handled

        System.DateOnly adjustedDateOnly = new System.DateOnly(yearAdjusted, dateOnly.Month, dateOnly.Day);

        Int16 dayNumber = (Int16)adjustedDateOnly.DayNumber;

        // Converts the number of the day to a byte array

        byte[] bytes = new byte[2];

        bytes[0] = (byte)(dayNumber >> 8);
        bytes[1] = (byte)(dayNumber & 255);

        return bytes;
    }

    internal static System.DateOnly[] ToArray(byte[] bytes)
    {
        int cnt = bytes.Length / 2;

        System.DateOnly[] result = new System.DateOnly[cnt];

        for (int i = 0; i < cnt; i++)
        {
            result[i] = FromByteArray(new ArraySegment<byte>(bytes, i * 2, 2).Array);
        }

        return result;
    }
}
gfoidl commented 1 year ago

I've used a DateOnly struct,

Would it work with DateTime (where the time-component is left blank) work too?

paviano commented 1 year ago

Nope, It wont. You've to provide a System.DateOnly.

You have the System.DateOnly only if you're using .NET6+; if you're using it you can simply DateOnly.FromDateTime(yourDateTime);