C# DateTime: What "date" to use when I'm using just the "time"?

22,557

Solution 1

what about DateTime.MinValue?

Solution 2

Let's help out the guys who want a Time structure:

/// <summary>
/// Time structure
/// </summary>
public struct Time : IComparable
{
    private int minuteOfDay;
    public static Time Midnight = "0:00";
    private static int MIN_OF_DAY = 60 * 24;

    public Time(int minuteOfDay)
    {
        if (minuteOfDay >= (60 * 24) || minuteOfDay < 0)
            throw new ArgumentException("Must be in the range 0-1439", "minuteOfDay");
        this.minuteOfDay = minuteOfDay;
    }

    public Time(int hour, int minutes)
    {
        if (hour < 0 || hour > 23)
            throw new ArgumentException("Must be in the range 0-23", "hour");
        if (minutes < 0 || minutes > 59)
            throw new ArgumentException("Must be in the range 0-59", "minutes");

        minuteOfDay = (hour * 60) + minutes;
    }

    #region Operators
    public static implicit operator Time(string s)
    {
        var parts = s.Split(':');
        if (parts.Length != 2)
            throw new ArgumentException("Time must be specified on the form tt:mm");
        return new Time(int.Parse(parts[0]), int.Parse(parts[1]));
    }


    public static bool operator >(Time t1, Time t2)
    {
        return t1.MinuteOfDay > t2.MinuteOfDay;
    }
    public static bool operator <(Time t1, Time t2)
    {
        return t1.MinuteOfDay < t2.MinuteOfDay;
    }
    public static bool operator >=(Time t1, Time t2)
    {
        return t1.MinuteOfDay >= t2.MinuteOfDay;
    }
    public static bool operator <=(Time t1, Time t2)
    {
        return t1.MinuteOfDay <= t2.MinuteOfDay;
    }
    public static bool operator ==(Time t1, Time t2)
    {
        return t1.GetHashCode() == t2.GetHashCode();
    }
    public static bool operator !=(Time t1, Time t2)
    {
        return t1.GetHashCode() != t2.GetHashCode();
    }

    /// Time
    /// Minutes that remain to
    /// Time conferred minutes
    public static Time operator +(Time t, int min)
    {
        if (t.minuteOfDay + min < (24 * 60))
        {
            t.minuteOfDay += min;
            return t;
        }
        else
        {
            t.minuteOfDay = (t.minuteOfDay + min) % MIN_OF_DAY;
            return t;
        }
    }

    public static Time operator -(Time t, int min)
    {
        if (t.minuteOfDay - min > -1)
        {
            t.minuteOfDay -= min;
            return t;
        }
        else
        {
            t.minuteOfDay = MIN_OF_DAY + (t.minuteOfDay - min);
            return t;
        }
    }

    public static TimeSpan operator -(Time t1, Time t2)
    {
        return TimeSpan.FromMinutes(Time.Span(t2, t1));
    }
    #endregion


    public int Hour
    {
        get
        {
            return (int)(minuteOfDay / 60);
        }
    }
    public int Minutes
    {
        get
        {
            return minuteOfDay % 60;
        }
    }


    public int MinuteOfDay
    {
        get { return minuteOfDay; }
    }

    public Time AddHours(int hours)
    {
        return this + (hours * 60);
    }

    public int CompareTo(Time other)
    {
        return this.minuteOfDay.CompareTo(other.minuteOfDay);
    }

    #region Overrides
    public override int GetHashCode()
    {
        return minuteOfDay.GetHashCode();
    }

    public override string ToString()
    {
        return string.Format("{0}:{1:00}", Hour, Minutes);
    }
    #endregion

    /// 
    /// Safe enumerering - whatever interval applied max days 
    /// 
    /// Start time
    /// Spring in minutes
    /// 
    public static IEnumerable Range(Time start, int step)
    {
        return Range(start, start, step);
    }

