Click here to Skip to main content
15,885,782 members
Home / Discussions / C#
   

C#

 
GeneralRe: Execution of query?? Pin
Dave Kreskowiak4-Feb-14 4:25
mveDave Kreskowiak4-Feb-14 4:25 
AnswerRe: Execution of query?? Pin
Eddy Vluggen4-Feb-14 2:59
professionalEddy Vluggen4-Feb-14 2:59 
SuggestionRe: Execution of query?? Pin
thatraja4-Feb-14 3:19
professionalthatraja4-Feb-14 3:19 
AnswerRe: Execution of query?? Pin
Dave Kreskowiak4-Feb-14 4:26
mveDave Kreskowiak4-Feb-14 4:26 
AnswerRe: Execution of query?? Pin
Marco Bertschi5-Feb-14 0:16
protectorMarco Bertschi5-Feb-14 0:16 
Questionconvert MySQL UTC_TIMESTAMP() to user local time Pin
Jassim Rahma4-Feb-14 0:13
Jassim Rahma4-Feb-14 0:13 
AnswerRe: convert MySQL UTC_TIMESTAMP() to user local time Pin
Dave Kreskowiak4-Feb-14 4:21
mveDave Kreskowiak4-Feb-14 4:21 
QuestionSense of making my own Timestamp class? Pin
Marco Bertschi3-Feb-14 20:42
protectorMarco Bertschi3-Feb-14 20:42 
Alright, this is not exactly a programming question, but I also doubt that it would fit into the Lounge.
Situation: I am currently implementing the Syslog Protocol in .Net, starting with the Base classes (Message, Header, Struct. Data). The Header contains a timestamp which's formatting is exactly defined.
A timestamp may look as follows:

2014-2-4T14:22:56.235Z+1
2014-2-4T14:22:56.235Z-1.5
2014-2-4T14:22:56.235123Z+1


What I have done so far is that I consider System.DateTime being unuseable as timestamp, even with a wrapper around it it would be highly difficult since setting a single field (e.g. Day, Year, Month and so on) is only possible by parsing an entire time string, or adding a Time span.
Now to avoid these circumstances, I have implemented the following class SyslogTimestamp:

