Reputation: 256841
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;
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.
Upvotes: 31
Views: 22846
Reputation: 141
No much difference compare to the accepted answer. Just to implement the idea.
public class TimeOfDay
{
public DateTime time;
public TimeOfDay(int Hour, int Minute, int Second)
{
time = DateTime.MinValue.Date.Add(new TimeSpan(Hour, Minute, Second));
}
}
Upvotes: 0
Reputation: 16411
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;
}
}
Upvotes: 8
Reputation: 20790
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.
Upvotes: 1
Reputation: 35216
Use a TimeSpan, and make it UTC if you have TimeZone issues.
Upvotes: 0
Reputation: 136697
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);
Upvotes: 6
Reputation: 9250
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.
Upvotes: 1
Reputation: 7437
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.
Upvotes: 3
Reputation: 17804
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.
Upvotes: 7
Reputation: 124746
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.
Upvotes: 4
Reputation: 1063298
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
.
Upvotes: 3