利用C#自定義一個(gè)時(shí)間類型YearMonth
在.Net Framework中,我們常用的時(shí)間類型是DateTime。直到.Net6微軟加入了兩個(gè)新的時(shí)間類型:DateOnly和TimeOnly,才彌補(bǔ)了之前的不足。
DateOnly:表示僅日期。比如:某人的生日,我只關(guān)心日期,就適合用DateOnly。
TimeOnly:表示僅時(shí)間。比如:每天定時(shí)執(zhí)行某個(gè)任務(wù),我只關(guān)心時(shí)間,就適合用TimeOnly。
由此可見,DateOnly和TimeOnly都有相應(yīng)的應(yīng)用場景??尚【幵趯?shí)際項(xiàng)目中遇到了這樣的業(yè)務(wù)場景:需要每月給客戶生成月賬單。這里我所關(guān)心的是某個(gè)月份,于是我首先想到用DateOnly表示(不考慮字符串)。
var date = new DateOnly(2023, 2, 1); // 代表2023年2月1日
雖然DateOnly可用,但從字面理解和表現(xiàn)形式上還是略顯尷尬。 DateOnly真正表達(dá)的是某一天并不是某個(gè)月, 在代碼層面也容易混淆,所以并不符合小編的心理期望。經(jīng)過一番糾結(jié)和思考,小編決定自己動手創(chuàng)建一個(gè)表示年/月的時(shí)間類型:YearMonth。
var ym = new YearMonth(2023, 2); // 代表2023年2月
YearMonth的源碼如下:
/// <summary>
/// 表示年/月的時(shí)間類型
/// </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時(shí)間類型已經(jīng)滿足小編的開發(fā)需要,當(dāng)然也可以根據(jù)需求繼續(xù)擴(kuò)展其它功能。
到此這篇關(guān)于利用C#自定義一個(gè)時(shí)間類型YearMonth的文章就介紹到這了,更多相關(guān)C#時(shí)間類型內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Unity中 ShaderGraph 實(shí)現(xiàn)超級炫酷的溶解效果入門級教程
這篇文章主要介紹了Unity中的 ShaderGraph 實(shí)現(xiàn)超級炫酷的溶解效果入門級教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-07-07
C#基于Whisper.net實(shí)現(xiàn)語音識別功能的示例詳解
在當(dāng)今數(shù)字化時(shí)代,語音識別技術(shù)已廣泛應(yīng)用于智能助手,語音轉(zhuǎn)文字,會議記錄等眾多領(lǐng)域,本文我們就來介紹一個(gè)強(qiáng)大的工具Whisper.net,看看如何在 C# 項(xiàng)目中利用它完成語音識別任務(wù)吧2025-06-06
C#使用Spire.PDF for .NET提取PDF文本的具體教程
在日常開發(fā)中,經(jīng)常會遇到從 PDF 文件中提取文本的需求,Spire.PDF for .NET 提供了簡單高效的 API,可以在 C# 項(xiàng)目中直接讀取 PDF 文本,無需安裝 Adobe Acrobat,所以本文給大家介紹了C#使用Spire.PDF for .NET提取PDF文本的具體教程,需要的朋友可以參考下2025-09-09
淺析C#中靜態(tài)方法和非靜態(tài)方法的區(qū)別
C#靜態(tài)方法與非靜態(tài)方法的區(qū)別不僅僅是概念上的,那么他們有什么具體的區(qū)別呢?讓我們通過本文向大家介紹下C#中靜態(tài)方法和非靜態(tài)方法的區(qū)別,一起看看吧2017-09-09
Unity UGUI實(shí)現(xiàn)滑動翻頁直接跳轉(zhuǎn)頁數(shù)
這篇文章主要為大家詳細(xì)介紹了Unity UGUI實(shí)現(xiàn)滑動翻頁,直接跳轉(zhuǎn)頁數(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04
Winform利用分頁控件實(shí)現(xiàn)導(dǎo)出PDF文檔功能
當(dāng)前的Winform分頁控件中,當(dāng)前導(dǎo)出的數(shù)據(jù)一般使用Excel來處理,但是有框架的使用客戶希望分頁控件能夠直接導(dǎo)出PDF,所以本文整理了一下分頁控件導(dǎo)出PDF的處理過程,分享一下2023-03-03

