tags:

views:

4850

answers:

13

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:

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

because there is no zero-th month or zero-th day.

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 it's 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.

A: 

I'd use SQL Server's zero date so it won't bite you later if you ever need to store the data.

Daniel Schaffer
That's a problem for your persistence code to worry about. I wouldn't worry about that in your business logic/presentation part.
Erik van Brakel
All else being equal (and in this case, it appears it is), why not just make it easier on yourself? Also, was giving me negative rep really necessary for this?
Daniel Schaffer
A: 

How about DateTime.Now.TimeOfDay, and use the TimeSpan?

Re "because that doesn't store times of the day." - well, it does if you think of a TimeSpan as the time since midnight.

A "duration", for example, screams TimeSpan.

Marc Gravell
Subtracting two DateTimes yields a TimeSpan.
Ian Boyd
+11  A: 

what about DateTime.MinValue?

Joachim Kerschbaumer
i like that the best, and not the hard-coded numbers, but add a timespan to the MinValue's Date.
Ian Boyd
+2  A: 

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.

Joe
+5  A: 

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.

Greg Hurlman
TimeSpan does not store a time of day. Updated question to show you why.
Ian Boyd
Just store it as UTC :)
Greg Hurlman
+1  A: 

I recommend DateTime.MinValue

Joel Coehoorn
A: 

I think it depends on the intended use. If you just want to show the user "2:00 PM", then DateTime.MinValue would be fine. If you need 2:00 on a certain date, then using a TimeSpan and adding it to a DateTime (using DateTime.Date) would be safer.

Jon B
+1  A: 

To display a TimeSpan formatted with local culture, simply add it to a date like DateTime.Today. Something like this:

(DateTime.Today + timeSpan).ToString();

Since your value really doesn't represent a date, you're better off storing it as a TimeSpan until the time comes to display it.

Neil Whitaker
+1  A: 

You can just create a new DateTime with a string literal.

String literal for time:

DateTime t = new DateTime("01:00:30");

String literal for date:

DateTime t = new DateTime("01/05/2008"); // english format
DateTime t = new DateTime("05.01.2008"); // german format

For a DateTime with date and time values:

DateTime t = new DateTime("01/05/2008T01:00:30");

In most cases, when creating a DateTime, i set it to DateTime.Now, if it is not actually set to anything else. If you instantiate an DateTime manually, you should beware of the DateTimeKind set correctly, otherwise this could lead to surprises.

BeowulfOF
+3  A: 

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);
Greg Beech
A: 

Use a TimeSpan, and make it UTC if you have TimeZone issues.

TheSoftwareJedi
+1  A: 

May I suggest that in some cases a custom struct could do? It could have an Int32 backing value (there are 86 milion milliseconds in a day; this would fit in an Int32).

There could be get-only properties :

Hours Minutes Seconds Milliseconds

You could also overload operators such as +, - and so on. Implement IEquatable, IComparable and whatever may be the case. Overload Equals, == . Overload and override ToString.

You could also provide more methods to construct from a DateTime or append to a datetime and so on.

Andrei Rinea
+5  A: 

Hi

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("Skal ligge i intervallet 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 enumerering - 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;
    }
}
Junior Mayhé
sorry the bad translation from the danish language!
Junior Mayhé