給C#新增一個時間類型: YearMonth

来源:https://www.cnblogs.com/fengjq/archive/2023/07/25/17578772.html
-Advertisement-
Play Games

在.Net Framework中,我們常用的時間類型是DateTime。直到.Net6微軟加入了兩個新的時間類型:DateOnly和TimeOnly,才彌補了之前的不足。 DateOnly:表示僅日期。比如:某人的生日,我只關心日期,就適合用DateOnly。 TimeOnly:表示僅時間。比如:每 ...


在.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的源碼如下:

  1  /// <summary>
  2  /// 表示年/月的時間類型
  3  /// </summary>
  4  [JsonConverter(typeof(YearMonthJsonConverter))]
  5  public readonly struct YearMonth
  6  {
  7      public int Year { get; }
  8 
  9      public int Month { get; }
 10 
 11      public YearMonth(int year, int month)
 12      {
 13          Year = year;
 14          Month = month;
 15      }
 16         
 17      public YearMonth AddMonths(int value)
 18      {
 19          var date = new DateOnly(Year, Month, 1);
 20          return FromDateOnly(date.AddMonths(value));
 21      }
 22 
 24      public YearMonth AddYears(int value)
 25      {
 26          var date = new DateOnly(Year, Month, 1);
 27          return FromDateOnly(date.AddYears(value));
 28      }
 29 
 30      public DateOnly FirstDay()
 31      {
 32          return new DateOnly(Year, Month, 1);
 33      }
 34 
 35      public DateOnly LastDay()
 36      {
 37          var nextMonth = AddMonths(1);
 38          var date = new DateOnly(nextMonth.Year, nextMonth.Month, 1);
 39          return date.AddDays(-1);
 40      }
 41 
 42      public int DaysInMonth()
 43      {
 44          return DateTime.DaysInMonth(Year, Month);
 45      }
 46 
 47      public static YearMonth Current 
 48      {
 49          get { return FromDateTime(DateTime.Now); }
 50      }
 51 
 52      public static YearMonth UtcCurrent
 53      {
 54          get { return FromDateTime(DateTime.UtcNow); }
 55      }
 56 
 57      public static YearMonth FromDateOnly(DateOnly dateOnly)
 58      {
 59          return new YearMonth(dateOnly.Year, dateOnly.Month);
 60      }
 61 
 62      public static YearMonth FromDateTime(DateTime dateTime)
 63      {
 64          return new YearMonth(dateTime.Year, dateTime.Month);
 65      }
 66         
 67      public static YearMonth FromString(string s)
 68      {
 69          if (DateTime.TryParse(s, out var date))
 70          {
 71              return FromDateTime(date);
 72          }
 73          throw new ArgumentException("format is error", nameof(s));
 74      }
 75 
 76      public override string ToString()
 77      {
 78          return $"{Year.ToString().PadLeft(4, '0')}-{Month.ToString().PadLeft(2, '0')}";
 79      }
 80 
 81      public static bool operator ==(YearMonth left, YearMonth right)
 82      {
 83          return left.Year == right.Year && left.Month == right.Month;
 84      }
 85 
 86      public static bool operator !=(YearMonth left, YearMonth right)
 87      {
 88          return !(left.Year == right.Year && left.Month == right.Month);
 89      }
 90 
 91      public static bool operator >=(YearMonth left, YearMonth right)
 92      {
 93          return (left.Year > right.Year) || (left.Year == right.Year && left.Month >= right.Month);
 94      }
 95 
 96      public static bool operator <=(YearMonth left, YearMonth right)
 97      {
 98          return (left.Year < right.Year) || (left.Year == right.Year && left.Month <= right.Month);
 99      }
100 
101      public static bool operator >(YearMonth left, YearMonth right)
102      {
103          return (left.Year > right.Year) || (left.Year == right.Year && left.Month > right.Month);
104      }
105 
106      public static bool operator <(YearMonth left, YearMonth right)
107      {
108          return (left.Year < right.Year) || (left.Year == right.Year && left.Month < right.Month);
109      }
110                
111      public override bool Equals(object obj)
112      {
113          return base.Equals(obj);
114      }
115 
116      public override int GetHashCode()
117      {
118          return base.GetHashCode();
119      }       
120 }