C#
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace Springlog.Com.Messaging
{
    /// <summary>
    /// Represents the Timestamp of a <see cref="SyslogMessageHeader"/>
    /// Author: Marco Bertschi, (C) 2014 Marco Bertschi
    /// </summary>
    public class SyslogTimestamp
    {
        #region Properties
        /// <summary>
        /// Returns the count of the days for a specific month in a specific year.
        /// </summary>
        /// <param name="month">month  </param>
        /// <param name="year">year</param>
        /// <returns></returns>
        static short GetDayMaxDaysOfMonth(int month, int year)
        {
            if (month != 2)
            {
                //  January       March         May           July          August        October        December        
                if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12)
                {
                    return 31;
                }
                else // April, June, September, November
                {
                    return 30;
                }
            }
            else //February
            {
                if (IsLeapYear(year))
                {
                    return 29;
                }
                return 28;
            }
        }
        /// <summary>
        /// Returns true if the argument is a leap year
        /// </summary>
        /// <param name="year">The year number to check</param>
        /// <returns></returns>
        private static bool IsLeapYear(int year)
        {
            if (year % 4 == 0)
            {
                if (year % 100 == 0)
                {
                    if (year % 400 == 0)
                    {
                        return true;
                    }
                    return false;
                }
                return true;
            }
            return false;
        }

        /// <summary>
        /// The part of the Timestamp which represents the year.
        /// </summary>
        int year;
        /// <summary>
        /// Gets the year part of the Timestamp.
        /// </summary>
        public int Year
        {
            get { return year; }
        }
        /// <summary>
        /// The part of the Timestamp which represents the month.
        /// </summary>
        int month;
        /// <summary>
        /// Gets the month part of the Timestamp.
        /// </summary>
        public int Month
        {
            get { return month; }
        }
        /// <summary>
        /// The part of the Timestamp which represents the day of the month.
        /// </summary>
        int dayOfMonth;
        /// <summary>
        /// Gets the days part of the Timestamp.
        /// </summary>
        public int DayOfMonth
        {
            get { return dayOfMonth; }
        }
        /// <summary>
        /// The part of the Timestamp which represents the hours.
        /// </summary>
        int hours;
        /// <summary>
        /// Gets the hours part of the Timestamp.
        /// </summary>
        public int Hours
        {
            get { return hours; }
        }
        /// <summary>
        /// The part of the Timestamp which represents the minutes.
        /// </summary>
        int minutes;
        /// <summary>
        /// Gets the minutes part of the Timestamp.
        /// </summary>
        public int Minutes
        {
            get { return minutes; }
        }
        /// <summary>
        /// The part of the Timestamp which represents the seconds.
        /// </summary>
        int seconds;
        /// <summary>
        /// Gets the seconds part of the Timestamp.
        /// </summary>
        public int Seconds
        {
            get { return seconds; }
        }
        /// <summary>
        /// The part of the Timestamp which represents the year.
        /// </summary>
        int miliseconds;
        /// <summary>
        /// Gets the milliseconds part of the Timestamp.
        /// </summary>
        public int Miliseconds
        {
            get { return miliseconds; }
        }
        /// <summary>
        /// The offset from the UTC timezone
        /// </summary>
        double utcOffset;
        /// <summary>
        /// Gets or sets the offset from the UTC timezone.
        /// </summary>
        public double UtcOffset
        {
            get { return utcOffset; }
            set { utcOffset = value; }
        }
        #endregion

        public SyslogTimestamp()
        {
            Reset();
        }

        public SyslogTimestamp(string timestamp)
        {
            Reset();
            FromString(timestamp);
        }

        public SyslogTimestamp(DateTime timestamp)
        {
            Reset();
            FromDateTime(timestamp);
        }

        /// <summary>
        /// Resets all fields to their default values;
        /// </summary>
        private void Reset()
        {
            miliseconds = 0;
            seconds = 0;
            minutes = 0;
            hours = 0;
            dayOfMonth = 0;
            month = 1;
            year = 1;
            utcOffset = 0;
        }

        /// <summary>
        /// Parses a string into a Syslog timestamp.
        /// </summary>
        /// <param name="dateTime">string which is going to be parsed</param>
        /// <returns>true = success | false = invalid string</returns>
        public bool FromString(string dateTime)
        {
            Regex splitRegex = new Regex("([0-9]{4})-([1-9]|[1][0-2])-([0-2]?[0-9]|[3][0-1])[T]([0-1]?[0-9]|[2][0-3])[:]([0-5]?[0-9])[:]([0-5]?[0-9])?.?([0-9]{1,6})[Z]([+-][0-9]|[+-]?[0][1][0-2])", RegexOptions.IgnoreCase);
            Match timestamp = splitRegex.Match(dateTime);

            if (timestamp.Groups.Count == 9)
            {
                AddYears(Int32.Parse(timestamp.Groups[1].Value));
                AddMonths(Int32.Parse(timestamp.Groups[2].Value));
                AddDays(Int32.Parse(timestamp.Groups[3].Value));
                AddHours(Int32.Parse(timestamp.Groups[4].Value));
                AddMinutes(Int32.Parse(timestamp.Groups[5].Value));
                AddSeconds(Int32.Parse(timestamp.Groups[6].Value));
                AddMilliseconds(Int32.Parse(timestamp.Groups[7].Value));
                utcOffset = Int32.Parse(timestamp.Groups[8].Value);

                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// Returns a fully formatted Syslog timestamp, as string.
        /// </summary>
        /// <returns>Syslog timestamp, as string</returns>
        public string ToFormattedString()
        {
            string timezonPreSign = "+";
            if (utcOffset < 0)
            {
                timezonPreSign = "";
            }
            return string.Format("{0}-{1}-{2}T{3}:{4}:{5}.{6}Z{7}{8}", year, month, dayOfMonth, hours, minutes, seconds, miliseconds, timezonPreSign, utcOffset);
        }
        public override string ToString()
        {
            return this.ToFormattedString();
        }
        /// <summary>
        /// Parses a <see cref="System.DateTime"/> type to a <see cref="SyslogTimestamp"/>. It is assumed that the
        /// DateTime type must be converted to UTC if the second argument is left out.
        /// </summary>
        /// <remarks>
        /// The FromDateTime method recognizes only the current daylight saving time adjustment rule for the local time zone. 
        /// As a result, it is guaranteed to accurately return the UTC offset of a local time only during the period in which the 
        /// latest adjustment rule is in effect. It may return inaccurate results if time is a historic date and time value 
        /// that was subject to a previous adjustment rule.
        /// </remarks>
        /// <param name="timestamp">The <see cref="System.DateTime"/> type which will be parsed</param>
        /// <param name="convertToUtc">true if the <paramref name="timestamp"/> must be converted to UTC. Else the UTC Offset of the 
        /// local computer is calculated and then added.</param>
        public void FromDateTime(DateTime timestamp, bool convertToUtc = true)
        {
            TimeSpan utcOffset = TimeZone.CurrentTimeZone.GetUtcOffset(timestamp);
            if (convertToUtc)
            {
                timestamp.Add(utcOffset);
                this.utcOffset = 0;
            }
            else
            {
                this.utcOffset = utcOffset.Hours + (utcOffset.Minutes / 100); 
            }

            AddMilliseconds(timestamp.Millisecond);
            AddSeconds(timestamp.Second);
            AddMinutes(timestamp.Minute);
            AddHours(timestamp.Hour);
            AddDays(timestamp.Day);
            AddMonths(timestamp.Month);
            AddYears(timestamp.Year);
        }

        /// <summary>
        /// Adds a <see cref="System.TimeSpan"/> to the timestamp
        /// </summary>
        /// <param name="timeSpan">The time span which is added to the Timestamp</param>
        public void Add(TimeSpan timeSpan)
        {
            AddMilliseconds(timeSpan.Milliseconds);
            AddSeconds(timeSpan.Seconds);
            AddMinutes(timeSpan.Minutes);
            AddHours(timeSpan.Hours);
            AddDays(timeSpan.Days);
        }
        /// <summary>
        /// Adds the passed millisecond value to the timestamp
        /// </summary>
        /// <param name="val">Added milliseconds</param>
        public void AddMilliseconds(int val)
        {
            if (val + miliseconds >= 1000)
            {
                AddSeconds( val / 1000);
                miliseconds = (val % 1000);
            }
            else
            {
                miliseconds += val;
            }
        }
        /// <summary>
        /// Adds the passed second value to the timestamp
        /// </summary>
        /// <param name="val">Added seconds</param>
        private void AddSeconds(int val)
        {
            if (seconds + val >= 60)
            {
                AddMinutes(val / 60);
                seconds = (val % 60);
            }
            else
            {
                seconds += val;
            }
        }
        /// <summary>
        /// Adds the passed minute value to the timestamp
        /// </summary>
        /// <param name="val">Added minutes</param>
        private void AddMinutes(int val)
        {
            if (minutes + val >= 60)
            {
                AddMinutes(val / 60);
                minutes = (val % 60);
            }
            else
            {
                minutes += val;
            }
        }
        /// <summary>
        /// Adds the passed hour value to the timestamp
        /// </summary>
        /// <param name="val">Added hours</param>
        private void AddHours(int val)
        {
            if (minutes + val >= 24)
            {
                AddDays (val / 24);
                minutes = (val % 24);
            }
            else
            {
                minutes += val;
            }
        }
        /// <summary>
        /// Adds the passed days value to the timestamp
        /// </summary>
        /// <param name="val">Added days</param>
        private void AddDays(int val)
        {
            short dayCount = GetDayMaxDaysOfMonth(month, year);
            if (dayOfMonth + val > dayCount)
            {
                AddMonths(val / dayCount);
                dayOfMonth = (val % dayCount);
            }
            else
            {
                dayOfMonth += val;
            }
        }
        /// <summary>
        /// Adds the passed month value to the timestamp
        /// </summary>
        /// <param name="val">Added months</param>
        private void AddMonths(int val)
        {
            if (month + val > 12)
            {
                AddYears(val / 12);
                month = (val % 12);
            }
            else
            {
                month += val;
            }
        }
        /// <summary>
        /// Adds the passed value to the year part of the time stamp
        /// </summary>
        /// <param name="val">Years to be added</param>
        private void AddYears(int val)
        {
            year += val;
        }

        /// <summary>
        /// Returns true if the the parameter matches this instance.
        /// </summary>
        /// <remarks>
        /// See <see cref="DoMatch"/>
        /// </remarks>
        /// <param name="other">The parameter to compare</param>
        /// <returns>true|false</returns>
        public override bool Equals(object o)
        {
            if (o is SyslogTimestamp)
            {
                return DoMatch((SyslogTimestamp)o, this);
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// Returns true if a & b match, else false.
        /// </summary>
        /// <remarks>
        /// Match criteria:
        /// (a.year == b.Year)
        /// && (a.month == b.Month)
        /// && (a.dayOfMonth == b.DayOfMonth)
        /// && (a.hours == b.Hours)
        /// && (a.minutes == b.Minutes)
        /// && (a.seconds == b.Seconds)
        /// && (a.miliseconds == b.Miliseconds)
        /// && (a.utcOffset == b.UtcOffset);
        /// </remarks>
        public static bool DoMatch(SyslogTimestamp a, SyslogTimestamp b)
        {
            bool doMatch = (a.year == b.Year)
                && (a.month == b.Month)
                && (a.dayOfMonth == b.DayOfMonth)
                && (a.hours == b.Hours)
                && (a.minutes == b.Minutes)
                && (a.seconds == b.Seconds)
                && (a.miliseconds == b.Miliseconds)
                && (a.utcOffset == b.UtcOffset);

            return doMatch;
        }
        /// <summary>
        /// The overloaded == operator
        /// </summary>
        /// <remarks>
        /// see http://msdn.microsoft.com/en-us/library/ms173147(v=vs.80).aspx
        /// </remarks>
        public static bool operator ==(SyslogTimestamp a, SyslogTimestamp b)
        {
            // If both are null, or both are same instance, return true.
            if (System.Object.ReferenceEquals(a, b))
            {
                return true;
            }

            // If one is null, but not both, return false.
            if (((object)a == null) || ((object)b == null))
            {
                return false;
            }

            return DoMatch(a, b);
        }
        /// <summary>
        /// The overloaded != operator.
        /// </summary>
        /// <remarks>
        /// see http://msdn.microsoft.com/en-us/library/ms173147(v=vs.80).aspx
        /// </remarks>
        public static bool operator !=(SyslogTimestamp a, SyslogTimestamp b)
        {
            return !(a == b);
        }
        /// <summary>
        /// The smaller than Operator
        /// compares every date|time related field with
        /// the other and returns true if the left hand side of
        /// the assignement is smaller than the right hand side
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator <(SyslogTimestamp a, SyslogTimestamp b)
        {
            if (a.Year < b.Year) { return true; }
            if (a.Year > b.Year) { return false; }

            if (a.Month < b.Month) { return true; }
            if (a.Month > b.Month) { return false; }

            if (a.DayOfMonth < b.DayOfMonth) { return true; }
            if (a.DayOfMonth > b.DayOfMonth) { return false; }

            if ((a.Hours + a.UtcOffset) < (b.Hours + b.UtcOffset)) { return true; }
            if ((a.Hours + a.UtcOffset) > (b.Hours + b.UtcOffset)) { return false; }

            if (a.Minutes < b.Minutes) { return true; }
            if (a.Minutes > b.Minutes) { return false; }

            if (a.Seconds < b.Seconds) { return true; }
            if (a.Seconds > b.Seconds) { return false; }

            if (a.Miliseconds < b.Miliseconds) { return true; }
            if (a.Miliseconds > b.Miliseconds) { return false; }

            return false;
        }
        /// <summary>
        /// The greater than Operator
        /// compares every date|time related field with
        /// the other and returns true if the left hand side of
        /// the assignement is greater than the right hand side
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator >(SyslogTimestamp a, SyslogTimestamp b)
        {
            if (a.Year > b.Year) { return true; }
            if (a.Year < b.Year) { return false; }

            if (a.Month > b.Month) { return true; }
            if (a.Month < b.Month) { return false; }

            if (a.DayOfMonth > b.DayOfMonth) { return true; }
            if (a.DayOfMonth < b.DayOfMonth) { return false; }

            if ((a.Hours + a.UtcOffset) > (b.Hours + b.UtcOffset)) { return true; }
            if ((a.Hours + a.UtcOffset) < (b.Hours + b.UtcOffset)) { return false; }

            if (a.Minutes > b.Minutes) { return true; }
            if (a.Minutes < b.Minutes) { return false; }

            if (a.Seconds > b.Seconds) { return true; }
            if (a.Seconds < b.Seconds) { return false; }

            if (a.Miliseconds > b.Miliseconds) { return true; }
            if (a.Miliseconds < b.Miliseconds) { return false; }

            return false;
        }
        /// <summary>
        /// greater or equal Operator
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns>(a > b) || DoMatch(a, b)</returns>
        public static bool operator >=(SyslogTimestamp a, SyslogTimestamp b) 
        {
            return (a > b) || DoMatch(a, b);
        }
        /// <summary>
        /// smaller or equal Operator
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns><code>(a { b) || DoMatch(a, b)</code></returns>
        public static bool operator <=(SyslogTimestamp a, SyslogTimestamp b)
        {
            return (a < b) || DoMatch(a, b);
        }

        /// <summary>
        /// Returns the Hash code of the object
        /// </summary>
        /// <returns>Hash code</returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }
}


Of course I have Unit Tests to check the integrity of the data handling within that class:
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Springlog.Com.Messaging;

namespace Springlog.Com.Messaging.UnitTests
{
    [TestClass]
    public class SyslogTimestampUnitTest
    {
        [TestMethod]
        public void SyslogTimestampComparisonIntegrity()
        {
            SyslogTimestamp timestamp1 = new SyslogTimestamp();
            SyslogTimestamp timestamp2 = new SyslogTimestamp();
            SyslogTimestamp timestamp3 = new SyslogTimestamp();
            SyslogTimestamp timestamp4 = new SyslogTimestamp();

            timestamp1.FromDateTime(DateTime.Now);
            timestamp2.FromDateTime(DateTime.Now.AddDays(-1));
            timestamp3 = timestamp1;
            timestamp4.FromDateTime(DateTime.Now.AddMinutes(2));

            Assert.AreEqual(true, (timestamp1 > timestamp2));
            Assert.AreEqual(true, (timestamp4 > timestamp1));
            Assert.AreEqual(false, (timestamp1 < timestamp2));
            Assert.AreEqual(true, (timestamp1 >= timestamp2));
            Assert.AreEqual(false, (timestamp1 <= timestamp2));
            Assert.AreEqual(true, (timestamp1 == timestamp3));
            Assert.AreEqual(false, (timestamp1 != timestamp3));
            Assert.AreEqual(false, (timestamp1 == timestamp4));
            Assert.AreEqual(false, (timestamp1 == timestamp2));
        }

        [TestMethod]
        public void SyslogTimestampStringConversionIntegrity()
        {
            DateTime now = DateTime.Now;
            SyslogTimestamp timestamp = new SyslogTimestamp();
            SyslogTimestamp timestamp2 = new SyslogTimestamp();
            timestamp.FromDateTime(now);
            timestamp.UtcOffset = 1;
            Assert.AreEqual(true, timestamp2.FromString(timestamp.ToFormattedString()));
            Assert.AreEqual(true, (timestamp2 == timestamp));
        }
    }
}


Now my question is: Can I achieve the same with System.DateTime?
I seriously doubt that, since System.DateTime's ParseExact method tends to have problems dealing with a variable amount of microseconds, and does not provide any field to store the UTC Offset.

Edit: I provided the new class implementation, since I have added various improvements.
Clean-up crew needed, grammar spill... - Nagy Vilmos


modified 5-Feb-14 8:52am.

AnswerRe: Sense of making my own Timestamp class? Pin
V.3-Feb-14 21:26
professionalV.3-Feb-14 21:26 
GeneralRe: Sense of making my own Timestamp class? Pin
Marco Bertschi3-Feb-14 21:35
protectorMarco Bertschi3-Feb-14 21:35 
GeneralRe: Sense of making my own Timestamp class? Pin
BillWoodruff4-Feb-14 12:43
professionalBillWoodruff4-Feb-14 12:43 
GeneralRe: Sense of making my own Timestamp class? Pin
Dave Kreskowiak4-Feb-14 13:42
mveDave Kreskowiak4-Feb-14 13:42 
AnswerRe: Sense of making my own Timestamp class? Pin
BillWoodruff4-Feb-14 3:56
professionalBillWoodruff4-Feb-14 3:56 
GeneralRe: Sense of making my own Timestamp class? Pin
Marco Bertschi4-Feb-14 4:03
protectorMarco Bertschi4-Feb-14 4:03 
AnswerRe: Sense of making my own Timestamp class? Pin
jschell4-Feb-14 13:20
jschell4-Feb-14 13:20 
GeneralRe: Sense of making my own Timestamp class? Pin
Marco Bertschi4-Feb-14 20:07
protectorMarco Bertschi4-Feb-14 20:07 
AnswerRe: Sense of making my own Timestamp class? Pin
TnTinMn6-Feb-14 12:37
TnTinMn6-Feb-14 12:37 
GeneralRe: Sense of making my own Timestamp class? Pin
Marco Bertschi6-Feb-14 21:12
protectorMarco Bertschi6-Feb-14 21:12 
GeneralRe: Sense of making my own Timestamp class? Pin
TnTinMn9-Feb-14 10:29
TnTinMn9-Feb-14 10:29 
GeneralRe: Sense of making my own Timestamp class? Pin
Marco Bertschi9-Feb-14 19:56
protectorMarco Bertschi9-Feb-14 19:56 
GeneralRe: Sense of making my own Timestamp class? Pin
TnTinMn10-Feb-14 13:12
TnTinMn10-Feb-14 13:12 
QuestionSSIS for Fixed Length line Pin
nitin_ion3-Feb-14 20:26
nitin_ion3-Feb-14 20:26 
AnswerRe: SSIS for Fixed Length line Pin
Bernhard Hiller3-Feb-14 20:52
Bernhard Hiller3-Feb-14 20:52 
GeneralRe: SSIS for Fixed Length line Pin
Marco Bertschi3-Feb-14 20:56
protectorMarco Bertschi3-Feb-14 20:56 
GeneralRe: SSIS for Fixed Length line Pin
nitin_ion3-Feb-14 21:46
nitin_ion3-Feb-14 21:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.