65.9K
CodeProject 正在变化。 阅读更多。
Home

处理时间的 Time 类

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.77/5 (3投票s)

2013年7月6日

Ms-PL

5分钟阅读

viewsIcon

26740

downloadIcon

351

我需要一个简单的类来处理CD歌曲时长的时间加减,结果却变成了一个庞大的类

引言

我正在编写一个跟踪CD的程序。我需要一种方法来存储每首歌曲的时长,我尝试使用DateTime变量来保存这些值。不用说,DateTime数据类型根本不够用。我搜索了一个可以用来保存这些值的,但一无所获。很多人推荐使用TimeSpan,但对我需要的功能来说,它完全没有用。所以我从小处着手,创建了一个Time数据类型来保存小时、分钟和秒。然后我意识到在减去值时可能会出现负数,所以我添加了一个Sign。然后,事情就失控了...

背景

我正在为Visual Basic和Visual C#准备一个培训课程。我需要多个示例程序,所以在过去两个月左右的时间里,我一直在不断地编写它们。嗯,这个主项目是一个CD跟踪程序,随着培训的每个部分完成,它将被扩展和增强。

第一部分:基础中,我有一个控制台程序,它使用一个Structure来保存艺术家姓名和专辑标题,并将数据保存到文本文件中。
第二部分:面向对象编程中,我将程序升级为使用类和XML文件。这就是这段代码的来源。第二部分不仅存储艺术家和专辑,还存储歌曲标题和时长、发行年份,并计算总时长。
第三部分:GUI编程中,我将把程序转换为GUI界面,并添加专辑封面和歌词。
最后,在第四部分:数据库编程中,我将再次升级,并将整个程序转换为使用数据库。

Using the Code

Time类添加到您的项目中,它会暴露以下内容:

属性

  • Hours - 一个整数值,保存小时部分
  • Minutes - 一个整数值,保存分钟部分。范围:0(零)到59(五十九)
  • Seconds - 一个整数值,保存秒部分。范围:0(零)到59(五十九)
  • Sign - 一个整数值,保存时间的符号。范围:-1表示负数,0表示零,+1表示正数

构造函数

  • New() - 无参构造函数。设置默认值为+00:00:00。
  • New(seconds) - 带参构造函数。会将秒转换为小时、分钟和秒。
  • New(minutes, seconds) - 带参构造函数。将创建S00:MM:SS格式的值,其中第一个S是数字的符号。
  • New(hours, minutes, seconds) - 带参构造函数。将创建SHH:MM:SS格式的值,其中第一个S是数字的符号。
  • New(sign, hours, minutes, seconds) - 带参构造函数。与前一个构造函数类似,但您可以显式设置符号。
  • New(string) - 带参构造函数。将解析字符串,使用冒号(:)作为分隔符。如果字符串中的参数缺失,则从右到左填充值。
  • New(string, delimeter) - 带参构造函数。与前一个构造函数类似,但您可以提供一个显式分隔符来解析字符串。

关系运算符

您可以使用以下关系运算符:

  • CompareTo(time) - 实现System.IComparable(Of Time).CompareTo
  • Compare(time, time) - 实现System.Collections.Generic.IComparer(Of Time).Compare
  • Equals1(time) - 实现System.IEquatable(Of Time).Equals
  • GetHashCode() - 因为我们有一个Equals()方法
  • < (小于) > (大于) <= (小于等于) >= (大于等于) = (等于) <> (不等于) - 所有有意义的关系运算符都已包含

重载运算符

您可以使用的重载数学运算符有:

  • - (取反) - 返回正时间的负值,负时间的正值
  • + (加) - (减) * (乘) / (除) - 我当初写这个类的全部原因
  • ToShort ToUShort ToInt16 ToUInt16 ToInteger ToUInteger ToInt32 ToUInt32 ToLong ToUlong ToInt64 ToUint64 - 标准转换方法
  • ToSingle ToDouble ToDecimal - 这些数字的整数部分转换为小时和分钟,而秒是小数部分(即30秒=0.5)
  • ToTime() and CType() - 可以将几乎所有其他类型转换为Time类型