其中特性 [JsonConverter(typeof(YearMonthJsonConverter))]用於Json序列化和反序列化。

 1 public class YearMonthJsonConverter : JsonConverter<YearMonth>
 2 {
 3      public override YearMonth Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
 4      {
 5          return YearMonth.FromString(reader.GetString());
 6      }
 7 
 8      public override void Write(Utf8JsonWriter writer, YearMonth value, JsonSerializerOptions options)
 9      {
10          writer.WriteStringValue(value.ToString());
11      }
12 }

 YearMonth的一些用法示例:

1 var ym = new YearMonth(2023, 2);
2 int n = ym.DaysInMonth();     //n:28
3 DateOnly d1 = ym.FirstDay();  //d1:2023/2/1
4 DateOnly d2 = ym.LastDay();   //d2:2023/2/28
5 string str = ym.ToString();   //str:2023-02
6 YearMonth ym2 = ym.AddMonths(1);  //ym2: 2023-03
7 YearMonth ym3 = YearMonth.FromDateOnly(new DateOnly(2023, 2, 8)); //ym3: 2023-02 
8 YearMonth ym4 = YearMonth.FromDateTime(new DateTime(2023, 2, 8, 12, 23, 45)); //ym4: 2023-02
9 bool b = new YearMonth(2023, 3) > new YearMonth(2023, 2);  //b: true

  至此,上面的YearMonth時間類型已經滿足小編的開發需要,當然也可以根據需求繼續擴展其它功能。

 

 

本文已同步至作者的微信公眾號:玩轉DotNet

感謝點贊並關註


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ## 問題 面試官: > try-catch 到底寫在迴圈裡面好,還是外面好? 這個問題,我相信大部分人都會答錯! ## 到底寫在哪裡好? 很多人會說當然寫在迴圈外面好,也有一部分人說寫在迴圈裡面好,其實這兩種回答都不完全對,我們來分析下兩者的弊端。 **try-catch 寫在迴圈外面的弊端:** ...
  • # SpringMVC攔截器和異常處理機制 ## 概念 SpringMVC攔截器類似於過濾器,用於進行預處理和後處理 將攔截器按照一定順序連接成一條鏈,就是攔截器鏈 ## 攔截器和過濾器區別 ![](https://img2023.cnblogs.com/blog/2844064/202307/28 ...
  • ## 教程簡介 層疊樣式表(英文全稱:Cascading Style Sheets)是一種用來表現HTML(標準通用標記語言的一個應用)或XML(標準通用標記語言的一個子集)等文件樣式的電腦語言。CSS不僅可以靜態地修飾網頁,還可以配合各種腳本語言動態地對網頁各元素進行格式化。CSS 能夠對網頁中 ...
  • 轉載於作者Lucas汪星人:https://www.jianshu.com/p/9955b4f27501 在原先作者的基礎上根據我自己修改了一些代碼僅供參考: 首先需要引用NuGet包:ZXing.Net.Bindings.ZKWeb.System.Drawing 也可以使用終端開發者PowerSh ...
  • # Unity UGUI的EventSystem(事件系統)組件的介紹及使用 ## 1. 什麼是EventSystem組件? EventSystem是Unity UGUI中的一個重要組件,用於處理用戶輸入事件,如點擊、拖拽、滾動等。它負責將用戶輸入事件傳遞給合適的UI元素,並觸發相應的事件回調函數。 ...
  • # 1. 目錄 - [1. 目錄](#1-目錄) - [2. 前言](#2-前言) - [2.1. 日誌控制項的選擇](#21-日誌控制項的選擇) - [3. 日誌配置](#3-日誌配置) - [3.1. 控制台列印](#31-控制台列印) - [3.2. 文件列印](#32-文件列印) - [4. 結 ...
  • ### 任務超時取消 示例 ``` public static async Task TimeoutCancelTask() { CancellationTokenSource cts = new CancellationTokenSource();//取消令牌 Task task = DoActi ...
  • 最近有小伙伴問怎麼學好C#語言,他感覺總是學不好。小編這篇文章將介紹如何學好它,僅供參考。C#是 Microsoft 公司開發的一種新型、高效的面向對象的編程語言,雖然出現的時間並不長,但是其易於學習、語法規範、程式嚴密的特點已經受到了很多企業和開發者的青睞。所以,對於追求技術和編程方面的人來說,提 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...