惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Secure Thoughts
Security Latest
Security Latest
Simon Willison's Weblog
Simon Willison's Weblog
O
OpenAI News
GbyAI
GbyAI
L
LINUX DO - 最新话题
A
Arctic Wolf
T
Tor Project blog
G
GRAHAM CLULEY
I
InfoQ
博客园_首页
IT之家
IT之家
The Register - Security
The Register - Security
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
P
Proofpoint News Feed
The GitHub Blog
The GitHub Blog
Blog — PlanetScale
Blog — PlanetScale
N
Netflix TechBlog - Medium
K
Kaspersky official blog
博客园 - 三生石上(FineUI控件)
S
SegmentFault 最新的问题
U
Unit 42
PCI Perspectives
PCI Perspectives
量子位
P
Palo Alto Networks Blog
S
Securelist
T
Troy Hunt's Blog
博客园 - 【当耐特】
Recorded Future
Recorded Future
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
S
Security Affairs
Engineering at Meta
Engineering at Meta
T
The Blog of Author Tim Ferriss
博客园 - 聂微东
罗磊的独立博客
N
News and Events Feed by Topic
人人都是产品经理
人人都是产品经理
B
Blog RSS Feed
NISL@THU
NISL@THU
C
Cisco Blogs
T
Threatpost
有赞技术团队
有赞技术团队
Forbes - Security
Forbes - Security
Hugging Face - Blog
Hugging Face - Blog
Last Week in AI
Last Week in AI
T
The Exploit Database - CXSecurity.com
Cloudbric
Cloudbric
Cyberwarzone
Cyberwarzone
Google DeepMind News
Google DeepMind News
C
Cyber Attacks, Cyber Crime and Cyber Security

博客园 - deerchao

Unity 在平面上播放含透明通道的视频(Play video with alpha channel on plane in unity) 域名迁移 错误721 -- 在虚拟机中连接VPN, 显示验证用户名和密码之后出错 - deerchao 繁体编码文本文件转换为简体编码的工具 生成VB多行字符串常量的工具 64位虚拟机Guest OS安装错误:0xC0000225 在64bit Win2008上运行Asp + Access网站 工具: 删除Visual Studio项目中文件链接,并把原文件复制到相应的目录 Tip: Resharper 中 "Unknown Comment" 问题的解决办法 Struct与赋值 Tips 测试ConnectionString是否能连接上数据库服务器 奇怪的TreeView(WinForms)自动选中问题 From C# to VB MapPath的反函数(Reversing MapPath) A fast object clone class - using Expression.Compile() jQuery.combobox, 给文本框添加下拉选项的轻量级插件 CDTray, 打开,关闭光驱的系统托盘程序 jQuery.Excel, 使用Ctrl+方向键/Home/End在input表格中移动
一个代表年月的类YearMonth
deerchao · 2010-04-21 · via 博客园 - deerchao

测试(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;
    }
}


代码:

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);
    }
}

辅助方法:

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);
    }
}