これがコードによる主な答えです。日付/時刻の精度、秒と分、または秒、分、日、最大数年までの任意の数を取得できることに注意してください(6つの部分/セグメントが含まれます)。上位 2 つを指定して 1 年以上経過している場合、「1 年 3 か月前」が返され、残りは 2 つのセグメントを要求したため返されません。数時間前の場合は、「2 時間 1 分前」のみが返されます。もちろん、1、2、3、4、5、または 6 セグメントを指定した場合も同じ規則が適用されます (秒、分、時間、日、月、年では 6 つのタイプしか作成できないため、最大 6 までです)。また、「分」と「分」のような文法の問題も修正します。これは、1 分以上であるかどうかに応じて、すべてのタイプで同じであり、「文字列」
使用例を次に示します: bAllowSegments は、表示するセグメントの数を識別します... 例: 3 の場合、返される文字列は (例として)... "3 years, 2 months and 13 days"
(上位 3 時間として時間、分、秒は含まれません)カテゴリが返されます)、ただし、日付が数日前などの新しい日付である場合は、"4 days, 1 hour and 13 minutes ago"
代わりに同じセグメント (3) を指定すると返されるため、すべてが考慮されます!
bAllowSegments が 2 の場合は が返さ"3 years and 2 months"
れ、6 (最大値)の場合は が返されますが、6 つのセグメントを指定しても上位 3 つのセグメントに日付データがないことを認識して無視するため、このよう"3 years, 2 months, 13 days, 13 hours, 29 minutes and 9 seconds"
になることに注意してください。 、心配しないでください:)。もちろん、0 のセグメントがある場合は、それを考慮して文字列を作成し、「0 時間」の部分を無視してと表示します。楽しんで、よろしかったらコメントください。NEVER RETURN
"0 years, 0 months, 0 days, 3 hours, 2 minutes and 13 seconds ago"
"3 days and 4 seconds ago"
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」関数が必要になります。これは、その文字列の最後の出現のみを置換します...持っていない、または実装したくない場合は、私のものを含めました。これは、変更を必要とせずに「そのまま」機能します。私はreverseit機能がもはや必要でないことを知っています(.netに存在します)が、ReplaceLastとReverseIt機能は.net以前の日から引き継がれているので、それがどのように古く見えるかを許してください(まだ100%動作しますが、使用していますem は 10 年以上、バグがないことを保証できます)... :)。また、VB6 を使用している場合は、StrReverse (.ReverseIt 拡張メソッドで拡張された文字列をラップする) を使用できます。ReverseIt() 関数 (拡張メソッドとして提供) を使用する代わりに。したがって、sReplacable.ReverseIt を実行する代わりに、StrReverse(sReplacable) を実行します。StrReverse() は組み込みの VB6 関数です (まったく同じことを行い、指定された文字列を反転し、それ以上のことはしません)。汎用の ReverseIt 関数の代わりに StrReverse() を使用する場合は、ReverseIt 関数/拡張機能を自由に削除してください。従来の ms-visualbasic-dll ライブラリをインポートしている限り、StrReverse() 関数は .NET で使用できるはずです。どちらの方法でも違いはありません.StrReverse()関数が存在することを知る前に私はReverseIt()を書いていました. StrReverse) - 実際、StrReverse (または同様の新しい . 文字列反転関数の NET 固有のバージョン) は、より効率的に記述されるでしょう :)。乾杯。
<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