且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

一个真正的时间跨度对象,.Years&放大器; .Months

更新时间:2023-02-26 16:16:13

下面是code的主要答案,请注意,您可以得到任何数日期/时间精度,秒和放大器;分钟或秒,分,天,随处可达年(其中将包括6件/段)。如果指定了前两名,它是一岁多,它将返回1年3个月前因为你要求的两个部分将不会返回休息。如果是只有几个小时的时候,那么它只会返回2小时,1分钟前。当然,如果您指定1,2,3,4,5或6 segmets规则同样适用(6马克塞斯因为秒,分钟,小时,天,月,年只能使6种)。它也将正确的语法问题,如产生的永远是语法正确的分与分,这取决于它是否1分钟以上,同样为所有类型的,而字符串。

Here is the main answer with code, please note that you can get any number of dates/times accuracy, seconds & minutes, or seconds, minutes and days, anywhere up to years (which would contain 6 parts/segments). If you specify top two and it's over a year old, it will return "1 year and 3 months ago" and won't return the rest because you've requested two segments. if it's only a few hours old, then it will only return "2 hours and 1 minute ago". Of course, same rules apply if you specify 1, 2, 3, 4, 5 or 6 segmets (maxes out at 6 because seconds, minutes, hours, days, months, years only make 6 types). It will also correct grammer issues like "minutes" vs "minute" depending on if it's 1 minute or more, same for all types, and the "string" generated will always be grammatically correct.

下面是使用的一些例子:
bAllowSegments标识有多少段显示...即:如果3,则返回的字符串将是(作为一个例子)... 3年2个月零13天(不包括时,分,秒为返回前3时间类别),但是,如果日期是一个较新的日期,如一些前几天,指定相同的网段(3)将返回4天,1小时13分钟前代替,所以它需要的一切考虑!

Here are some examples for use: bAllowSegments identifies how many segments to show... ie: if 3, then return string would be (as an example)... "3 years, 2 months and 13 days" (won't include hours, minutes and seconds as the top 3 time categories are returned), if however, the date was a newer date, such as something a few days ago, specifying the same segments (3) will return "4 days, 1 hour and 13 minutes ago" instead, so it takes everything into account!

如果bAllowSegments是2它将返回3年2个月,如果6(最大值)将返回3年,2个月的第13天,13个小时29分9秒,但是,提醒的是,它会有去无回像这样0年0个月0天,3小时,5分13秒前,因为它明白存在的前3段没有最新的数据,而忽略他们,即使你指定6段,所以不用担心:)。当然,如果没有与在其0的段,它会在形成串时考虑到这一点,和将显示为3.天4秒前和忽略了0小时栏目!欣赏并请评论,如果你喜欢。

if bAllowSegments is 2 it would return "3 years and 2 months" and if 6 (maximum value) would return "3 years, 2 months, 13 days, 13 hours, 29 minutes and 9 seconds", but, be reminded that it will NEVER RETURN something like this "0 years, 0 months, 0 days, 3 hours, 2 minutes and 13 seconds ago" as it understands there is no date data in the top 3 segments and ignores them, even if you specify 6 segments, so don't worry :). Of course, if there is a segment with 0 in it, it will take that into account when forming the string, and will display as "3 days and 4 seconds ago" and ignoring the "0 hours" part! Enjoy and please comment if you like.

 Public Function RealTimeUntilNow(ByVal dt As DateTime, Optional ByVal bAllowSegments As Byte = 2) As String
  ' bAllowSegments identifies how many segments to show... ie: if 3, then return string would be (as an example)...
  ' "3 years, 2 months and 13 days" the top 3 time categories are returned, if bAllowSegments is 2 it would return
  ' "3 years and 2 months" and if 6 (maximum value) would return "3 years, 2 months, 13 days, 13 hours, 29 minutes and 9 seconds"
  Dim rYears, rMonths, rDays, rHours, rMinutes, rSeconds As Int16
  Dim dtNow = DateTime.Now
  Dim daysInBaseMonth = Date.DaysInMonth(dt.Year, dt.Month)

  rYears = dtNow.Year - dt.Year
  rMonths = dtNow.Month - dt.Month
  If rMonths < 0 Then rMonths += 12 : rYears -= 1 ' add 1 year to months, and remove 1 year from years.
  rDays = dtNow.Day - dt.Day
  If rDays < 0 Then rDays += daysInBaseMonth : rMonths -= 1
  rHours = dtNow.Hour - dt.Hour
  If rHours < 0 Then rHours += 24 : rDays -= 1
  rMinutes = dtNow.Minute - dt.Minute
  If rMinutes < 0 Then rMinutes += 60 : rHours -= 1
  rSeconds = dtNow.Second - dt.Second
  If rSeconds < 0 Then rSeconds += 60 : rMinutes -= 1

  ' this is the display functionality
  Dim sb As StringBuilder = New StringBuilder()
  Dim iSegmentsAdded As Int16 = 0

  If rYears > 0 Then sb.Append(rYears) : sb.Append(" year" & If(rYears <> 1, "s", "") & ", ") : iSegmentsAdded += 1
  If bAllowSegments = iSegmentsAdded Then GoTo parseAndReturn

  If rMonths > 0 Then sb.AppendFormat(rMonths) : sb.Append(" month" & If(rMonths <> 1, "s", "") & ", ") : iSegmentsAdded += 1
  If bAllowSegments = iSegmentsAdded Then GoTo parseAndReturn

  If rDays > 0 Then sb.Append(rDays) : sb.Append(" day" & If(rDays <> 1, "s", "") & ", ") : iSegmentsAdded += 1
  If bAllowSegments = iSegmentsAdded Then GoTo parseAndReturn

  If rHours > 0 Then sb.Append(rHours) : sb.Append(" hour" & If(rHours <> 1, "s", "") & ", ") : iSegmentsAdded += 1
  If bAllowSegments = iSegmentsAdded Then GoTo parseAndReturn

  If rMinutes > 0 Then sb.Append(rMinutes) : sb.Append(" minute" & If(rMinutes <> 1, "s", "") & ", ") : iSegmentsAdded += 1
  If bAllowSegments = iSegmentsAdded Then GoTo parseAndReturn

  If rSeconds > 0 Then sb.Append(rSeconds) : sb.Append(" second" & If(rSeconds <> 1, "s", "") & "") : iSegmentsAdded += 1

