「1か月」の定義は月によって異なり、他の回答ではこれを考慮に入れていないため、実際には次の方法で実際に実行できます。フレームワークに組み込まれていない問題に関する詳細情報が必要な場合は、この投稿をご覧ください:.Years&.Monthsを使用したReal Timespanオブジェクト(ただし、以下の関数を理解して使用するためにその投稿を読む必要はありません、それは100%機能しますが、他の人が使用するのが好きな近似の固有の不正確さはありません。また、.ReverseIt関数をフレームワークにある組み込みの.Reverse関数に置き換えてもかまいません(完全を期すためにここにあります)。
日付/時刻の精度、秒と分、または秒、分と日、何年にも及ぶ任意の数(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時間に含めませんただし、日付が数日前などの新しい日付の場合、同じセグメント(3)を指定すると"4 days, 1 hour and 13 minutes ago"
代わりに返されるため、すべてが考慮されます。
bAllowSegmentsが2であれば、それは戻ってくる"3 years and 2 months"
6(最大値)とあれば返します"3 years, 2 months, 13 days, 13 hours, 29 minutes and 9 seconds"
、しかし、それはすることが思い出されNEVER RETURN
、このような何かを"0 years, 0 months, 0 days, 3 hours, 2 minutes and 13 seconds ago"
あなたは6つのセグメントを指定した場合でも、それはトップ3のセグメントには日付データがありません理解し、それらを無視して、なので心配しないでください:) もちろん、その中に0があるセグメントがある場合、文字列を形成するときにそれが考慮され"3 days and 4 seconds ago"
、「0時間」の部分として無視されて表示されます。楽しんでコメントしてください。
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より前の日付から引き継がれています。 emは10年以上、バグがないことを保証できます)... :)。乾杯。
<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