利用C#自定义一个时间类型YearMonth
作者:天行健君子以自强
.Net6中加入了两个新的时间类型:DateOnly和TimeOnly,但DateOnly和TimeOnly都有相应的应用场景,所以本文就来自定义一个时间类型YearMonth,用于解决实际项目开发中的需求,希望对大家有所帮助
在.Net Framework中,我们常用的时间类型是DateTime。直到.Net6微软加入了两个新的时间类型:DateOnly和TimeOnly,才弥补了之前的不足。
DateOnly:表示仅日期。比如:某人的生日,我只关心日期,就适合用DateOnly。
TimeOnly:表示仅时间。比如:每天定时执行某个任务,我只关心时间,就适合用TimeOnly。
由此可见,DateOnly和TimeOnly都有相应的应用场景。可小编在实际项目中遇到了这样的业务场景:需要每月给客户生成月账单。这里我所关心的是某个月份,于是我首先想到用DateOnly表示(不考虑字符串)。
var date = new DateOnly(2023, 2, 1); // 代表2023年2月1日
虽然DateOnly可用,但从字面理解和表现形式上还是略显尴尬。 DateOnly真正表达的是某一天并不是某个月, 在代码层面也容易混淆,所以并不符合小编的心理期望。经过一番纠结和思考,小编决定自己动手创建一个表示年/月的时间类型:YearMonth。
var ym = new YearMonth(2023, 2); // 代表2023年2月
YearMonth的源码如下:
/// <summary>
/// 表示年/月的时间类型
/// </summary>
[JsonConverter(typeof(YearMonthJsonConverter))]
public readonly struct YearMonth
{
public int Year { get; }
public int Month { get; }
public YearMonth(int year, int month)
{
Year = year;
Month = month;
}
public YearMonth AddMonths(int value)
{
var date = new DateOnly(Year, Month, 1);
return FromDateOnly(date.AddMonths(value));
}
public YearMonth AddYears(int value)
{
var date = new DateOnly(Year, Month, 1);
return FromDateOnly(date.AddYears(value));
}
public DateOnly FirstDay()
{
return new DateOnly(Year, Month, 1);
}
public DateOnly LastDay()
{
var nextMonth = AddMonths(1);
var date = new DateOnly(nextMonth.Year, nextMonth.Month, 1);
return date.AddDays(-1);
}
public int DaysInMonth()
{
return DateTime.DaysInMonth(Year, Month);
}
public static YearMonth Current
{
get { return FromDateTime(DateTime.Now); }
}
public static YearMonth UtcCurrent
{
get { return FromDateTime(DateTime.UtcNow); }
}
public static YearMonth FromDateOnly(DateOnly dateOnly)
{
return new YearMonth(dateOnly.Year, dateOnly.Month);
}
public static YearMonth FromDateTime(DateTime dateTime)
{
return new YearMonth(dateTime.Year, dateTime.Month);
}
public static YearMonth FromString(string s)
{
if (DateTime.TryParse(s, out var date))
{
return FromDateTime(date);
}
throw new ArgumentException("format is error", nameof(s));
}
public override string ToString()
{
return $"{Year.ToString().PadLeft(4, '0')}-{Month.ToString().PadLeft(2, '0')}";
}
public static bool operator ==(YearMonth left, YearMonth right)
{
return left.Year == right.Year && left.Month == right.Month;
}
public static bool operator !=(YearMonth left, YearMonth right)
{
return !(left.Year == right.Year && left.Month == right.Month);
}
public static bool operator >=(YearMonth left, YearMonth right)
{
return (left.Year > right.Year) || (left.Year == right.Year && left.Month >= right.Month);
}
public static bool operator <=(YearMonth left, YearMonth right)
{
return (left.Year < right.Year) || (left.Year == right.Year && left.Month <= right.Month);
}
public static bool operator >(YearMonth left, YearMonth right)
{
return (left.Year > right.Year) || (left.Year == right.Year && left.Month > right.Month);
}
public static bool operator <(YearMonth left, YearMonth right)
{
return (left.Year < right.Year) || (left.Year == right.Year && left.Month < right.Month);
}
public override bool Equals(object obj)
{
return base.Equals(obj);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}其中特性 [JsonConverter(typeof(YearMonthJsonConverter))]用于Json序列化和反序列化。
public class YearMonthJsonConverter : JsonConverter<YearMonth>
{
public override YearMonth Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return YearMonth.FromString(reader.GetString());
}
public override void Write(Utf8JsonWriter writer, YearMonth value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString());
}
}YearMonth的一些用法示例:
var ym = new YearMonth(2023, 2); int n = ym.DaysInMonth(); //n:28 DateOnly d1 = ym.FirstDay(); //d1:2023/2/1 DateOnly d2 = ym.LastDay(); //d2:2023/2/28 string str = ym.ToString(); //str:2023-02 YearMonth ym2 = ym.AddMonths(1); //ym2: 2023-03 YearMonth ym3 = YearMonth.FromDateOnly(new DateOnly(2023, 2, 8)); //ym3: 2023-02 YearMonth ym4 = YearMonth.FromDateTime(new DateTime(2023, 2, 8, 12, 23, 45)); //ym4: 2023-02 bool b = new YearMonth(2023, 3) > new YearMonth(2023, 2); //b: true
至此,上面的YearMonth时间类型已经满足小编的开发需要,当然也可以根据需求继续扩展其它功能。
到此这篇关于利用C#自定义一个时间类型YearMonth的文章就介绍到这了,更多相关C#时间类型内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
