一个代表年月的类YearMonth

测试(VS自带框架):

 

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
 
/// <summary>
///This is a test class for YearMonthTest and is intended
///to contain all YearMonthTest Unit Tests
///</summary>
[TestClass()]
public class YearMonthTest
{
 
    /// <summary>
    ///A test for YearMonth Constructor
    ///</summary>
    [TestMethod()]
    public void YearMonthConstructorTest()
    {
        var date = new DateTime(2000, 1, 1);
        var target = new YearMonth(date);
        Assert.AreEqual(2000, target.Year);
        Assert.AreEqual(1, target.Month);
    }
 
    /// <summary>
    ///A test for YearMonth Constructor
    ///</summary>
    [TestMethod()]
    public void YearMonthConstructorTest1()
    {
        YearMonth target = new YearMonth(2010, 4);
        Assert.AreEqual(2010, target.Year);
        Assert.AreEqual(4, target.Month);
    }
 
    /// <summary>
    ///A test for GetDate
    ///</summary>
    [TestMethod()]
    public void GetDateTest()
    {
        var target = new YearMonth(2010, 5);
        var expected = new DateTime(2010, 5, 3);
        var actual = target.GetDate(3);
        Assert.AreEqual(expected, actual);
    }
 
    [TestMethod]
    public void GetDateThrows()
    {
        Assert.IsTrue(Throws(typeof(ArgumentOutOfRangeException), () => new YearMonth(2012, 12).GetDate(32)));
    }
 
    /// <summary>
    ///A test for ToString
    ///</summary>
    [TestMethod()]
    public void ToStringTest()
    {
        var target = new YearMonth(2008, 3);
 
        Assert.AreEqual("200803", target.ToString());
    }
 
    /// <summary>
    ///A test for IsValid
    ///</summary>
    [TestMethod()]
    public void IsValidTest()
    {
        Assert.IsTrue(new YearMonth(2008, 12).IsValid);
 
        Assert.IsFalse(new YearMonth(2010, 13).IsValid);
        Assert.IsFalse(new YearMonth(2010, 0).IsValid);
        Assert.IsFalse(new YearMonth(2010, -3).IsValid);
 
        Assert.IsFalse(new YearMonth(0, 3).IsValid);
        Assert.IsFalse(new YearMonth(-2, 3).IsValid);
        Assert.IsTrue(new YearMonth(9999, 12).IsValid);
        Assert.IsFalse(new YearMonth(10000, 1).IsValid);
 
        Assert.IsFalse(new YearMonth(-2, -3).IsValid);
    }
 
    /// <summary>
    ///A test for Equals
    ///</summary>
    [TestMethod()]
    public void EqualsTest()
    {
        var target = new YearMonth(2010, 4);
        Assert.IsTrue(target.Equals(new YearMonth(2010, 4)));
        Assert.IsFalse(target.Equals(new YearMonth(2010, 3)));
 
        Assert.IsFalse(target.Equals(string.Empty));
    }
 
    /// <summary>
    ///A test for TryParse
    ///</summary>
    [TestMethod()]
    public void TryParseTest()
    {
        YearMonth result;
        var success = YearMonth.TryParse("201012", out result);
        Assert.IsTrue(success);
        Assert.AreEqual(new YearMonth(2010, 12), result);
 
        success = YearMonth.TryParse("", out result);
        Assert.IsFalse(success);
        Assert.AreEqual(result, null);
    }
 
    /// <summary>
    ///A test for Parse
    ///</summary>
    [TestMethod()]
    public void ParseTest()
    {
        Assert.AreEqual(new YearMonth(2008, 12), YearMonth.Parse("200812"));
    }
 
    [TestMethod]
    public void ParseThrows()
    {
        Assert.IsTrue(Throws(typeof(ArgumentNullException), () => YearMonth.Parse(null)));
        Assert.IsTrue(Throws(typeof(ArgumentException), () => YearMonth.Parse("")));
        Assert.IsTrue(Throws(typeof(ArgumentException), () => YearMonth.Parse("aaaaaa")));
        Assert.IsTrue(Throws(typeof(ArgumentException), () => YearMonth.Parse("20121221")));
    }
 
 
 
    /// <summary>
    ///A test for AddYears
    ///</summary>
    [TestMethod()]
    public void AddYearsTest()
    {
        Assert.AreEqual(new YearMonth(2011, 11), new YearMonth(2008, 11).AddYears(3));
        Assert.AreEqual(new YearMonth(2011, 11), new YearMonth(2011, 11).AddYears(0));
        Assert.AreEqual(new YearMonth(2011, 11), new YearMonth(2012, 11).AddYears(-1));
    }
 
    /// <summary>
    ///A test for AddMonths
    ///</summary>
    [TestMethod()]
    public void AddMonthsTest()
    {
        Assert.AreEqual(new YearMonth(2010, 4), new YearMonth(2010, 3).AddMonths(1));
        Assert.AreEqual(new YearMonth(2010, 4), new YearMonth(2010, 4).AddMonths(0));
        Assert.AreEqual(new YearMonth(2010, 4), new YearMonth(2010, 8).AddMonths(-4));
 
        Assert.AreEqual(new YearMonth(2010, 1), new YearMonth(2009, 11).AddMonths(2));
        Assert.AreEqual(new YearMonth(2009, 11), new YearMonth(2010, 1).AddMonths(-2));
 
        Assert.AreEqual(new YearMonth(2009, 12), new YearMonth(2010, 1).AddMonths(-1));
        Assert.AreEqual(new YearMonth(2010, 1), new YearMonth(2009, 12).AddMonths(1));
    }
     
