作者: 轩墨玉生烟
查看: 931|回复: 9

【代码】一个BigDate类的实现

[复制链接]
轩墨玉生烟 发表于 2016-5-5 22:57:08 | 显示全部楼层 |阅读模式
查看: 931|回复: 9
有的时候,可能需要用到一个很大的日期类,那么该怎么实现呢?下面就奉上我的源代码,里面实现了一些常用的功能:
[C#] 纯文本查看 复制代码
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace Cabinink.Writer.Cores
{
   public class BigDate
   {
      protected int year;//范围:公元前6000至公元2147483647年
      protected byte month;
      protected byte day;
      public BigDate()
      {
         year = DateTime.Now.Year;
         month = (byte)DateTime.Now.Month;
         day = (byte)DateTime.Now.Day;
      }
      public BigDate(DateTime _date)
      {
         year = _date.Year;
         month = (byte)_date.Month;
         day = (byte)_date.Day;
      }
      public BigDate(int _year, byte _month, byte _day)
      {
         if (_year < MinimumYear && _year > MaximumYear) throw new DateOverflowException("年份超出范围!");
         if (_month < 1 && _month > 12) throw new DateOverflowException("月份超出范围!");
         if (_day < 1 && _day > MaximumDays) throw new DateOverflowException("天数超出当前月份所包含天数的范围");
         year = _year;
         month = _month;
         day = _day;
      }
      public static int MaximumYear  //获取BigDate能够表示的最大年份
      {
         get { return int.MaxValue; }
      }
      public static int MinimumYear  //获取BigDate能够表示的最小年份
      {
         get { return -6000; }
      }
      public byte MaximumDays //获取当前实例中指定的月份的最大天数
      {
         get
         {
            byte maxdays = 30;
            switch (Month)
            {
               case 1:
               case 3:
               case 5:
               case 7:
               case 8:
               case 10:
               case 12:
                  maxdays = 31;
                  break;
               case 4:
               case 6:
               case 9:
               case 11:
                  maxdays = 30;
                  break;
               case 2:
                  if (IsIntercalaryYear()) maxdays = 29; else maxdays = 28;
                  break;
            }
            return maxdays;
         }
      }
      public int Year
      {
         get { return year; }
         set
         {
            if (value < MinimumYear && value > MaximumYear) throw new DateOverflowException("年份超出范围!");
            year = value;
         }
      }
      public byte Month
      {
         get { return month; }
         set
         {
            if (value < 1 && value > 12) throw new DateOverflowException("月份超出范围!");
            month = value;
         }
      }
      public byte Day
      {
         get { return day; }
         set
         {
            if (value < 1 && value > MaximumDays) throw new DateOverflowException("天数超出当前月份所包含天数的范围");
            day = value;
         }
      }
      public ulong DaysBeginWithMinimumYear  //获取当前实例的日期是从-6000年01月01日开始的第几天
      {
         get
         {
            ulong days = 0;
            int leapyear_count = 0;
            days = (ulong)Math.Abs(MinimumYear) * 365 + (ulong)Year * 365;
            if (IsIntercalaryYear()) days += (ulong)new DateTime(2008, Month, Day).DayOfYear;
            else days += (ulong)new DateTime(2010, Month, Day).DayOfYear;
            for (int i = MinimumYear; i <= Year; i++)
            {
               if (new BigDate(i, 1, 1).IsIntercalaryYear()) ++leapyear_count;
            }
            return days + (ulong)leapyear_count;
         }
      }
      public bool IsIntercalaryYear()  //判定当前实例所示年份是否属于闰年
      {
         return DateTime.IsLeapYear(Year);
      }
      public List<int> CompareOfYear(BigDate _diffdate) //将两个年份按照从小到大的顺序排列,若执行成功,则会返回一个有顺序的年份列表。
      {
         return Year >= _diffdate.Year ? new int[] { _diffdate.Year, Year }.ToList() : new int[] { Year, _diffdate.Year }.ToList();
      }
      /// <summary>
      /// 将两个日期按照年份从小到大的顺序排列
      /// </summary>
      /// <param name="_diffdate">指定的BigDate实例。</param>
      /// <returns>若执行成功,则会返回一个有顺序的DateTime年份列表。</returns>
      public List<DateTime> CompareOfDateTime(BigDate _diffdate)
      {
         return Year >= _diffdate.Year ? new DateTime[]
         {
            new DateTime(_diffdate.Year, _diffdate.Month, _diffdate.Day),
            new DateTime(Year, Month, Day)
         }
         .ToList() :
         new DateTime[]
         {
            new DateTime(Year, Month, Day),
            new DateTime(_diffdate.Year, _diffdate.Month, _diffdate.Day)
         }.ToList();
      }
      public List<int> GetIntercalaryYears(BigDate _diffdate)  //获取指定范围之间的闰年年份
      {
         List<int> leaps = new List<int>();
         if (Math.Abs(CompareOfYear(_diffdate)[0] - CompareOfYear(_diffdate)[1]) < 2)
         {
            throw new DifferenceTooSmallException("指定范围的年份差的绝对值不能小于2!");
         }
         Parallel.For(CompareOfYear(_diffdate)[0], CompareOfYear(_diffdate)[1] + 1, (index) =>
         {
            if (new BigDate(index, 1, 1).IsIntercalaryYear()) leaps.Add(index);
         });
         leaps.Sort();
         return leaps;
      }
      /// <summary>
      /// 计算指定日期与当前日期之间的天数差
      /// </summary>
      /// <param name="_diffdate">指定的与当前日期有差别的日期。</param>
      /// <returns>如果这个方法未抛出异常,则会返回两个日期之间的天数差的UInt64表示形式。</returns>
      public ulong GetDifferenceOfDay(BigDate _diffdate)
      {
         return (ulong)Math.Abs(DaysBeginWithMinimumYear - (decimal)_diffdate.DaysBeginWithMinimumYear);
      }
      /// <summary>
      /// 获取当前实例的指定格式的字符串
      /// </summary>
      /// <param name="_category">指定的格式,即显示方式。</param>
      /// <returns>该操作将会返回这个实例的字符串形式,但是这个字符串是一个有使用意义的字符串。</returns>
      public string ToString(EDateDisplayCategory _category)
      {
         string datest = string.Empty;
         switch (_category)
         {
            case EDateDisplayCategory.OnlySerial:
               datest = Year.ToString() + Month.ToString("D2") + Day.ToString("D2");
               break;
            case EDateDisplayCategory.SolidusSegmentation:
               datest = Year.ToString() + "/" + Month.ToString("D2") + "/" + Day.ToString("D2");
               break;
            case EDateDisplayCategory.DashedSegmentation:
               datest = Year.ToString() + "-" + Month.ToString("D2") + "-" + Day.ToString("D2");
               break;
            case EDateDisplayCategory.PointSegmentation:
               datest = Year.ToString() + "." + Month.ToString("D2") + "." + Day.ToString("D2");
               break;
            case EDateDisplayCategory.VolnaSegmentation:
               datest = Year.ToString() + "~" + Month.ToString("D2") + "~" + Day.ToString("D2");
               break;
            case EDateDisplayCategory.ChineseSegmentation:
               datest = Year.ToString() + "年" + Month.ToString("D2") + "月" + Day.ToString("D2") + "日";
               break;
            default:
               datest = Year.ToString() + Month.ToString("D2") + Day.ToString("D2");
               break;
         }
         return datest;
      }
      public override string ToString()
      {
         return "Cabinink.Writer.Cores.BigDate";
      }
   }
   public enum EDateDisplayCategory : int   //日期显示方式的枚举
   {
      /// <summary>
      /// 序列表示
      /// </summary>
      OnlySerial = 0x0000,
      /// <summary>
      /// 斜线符号分割
      /// </summary>
      SolidusSegmentation = 0x0001,
      /// <summary>
      /// 短横线符号分割
      /// </summary>
      DashedSegmentation = 0x0002,
      /// <summary>
      /// 句点符号分割
      /// </summary>
      PointSegmentation = 0x0003,
      /// <summary>
      /// 波浪号分割
      /// </summary>
      VolnaSegmentation = 0x0004,
      /// <summary>
      /// 中文单位分割
      /// </summary>
      ChineseSegmentation = 0x0006
   }
   /// <summary>
   /// 大型日期任意成分超出范围时而抛出的异常
   /// </summary>
   [Serializable]
   public class DateOverflowException : Exception
   {
      public DateOverflowException() { }
      public DateOverflowException(string message) : base(message) { }
      public DateOverflowException(string message, Exception inner) : base(message, inner) { }
      protected DateOverflowException(SerializationInfo info, StreamingContext context) : base(info, context) { }
   }
   /// <summary>
   /// 如果指定的年份范围太小而抛出的异常
   /// </summary>
   [Serializable]
   public class DifferenceTooSmallException : Exception
   {
      public DifferenceTooSmallException() { }
      public DifferenceTooSmallException(string message) : base(message) { }
      public DifferenceTooSmallException(string message, Exception inner) : base(message, inner) { }
      protected DifferenceTooSmallException(SerializationInfo info, StreamingContext context) : base(info, context) { }
   }
}

评分

参与人数 1金钱 +3 收起 理由
乔克斯 + 3 感谢LZ对论坛做出的贡献~

查看全部评分

回复 论坛版权

使用道具 举报

 楼主| 轩墨玉生烟 发表于 2016-5-5 22:58:13 | 显示全部楼层
自顶一下
回复

使用道具 举报

 楼主| 轩墨玉生烟 发表于 2016-5-5 23:15:38 | 显示全部楼层
补充一下,这个类可以用在小说写作软件开发里面,特别是一部小说的故事线策划,可能就需要用到这个
乔克斯 发表于 2016-5-6 15:21:33 | 显示全部楼层
不明觉厉。
回复

使用道具 举报

 楼主| 轩墨玉生烟 发表于 2016-5-11 00:14:01 | 显示全部楼层

sao乔么么哒
310939468 发表于 2016-5-24 23:45:34 | 显示全部楼层
看帖回帖是美德
逗逼 发表于 2016-9-12 20:57:01 | 显示全部楼层
不明觉厉
回复

使用道具 举报

 楼主| 轩墨玉生烟 发表于 2016-9-21 18:56:14 | 显示全部楼层

没什么,只是根据需求做的一个东西。
jacksonwong 发表于 2019-5-10 16:10:01 | 显示全部楼层
谢谢楼主!
回复

使用道具 举报

3992755 发表于 2019-6-5 21:58:58 | 显示全部楼层
漂亮漂亮漂亮漂亮漂亮漂亮
您需要登录后才可以回帖 登录 | 加入CSkin论坛

本版积分规则

QQ|申请友链|小黑屋|手机版|Archiver|CSkin ( 粤ICP备13070794号

Powered by Discuz! X3.2  © 2001-2013 Comsenz Inc.  Designed by ARTERY.cn
GMT+8, 2019-7-23 00:14, Processed in 0.778846 second(s), 35 queries , Gzip On.

快速回复 返回顶部 返回列表