利用C#自定义一个时间类型YearMonth

 更新时间:2023年07月26日 08:52:14   作者:天行健君子以自强  
.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#时间类型内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Unity中 ShaderGraph 实现超级炫酷的溶解效果入门级教程

    Unity中 ShaderGraph 实现超级炫酷的溶解效果入门级教程

    这篇文章主要介绍了Unity中的 ShaderGraph 实现超级炫酷的溶解效果入门级教程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-07-07
  • C#基于Whisper.net实现语音识别功能的示例详解

    C#基于Whisper.net实现语音识别功能的示例详解

    在当今数字化时代,语音识别技术已广泛应用于智能助手,语音转文字,会议记录等众多领域,本文我们就来介绍一个强大的工具Whisper.net,看看如何在 C# 项目中利用它完成语音识别任务吧
    2025-06-06
  • C#利用缓存分块读写大文件

    C#利用缓存分块读写大文件

    这篇文章主要为大家详细介绍了C#利用缓存分块读写大文件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-05-05
  • C#: 引用变量与数值变量的区别

    C#: 引用变量与数值变量的区别

    在C#中主要存在两大类型的数据:引用类型(class)和值类型(struct)。本文探讨一下C#中引用变量和数值变量的区别。
    2013-03-03
  • C#使用Spire.PDF for .NET提取PDF文本的具体教程

    C#使用Spire.PDF for .NET提取PDF文本的具体教程

    在日常开发中,经常会遇到从 PDF 文件中提取文本的需求,Spire.PDF for .NET 提供了简单高效的 API,可以在 C# 项目中直接读取 PDF 文本,无需安装 Adobe Acrobat,所以本文给大家介绍了C#使用Spire.PDF for .NET提取PDF文本的具体教程,需要的朋友可以参考下
    2025-09-09
  • C#写差异文件备份工具的示例

    C#写差异文件备份工具的示例

    这篇文章主要介绍了C#写差异文件备份工具的示例,帮助大家利用c#备份,管理文件,感兴趣的朋友可以了解下
    2020-10-10
  • C#中 城市线路图的纯算法以及附带求极权值

    C#中 城市线路图的纯算法以及附带求极权值

    本篇文章介绍了,在C#中城市线路图的纯算法以及附带求极权值的方法,需要的朋友参考下
    2013-04-04
  • 浅析C#中静态方法和非静态方法的区别

    浅析C#中静态方法和非静态方法的区别

    C#静态方法与非静态方法的区别不仅仅是概念上的,那么他们有什么具体的区别呢?让我们通过本文向大家介绍下C#中静态方法和非静态方法的区别,一起看看吧
    2017-09-09
  • Unity UGUI实现滑动翻页直接跳转页数

    Unity UGUI实现滑动翻页直接跳转页数

    这篇文章主要为大家详细介绍了Unity UGUI实现滑动翻页,直接跳转页数,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-04-04
  • Winform利用分页控件实现导出PDF文档功能

    Winform利用分页控件实现导出PDF文档功能

    当前的Winform分页控件中,当前导出的数据一般使用Excel来处理,但是有框架的使用客户希望分页控件能够直接导出PDF,所以本文整理了一下分页控件导出PDF的处理过程,分享一下
    2023-03-03

最新评论