    static bool Throws(Type exceptionType, Action action)
    {
        try
        {
            action();
        }
        catch (Exception ex)
        {
            if (ex.GetType() == exceptionType || ex.GetType().IsSubclassOf(exceptionType))
                return true;
 
            throw;
        }
        return false;
    }
}


代码:

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
using System;
using System.Linq;
 
/// <summary>
/// 代表一个年份中的某个指定月份. 如:2008年10月.
/// </summary>
public sealed class YearMonth
{
    private readonly int _year;
    private readonly int _month;
 
    /// <summary>
    /// 用指定的年份和月份构造一个 YearMonth 对象.
    /// </summary>
    /// <param name="year">年号,如2012.</param>
    /// <param name="month">月份,1代表1月,12代表12月.</param>
    public YearMonth(int year, int month)
    {
        _year = year;
        _month = month;
    }
 
    /// <summary>
    /// 根据指定日期所在的月份构造一个 YearMonth 对象.
    /// </summary>
    /// <param name="date">指定的日期.它的年份和月份部分会作为构造的YearMonth的值使用.</param>
    public YearMonth(DateTime date)
    {
        _year = date.Year;
        _month = date.Month;
    }
 
    public int Year
    {
        get { return _year; }
    }
 
    public int Month
    {
        get { return _month; }
    }
 
    /// <summary>
    /// 是否是有效的值.无效的值可能是年份小于1, 或年份大于9999, 或月份小于1, 或月份大于12.
    /// </summary>
    public bool IsValid
    {
        get
        {
            return 0 < Year && Year < 10000
                   && 0 < Month && Month < 13;
        }
    }
 
    /// <summary>
    /// 获取代表该月指定日期的 DateTime 对象
    /// </summary>
    /// <param name="day">日期,范围1到31.</param>
    /// <exception cref="ArgumentOutOfRangeException">day大于本月的天数.</exception>
    public DateTime GetDate(int day)
    {
        return new DateTime(Year, Month, day);
    }
 
    /// <summary>
    /// 返回一个新YearMonth对象,其值为当前对象的值加上指定个年份
    /// </summary>
    /// <param name="value">要在当前年月上增加多少年</param>
    public YearMonth AddYears(int value)
    {
        return new YearMonth(Year + value, Month);
    }
 
    /// <summary>
    /// 返回一个新YearMonth对象,其值为当前对象的值加上指定个月份
    /// </summary>
    /// <param name="value">要在当前年月上增加多少个月</param>
    public YearMonth AddMonths(int value)
    {
        var totalMonths = Year * 12 + Month + value;
 
        var year = totalMonths / 12;
        var month = totalMonths % 12;
        if (month == 0)
        {
            month = 12;
            year--;
        }
 
        return new YearMonth(year, month);
    }
 
    /// <summary>
    /// 返回数字代表的年月份值,共6位数字,前4位代表年份,后两位代表月份,如:200805
    /// </summary>
    public override string ToString()
    {
        return "{0:D4}{1:D2}".FormatWith(Year, Month);
    }
 
    /// <summary>
    /// 判断一个是否与当前对象代表相同的值的YearMonth对象.
    /// </summary>
    public override bool Equals(object obj)
    {
        return Equals(obj as YearMonth);
    }
 
    /// <summary>
    ///判断另一个YearMonth对象是否与当前对象代表相同的值.
    /// </summary>
    public bool Equals(YearMonth rhs)
    {
        if (ReferenceEquals(null, rhs))
            return false;
        if (ReferenceEquals(this, rhs))
            return true;
 
        return _year == rhs._year &&
            _month == rhs._month;
    }
 
    public override int GetHashCode()
    {
        unchecked
        {
            return (_year * 397) ^ _month;
        }
    }
 
    public static bool operator ==(YearMonth lhs, YearMonth rhs)
    {
        return Object.Equals(lhs, rhs);
    }
 
    public static bool operator !=(YearMonth lhs, YearMonth rhs)
    {
        return !(lhs == rhs);
    }
 
    public static bool TryParse(string s, out YearMonth result)
    {
        try
        {
            result = Parse(s);
            return true;
        }
        catch (ArgumentException)
        {
            result = null;
            return false;
        }
    }
 
    /// <summary>
    /// 通过解析字符串构造一个YearMonth对象.
    /// </summary>
    /// <param name="s">要解析的字符串.</param>
    /// <exception cref="ArgumentNullException">s为null.</exception>
    /// <exception cref="ArgumentException">s包含非数字字符,或s的长度不为6.</exception>
    public static YearMonth Parse(string s)
    {
        if (s == null)
            throw new ArgumentNullException("s");
        if (s.Length != 6 || s.Any(x => x < '0' || x > '9'))
            throw new ArgumentException("s应该是6位数字.");
 
        var year = int.Parse(s.Substring(0, 4));
        var month = int.Parse(s.Substring(4));
 
        return new YearMonth(year, month);
    }
}

 

辅助方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static class StringExtensions
{
    public static string FormatWith(this string format, object arg0)
    {
        return string.Format(format, arg0);
    }
 
    public static string FormatWith(this string format, object arg0, object arg1)
    {
        return string.Format(format, arg0, arg1);
    }
 
    public static string FormatWith(this string format, object arg0, object arg1, object arg2)
    {
        return string.Format(format, arg0, arg1, arg2);
    }
}

posted on   deerchao  阅读(1160)  评论(0编辑  收藏  举报

编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
历史上的今天:
2007-04-21 一些感想,欢迎拍砖
< 2010年4月 >
28 29 30 31 1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 1
2 3 4 5 6 7 8

统计

点击右上角即可分享
微信分享提示