답변:
다른 사람들이 말했듯이 a 를 사용 DateTime
하고 날짜를 무시하거나 a를 사용할 수 TimeSpan
있습니다. 개인적으로 나는이 솔루션 중 하나에 관심이 없습니다. 두 유형 모두 실제로 표현하려는 개념을 반영하지 않기 때문에 .NET의 날짜 / 시간 유형은 스파 스 측면에서 다소 시작된 이유 중 하나라고 생각합니다. 노다 시간 . Noda Time에서 LocalTime
유형을 사용하여 시간을 나타낼 수 있습니다 .
한 가지 고려해야 할 사항 : 하루 중 시간이 반드시 같은 날 자정 이후의 시간 길이는 아닙니다 ...
(또 다른 점으로, 상점 의 폐점 시간을 나타내려면 24:00, 즉 하루가 끝나는 시간을 나타내는 것이 좋습니다. Noda를 포함한 대부분의 날짜 / 시간 API 시간-시간 값으로 표시하지 마십시오.)
Duration
Noda Time 또는 TimeSpan
BCL. 아마도 "video + comment in place"를 유형으로 캡슐화 한 다음 해당 유형의 배열을 가질 것입니다.
기간 을 사용할 수 있습니다
TimeSpan timeSpan = new TimeSpan(2, 14, 18);
Console.WriteLine(timeSpan.ToString()); // Displays "02:14:18".
[편집]
다른 답변과 질문에 대한 편집을 고려할 때 여전히 TimeSpan을 사용합니다. 프레임 워크의 기존 구조로 충분하면 새 구조를 작성할 필요가 없습니다.
이 줄에서 많은 기본 데이터 유형이 복제됩니다.
TimeSpan
. 프레임 워크 자체에서 사용할 수있는 것이 가장 좋지만 유쾌하다고 말하는 것과 다릅니다.
그 빈칸이 Date
실제로 버그라면, 더 간단한 Time
구조 를 만들 수도 있습니다 :
// more work is required to make this even close to production ready
class Time
{
// TODO: don't forget to add validation
public int Hours { get; set; }
public int Minutes { get; set; }
public int Seconds { get; set; }
public override string ToString()
{
return String.Format(
"{0:00}:{1:00}:{2:00}",
this.Hours, this.Minutes, this.Seconds);
}
}
또는 귀찮게하는 이유 : 해당 정보로 계산할 필요가 없으면로 저장하십시오 String
.
TimeSpan
이 (가) 이미 존재 하고 상당히 개선 된 방식 으로 인해 귀하를 다운 보팅했습니다 .
DateTime을 사용한다고 말합니다. 날짜 부분이 필요하지 않으면 무시하십시오. 사용자에게 시간 만 표시해야하는 경우 다음과 같이 사용자에게 형식화 된 시간을 출력하십시오.
DateTime.Now.ToString("t"); // outputs 10:00 PM
새 클래스를 만들거나 TimeSpan을 사용하는 모든 추가 작업이 필요하지 않은 것 같습니다.
Rubens의 수업은 좋은 생각이라고 생각하므로 기본 유효성 검사를 사용하여 Time 클래스의 불변 샘플을 만들려고 생각했습니다.
class Time
{
public int Hours { get; private set; }
public int Minutes { get; private set; }
public int Seconds { get; private set; }
public Time(uint h, uint m, uint s)
{
if(h > 23 || m > 59 || s > 59)
{
throw new ArgumentException("Invalid time specified");
}
Hours = (int)h; Minutes = (int)m; Seconds = (int)s;
}
public Time(DateTime dt)
{
Hours = dt.Hour;
Minutes = dt.Minute;
Seconds = dt.Second;
}
public override string ToString()
{
return String.Format(
"{0:00}:{1:00}:{2:00}",
this.Hours, this.Minutes, this.Seconds);
}
}
Chibueze Opata 외에도 :
class Time
{
public int Hours { get; private set; }
public int Minutes { get; private set; }
public int Seconds { get; private set; }
public Time(uint h, uint m, uint s)
{
if(h > 23 || m > 59 || s > 59)
{
throw new ArgumentException("Invalid time specified");
}
Hours = (int)h; Minutes = (int)m; Seconds = (int)s;
}
public Time(DateTime dt)
{
Hours = dt.Hour;
Minutes = dt.Minute;
Seconds = dt.Second;
}
public override string ToString()
{
return String.Format(
"{0:00}:{1:00}:{2:00}",
this.Hours, this.Minutes, this.Seconds);
}
public void AddHours(uint h)
{
this.Hours += (int)h;
}
public void AddMinutes(uint m)
{
this.Minutes += (int)m;
while(this.Minutes > 59)
this.Minutes -= 60;
this.AddHours(1);
}
public void AddSeconds(uint s)
{
this.Seconds += (int)s;
while(this.Seconds > 59)
this.Seconds -= 60;
this.AddMinutes(1);
}
}
모든 기능을 갖춘 TimeOfDay 클래스가 있습니다.
이것은 간단한 경우에 과잉이지만, 내가 한 것처럼 고급 기능이 필요한 경우 도움이 될 수 있습니다.
코너 케이스, 일부 기본 수학, 비교, DateTime과의 상호 작용, 구문 분석 등을 처리 할 수 있습니다.
아래는 TimeOfDay 클래스의 소스 코드입니다. 사용 예를보고 여기에서 자세히 알아 보십시오 .
이 클래스는 대부분의 내부 계산 및 비교에 DateTime을 사용하므로 DateTime에 이미 포함 된 모든 지식을 활용할 수 있습니다.
// Author: Steve Lautenschlager, CambiaResearch.com
// License: MIT
using System;
using System.Text.RegularExpressions;
namespace Cambia
{
public class TimeOfDay
{
private const int MINUTES_PER_DAY = 60 * 24;
private const int SECONDS_PER_DAY = SECONDS_PER_HOUR * 24;
private const int SECONDS_PER_HOUR = 3600;
private static Regex _TodRegex = new Regex(@"\d?\d:\d\d:\d\d|\d?\d:\d\d");
public TimeOfDay()
{
Init(0, 0, 0);
}
public TimeOfDay(int hour, int minute, int second = 0)
{
Init(hour, minute, second);
}
public TimeOfDay(int hhmmss)
{
Init(hhmmss);
}
public TimeOfDay(DateTime dt)
{
Init(dt);
}
public TimeOfDay(TimeOfDay td)
{
Init(td.Hour, td.Minute, td.Second);
}
public int HHMMSS
{
get
{
return Hour * 10000 + Minute * 100 + Second;
}
}
public int Hour { get; private set; }
public int Minute { get; private set; }
public int Second { get; private set; }
public double TotalDays
{
get
{
return TotalSeconds / (24d * SECONDS_PER_HOUR);
}
}
public double TotalHours
{
get
{
return TotalSeconds / (1d * SECONDS_PER_HOUR);
}
}
public double TotalMinutes
{
get
{
return TotalSeconds / 60d;
}
}
public int TotalSeconds
{
get
{
return Hour * 3600 + Minute * 60 + Second;
}
}
public bool Equals(TimeOfDay other)
{
if (other == null) { return false; }
return TotalSeconds == other.TotalSeconds;
}
public override bool Equals(object obj)
{
if (obj == null) { return false; }
TimeOfDay td = obj as TimeOfDay;
if (td == null) { return false; }
else { return Equals(td); }
}
public override int GetHashCode()
{
return TotalSeconds;
}
public DateTime ToDateTime(DateTime dt)
{
return new DateTime(dt.Year, dt.Month, dt.Day, Hour, Minute, Second);
}
public override string ToString()
{
return ToString("HH:mm:ss");
}
public string ToString(string format)
{
DateTime now = DateTime.Now;
DateTime dt = new DateTime(now.Year, now.Month, now.Day, Hour, Minute, Second);
return dt.ToString(format);
}
public TimeSpan ToTimeSpan()
{
return new TimeSpan(Hour, Minute, Second);
}
public DateTime ToToday()
{
var now = DateTime.Now;
return new DateTime(now.Year, now.Month, now.Day, Hour, Minute, Second);
}
#region -- Static --
public static TimeOfDay Midnight { get { return new TimeOfDay(0, 0, 0); } }
public static TimeOfDay Noon { get { return new TimeOfDay(12, 0, 0); } }
public static TimeOfDay operator -(TimeOfDay t1, TimeOfDay t2)
{
DateTime now = DateTime.Now;
DateTime dt1 = new DateTime(now.Year, now.Month, now.Day, t1.Hour, t1.Minute, t1.Second);
TimeSpan ts = new TimeSpan(t2.Hour, t2.Minute, t2.Second);
DateTime dt2 = dt1 - ts;
return new TimeOfDay(dt2);
}
public static bool operator !=(TimeOfDay t1, TimeOfDay t2)
{
if (ReferenceEquals(t1, t2)) { return true; }
else if (ReferenceEquals(t1, null)) { return true; }
else
{
return t1.TotalSeconds != t2.TotalSeconds;
}
}
public static bool operator !=(TimeOfDay t1, DateTime dt2)
{
if (ReferenceEquals(t1, null)) { return false; }
DateTime dt1 = new DateTime(dt2.Year, dt2.Month, dt2.Day, t1.Hour, t1.Minute, t1.Second);
return dt1 != dt2;
}
public static bool operator !=(DateTime dt1, TimeOfDay t2)
{
if (ReferenceEquals(t2, null)) { return false; }
DateTime dt2 = new DateTime(dt1.Year, dt1.Month, dt1.Day, t2.Hour, t2.Minute, t2.Second);
return dt1 != dt2;
}
public static TimeOfDay operator +(TimeOfDay t1, TimeOfDay t2)
{
DateTime now = DateTime.Now;
DateTime dt1 = new DateTime(now.Year, now.Month, now.Day, t1.Hour, t1.Minute, t1.Second);
TimeSpan ts = new TimeSpan(t2.Hour, t2.Minute, t2.Second);
DateTime dt2 = dt1 + ts;
return new TimeOfDay(dt2);
}
public static bool operator <(TimeOfDay t1, TimeOfDay t2)
{
if (ReferenceEquals(t1, t2)) { return true; }
else if (ReferenceEquals(t1, null)) { return true; }
else
{
return t1.TotalSeconds < t2.TotalSeconds;
}
}
public static bool operator <(TimeOfDay t1, DateTime dt2)
{
if (ReferenceEquals(t1, null)) { return false; }
DateTime dt1 = new DateTime(dt2.Year, dt2.Month, dt2.Day, t1.Hour, t1.Minute, t1.Second);
return dt1 < dt2;
}
public static bool operator <(DateTime dt1, TimeOfDay t2)
{
if (ReferenceEquals(t2, null)) { return false; }
DateTime dt2 = new DateTime(dt1.Year, dt1.Month, dt1.Day, t2.Hour, t2.Minute, t2.Second);
return dt1 < dt2;
}
public static bool operator <=(TimeOfDay t1, TimeOfDay t2)
{
if (ReferenceEquals(t1, t2)) { return true; }
else if (ReferenceEquals(t1, null)) { return true; }
else
{
if (t1 == t2) { return true; }
return t1.TotalSeconds <= t2.TotalSeconds;
}
}
public static bool operator <=(TimeOfDay t1, DateTime dt2)
{
if (ReferenceEquals(t1, null)) { return false; }
DateTime dt1 = new DateTime(dt2.Year, dt2.Month, dt2.Day, t1.Hour, t1.Minute, t1.Second);
return dt1 <= dt2;
}
public static bool operator <=(DateTime dt1, TimeOfDay t2)
{
if (ReferenceEquals(t2, null)) { return false; }
DateTime dt2 = new DateTime(dt1.Year, dt1.Month, dt1.Day, t2.Hour, t2.Minute, t2.Second);
return dt1 <= dt2;
}
public static bool operator ==(TimeOfDay t1, TimeOfDay t2)
{
if (ReferenceEquals(t1, t2)) { return true; }
else if (ReferenceEquals(t1, null)) { return true; }
else { return t1.Equals(t2); }
}
public static bool operator ==(TimeOfDay t1, DateTime dt2)
{
if (ReferenceEquals(t1, null)) { return false; }
DateTime dt1 = new DateTime(dt2.Year, dt2.Month, dt2.Day, t1.Hour, t1.Minute, t1.Second);
return dt1 == dt2;
}
public static bool operator ==(DateTime dt1, TimeOfDay t2)
{
if (ReferenceEquals(t2, null)) { return false; }
DateTime dt2 = new DateTime(dt1.Year, dt1.Month, dt1.Day, t2.Hour, t2.Minute, t2.Second);
return dt1 == dt2;
}
public static bool operator >(TimeOfDay t1, TimeOfDay t2)
{
if (ReferenceEquals(t1, t2)) { return true; }
else if (ReferenceEquals(t1, null)) { return true; }
else
{
return t1.TotalSeconds > t2.TotalSeconds;
}
}
public static bool operator >(TimeOfDay t1, DateTime dt2)
{
if (ReferenceEquals(t1, null)) { return false; }
DateTime dt1 = new DateTime(dt2.Year, dt2.Month, dt2.Day, t1.Hour, t1.Minute, t1.Second);
return dt1 > dt2;
}
public static bool operator >(DateTime dt1, TimeOfDay t2)
{
if (ReferenceEquals(t2, null)) { return false; }
DateTime dt2 = new DateTime(dt1.Year, dt1.Month, dt1.Day, t2.Hour, t2.Minute, t2.Second);
return dt1 > dt2;
}
public static bool operator >=(TimeOfDay t1, TimeOfDay t2)
{
if (ReferenceEquals(t1, t2)) { return true; }
else if (ReferenceEquals(t1, null)) { return true; }
else
{
return t1.TotalSeconds >= t2.TotalSeconds;
}
}
public static bool operator >=(TimeOfDay t1, DateTime dt2)
{
if (ReferenceEquals(t1, null)) { return false; }
DateTime dt1 = new DateTime(dt2.Year, dt2.Month, dt2.Day, t1.Hour, t1.Minute, t1.Second);
return dt1 >= dt2;
}
public static bool operator >=(DateTime dt1, TimeOfDay t2)
{
if (ReferenceEquals(t2, null)) { return false; }
DateTime dt2 = new DateTime(dt1.Year, dt1.Month, dt1.Day, t2.Hour, t2.Minute, t2.Second);
return dt1 >= dt2;
}
/// <summary>
/// Input examples:
/// 14:21:17 (2pm 21min 17sec)
/// 02:15 (2am 15min 0sec)
/// 2:15 (2am 15min 0sec)
/// 2/1/2017 14:21 (2pm 21min 0sec)
/// TimeOfDay=15:13:12 (3pm 13min 12sec)
/// </summary>
public static TimeOfDay Parse(string s)
{
// We will parse any section of the text that matches this
// pattern: dd:dd or dd:dd:dd where the first doublet can
// be one or two digits for the hour. But minute and second
// must be two digits.
Match m = _TodRegex.Match(s);
string text = m.Value;
string[] fields = text.Split(':');
if (fields.Length < 2) { throw new ArgumentException("No valid time of day pattern found in input text"); }
int hour = Convert.ToInt32(fields[0]);
int min = Convert.ToInt32(fields[1]);
int sec = fields.Length > 2 ? Convert.ToInt32(fields[2]) : 0;
return new TimeOfDay(hour, min, sec);
}
#endregion
private void Init(int hour, int minute, int second)
{
if (hour < 0 || hour > 23) { throw new ArgumentException("Invalid hour, must be from 0 to 23."); }
if (minute < 0 || minute > 59) { throw new ArgumentException("Invalid minute, must be from 0 to 59."); }
if (second < 0 || second > 59) { throw new ArgumentException("Invalid second, must be from 0 to 59."); }
Hour = hour;
Minute = minute;
Second = second;
}
private void Init(int hhmmss)
{
int hour = hhmmss / 10000;
int min = (hhmmss - hour * 10000) / 100;
int sec = (hhmmss - hour * 10000 - min * 100);
Init(hour, min, sec);
}
private void Init(DateTime dt)
{
Init(dt.Hour, dt.Minute, dt.Second);
}
}
}
DateTime 또는 TimeSpan을 사용하지 않고 하루 중 시간 만 저장하려는 경우 자정 이후 초를 Int32에 저장하거나 자정 이후의 분 (초를 원하지 않는 경우)을 저장할 수 있습니다. Int16에 맞습니다. 그러한 값에서시, 분 및 초에 액세스하는 데 필요한 몇 가지 방법을 작성하는 것은 쉽지 않습니다.
DateTime / TimeSpan을 피할 수있는 유일한 이유는 구조의 크기가 중요한 경우입니다.
(물론 위와 같이 클래스에 싸여있는 간단한 구성표를 사용하는 경우 갑자기 이점을 줄 것이라는 점을 알게되면 스토리지를 TimeSpan으로 교체하는 것이 쉽지 않을 것입니다)