杂项方法

您可以使用其他数学运算:

  • Abs() - 绝对值
  • Min() and Max() - 两个值的最小值和最大值
  • Ceiling(), Floor() and Round() - 这些工作方式与标准四舍五入方法类似,并四舍五入到分钟
  • ToString() - 输出#0:00:00-#0:00:00

关于可能的缩小转换,我使用了一些范围检查,如果超出范围则抛出OverflowException。我使用标准异常,以便您可以轻松地将代码集成到您的程序中。

Public Shared Function ToShort(ByVal time As Time) As Short
    Dim temp As Integer = time.Sign * ((time.Hours * 3600) + (time.Minutes * 60) + time.Seconds)
    If temp < -32768 Or temp > 32767 Then
        Throw New OverflowException
    End If
    Return CShort(temp)
End Function

我意识到比较两个Time值会很繁琐且冗长,所以我在Compare()方法中,将Time转换为Integer,然后将它们作为整数进行比较。

Public Function CompareTo(other As Time) As Integer _
    Implements System.IComparable(Of Time).CompareTo
    Dim time1, time2 As Integer
    time1 = Me.Sign * ((Me.Hours * 3600) + (Me.Minutes * 60) + Me.Seconds)
    time2 = other.Sign * ((other.Hours * 3600) + (other.Minutes * 60) + other.Seconds)
    Return time1.CompareTo(time2)
End Function

在加/减/乘法方法中,我将它们转换为整数,进行数学运算,然后将它们转换回Time

Public Shared Operator +(ByVal time1 As Time, ByVal time2 As Time) As Time
    Dim temp As Integer
    temp = ToInteger(time1) + ToInteger(time2)
    Return ToTime(temp)
End Operator

还有ToTime方法。

Public Shared Function ToTime(ByVal value As Integer) As Time
    Dim hours, minutes, seconds As Integer
    hours = value \ 3600
    seconds = value Mod 3600
    minutes = seconds \ 60
    seconds = seconds Mod 60
    Return New Time(Math.Sign(value), hours, minutes, seconds)
End Function

但在Division方法中,我首先将它们转换为Decimal,然后进行除法运算。

Public Shared Operator /(ByVal time1 As Time, ByVal time2 As Time) As Time
    Dim temp As Decimal
    temp = ToDecimal(time1) / ToDecimal(time2)
    Return ToTime(temp)
End Operator

否则结果会很奇怪。

快速测试

我使用下面的小程序对此进行了测试。在我有限的测试中,它通过了,但广泛的测试可能(而且很可能会)暴露缺陷。如果您发现任何问题,请告诉我!

Module TestTimeClass
    Sub Main()
        Dim i As Time
        Dim j As New Time(275)
        Dim k As New Time("4:15")
        i = j + k
        Console.WriteLine(i.ToString())
        i = k - j
        Console.WriteLine(i.ToString())
        Console.WriteLine(Time.ToDecimal(i))
        If k < j Then
            Console.WriteLine("k is smaller than j.")
        Else
            Console.WriteLine("j is smaller than k.")
        End If
        Console.ReadLine()
    End Sub
End Module

关注点

我试图将代码压缩到我能达到的最小程度,而不至于让我自己发疯。这就是为什么这么多地方调用其他地方,主要是因为我不仅讨厌打字,而且我知道如果一个例程的代码有效,那么在另一个例程中重用它就能确保它在那里也能工作。我从小处着手:只想添加和减去时间值。然后,当我添加一点小东西让代码工作得更好一点时,最终我发现我有一个巨大的Time Class,可以处理您可能需要对Time值做的几乎所有事情。

我在这里发布它,希望您可以在自己的程序中使用它,同时也看看我如何改进它、扩展它和/或优化它。

非常欢迎任何问题!

历史

  • 2013-07-04 - 版本 0.0.0.1 (预预预alpha)
  • 2013-07-07 - 添加了Time类的C#版本
© . All rights reserved.