    /// 
    /// Safe enumeration - whatever interval applied max days
    /// 
    public static IEnumerable Range(Time start, Time stop, int step)
    {
        int offset = start.MinuteOfDay;
        for (var i = 0; i < Time.Span(start, stop); i += step)
        {
            yield return Time.Midnight + (i + offset);
        }
    }

    /// 
    /// Calculates the number of minutes between t1 and t2
    /// 
    public static int Span(Time t1, Time t2)
    {
        if (t1 < t2) // same day
            return t2.MinuteOfDay - t1.MinuteOfDay;
        else // over midnight
            return MIN_OF_DAY - t1.MinuteOfDay + t2.MinuteOfDay;
    }
}

Solution 3

A TimeSpan most certainly can store the time of the day - you just have to treat the value as the amount of time elapsed since midnight, basically the same way we read a clock.

Solution 4

Personally I'd create a custom Time struct that contains a DateTime instance, and which has similar properties, constructors etc. but doesn't expose days/months/etc. Just make all your public accessors pass through to the contained instance. Then you can simply have the epoch as a private static readonly DateTime field and it doesn't matter what value you choose as it's all neatly contained within your custom struct. In the rest of your code can simply write:

var time = new Time(16, 47, 58);

Solution 5

Given that DateTime.TimeOfDay returns a TimeSpan, I'd use that.

Why can't you use a TimeSpan? I don't understand your comment that it doesn't store times of day.

Share:
22,557
mistertodd
Author by

mistertodd

Any code is public domain. No attribution required. జ్ఞా &lt;sup&gt;🕗&lt;/sup&gt;🕗 Yes, i do write i with a lowercase i. The Meta Stackexchange answer that I am most proud of

Updated on November 13, 2020

Comments

  • mistertodd
    mistertodd over 3 years

    I'm using a DateTime in C# to display times. What date portion does everyone use when constructing a time?

    E.g. the following is not valid because there is no zero-th month or zero-th day:

    // 4:37:58 PM
    DateTime time = new DateTime(0, 0, 0, 16, 47, 58);
    

    Do I use COM's zero date?

    // 4:37:58 PM
    DateTime time = new DateTime(1899, 12, 30, 16, 47, 58);
    

    Or perhaps SQL Server's?

    //4:37:58 PM
    DateTime time = new DateTime(1900, 1, 1, 16, 47, 58);
    

    I realize it's arbitrary, since I'll be ignoring the date portions in code, but it would still be nice to be able to use:

    DateTime duration = time2 - time1;
    

    Answer

    I think I like MinValue

     DateTime time = DateTime.MinValue.Date.Add(new TimeSpan(16, 47, 58));
    

    Note: I can't use a TimeSpan, because that doesn't store times of the day. And the reason I know that is because there's no way to display its contents as a time.

    Which is to say that TimeSpan records a span of time, not a time of day, e.g.:

    TimeSpan t = new TimeSpan(16, 47, 58);
    t.ToString();
    

    returns a span of time in the format hours:minutes:seconds, e.g.:

    16:47:58
    

    rather than a time:

    4:47:58 PM    (United States)
    04:47:58 nm   (South Africa)
    4:47:58.MD    (Albania)
    16:47:58      (Algeria)
    04:47:58 م    (Bahrain)
    PM 4:47:58    (Singapore)
    下午 04:47:58  (Taiwan)
    04:47:58 PM   (Belize)
    4:47:58 p.m.  (New Zealand)
    4:47:58 μμ    (Greece)
    16.47.58      (Italy)
    오후 4:47:58   (Korea)
    04:47:58 ب.ظ  (Iran)
    ਸ਼ਾਮ 04:47:58   (India)
    04:47:58 p.m. (Argentina)
    etc
    

    In other words, there is a difference between a timespan, and a time. And also realize that TimeSpan doesn't provide a mechanism to convert a span of time into a time of day - and there is a reason for that.