parseAndReturn:

  ' if the string is entirely empty, that means it was just posted so its less than a second ago, and an empty string getting passed will cause an error
  ' so we construct our own meaningful string which will still fit into the "Posted * ago " syntax...

  If sb.ToString = "" Then sb.Append("less than 1 second")

  Return ReplaceLast(sb.ToString.TrimEnd(" ", ",").ToString, ",", " and")

 End Function

当然,你需要一个ReplaceLast功能,这需要一个源字符串和一个参数指定需要更换什么,另一个ARG指定你要替换它什么,它只是取代了过去的次数该字符串的...我包括我的一个,如果你没有一个或不想要实现它,所以在这里它是,它会工作作为是没有必要的修改。我知道reverseit功能不再需要(存在于.NET),但ReplaceLast和Rev​​erseIt FUNC从pre-.net天结转,所以请原谅如何过时它可能看起来(仍然工程100%寿,使用EM了十几年了,可以保函他们是***的bug)... :)。此外,如果您使用的是VB6,你可以使用StrReverse(包装它扩展了.ReverseIt扩展方法的字符串左右),而不是使用ReverseIt()函数(如扩展方法提供)。所以,与其做sReplacable.ReverseIt,你会做StrReverse(sReplacable)为StrReverse()是一个内置在VB6功能(和做同样的事情,反转给定的字符串,而什么都不做更多)。如果你使用StrReverse(),而不是我一般ReverseIt功能,可随时删除ReverseIt功能/扩展。 StrReverse()函数应该在.NET中可只要你导入遗留MS-VisualBasic中的DLL库。没有什么区别无论哪种方式,我写了ReverseIt()之前,我甚至知道StrReverse()函数已经存在,并曾使用它一直以来出于习惯(没有真正的理由使用矿相对于内置的通用函数StrReverse) - 事实上,我敢肯定,StrReverse(或类似的,新的.NET特定字符串反转功能的版本)将被写入更有效率:)。欢呼声。

Of course, you will need a "ReplaceLast" function, which takes a source string, and an argument specifying what needs to be replaced, and another arg specifying what you want to replace it with, and it only replaces the last occurance of that string... i've included my one if you don't have one or dont want to implement it, so here it is, it will work "as is" with no modification needed. I know the reverseit function is no longer needed (exists in .net) but the ReplaceLast and the ReverseIt func are carried over from the pre-.net days, so please excuse how dated it may look (still works 100% tho, been using em for over ten years, can guarante they are bug free)... :). Also, if you are using VB6, you can use StrReverse (wrapping it around the string extended with the .ReverseIt extension method), instead of using the ReverseIt() function (provided as an extension method). So, instead of doing sReplacable.ReverseIt, you'd do StrReverse(sReplacable) as StrReverse() is a built in VB6 function (and does the exact same thing, reverses a given string, and does nothing more). If you use StrReverse() instead of my generic ReverseIt function, feel free to delete the ReverseIt function/extension. StrReverse() function should be available in .NET as long as you are importing the legacy ms-visualbasic-dll library. Makes no difference either way, I had written ReverseIt() before I even know a StrReverse() function had existed, and had been using it ever since out of habit (no real reason to use mine as opposed to the in-built generic function StrReverse) - in fact, I'm sure StrReverse (or a similar, newer .NET specific version of a string reversing function) would be written to be more efficient :). cheers.

<Extension()> _ 
Public Function ReplaceLast(ByVal sReplacable As String, ByVal sReplaceWhat As String, ByVal sReplaceWith As String) As String 
    ' let empty string arguments run, incase we dont know if we are sending and empty string or not. 
    sReplacable = sReplacable.ReverseIt 
    sReplacable = Replace(sReplacable, sReplaceWhat.ReverseIt, sReplaceWith.ReverseIt, , 1) ' only does first item on reversed version! 
    Return sReplacable.ReverseIt.ToString 
End Function 

<Extension()> _ 
Public Function ReverseIt(ByVal strS As String, Optional ByVal n As Integer = -1) As String 
    Dim strTempX As String = "", intI As Integer 

    If n > strS.Length Or n = -1 Then n = strS.Length 

    For intI = n To 1 Step -1 
        strTempX = strTempX + Mid(strS, intI, 1) 
    Next intI 

    ReverseIt = strTempX + Right(strS, Len(strS) - n) 

End Function