Im Folgenden finden Sie die genaueste Methode, da die Definition von "1 Monat" sich je nach Monat ändert und keine der anderen Antworten dies berücksichtigt! Wenn Sie weitere Informationen zu dem Problem wünschen, das nicht in das Framework integriert ist, können Sie diesen Beitrag lesen: Ein reales Zeitspannenobjekt mit .Jahren und .Monaten (das Lesen dieses Beitrags ist jedoch nicht erforderlich, um die folgende Funktion zu verstehen und zu verwenden. Es funktioniert zu 100%, ohne die inhärenten Ungenauigkeiten der Annäherung, die andere gerne verwenden - und Sie können die .ReverseIt-Funktion durch die integrierte .Reverse-Funktion ersetzen, die Sie möglicherweise in Ihrem Framework haben (der Vollständigkeit halber nur hier).
Bitte beachten Sie, dass Sie eine beliebige Anzahl von Datums- / Zeitgenauigkeiten, Sekunden und Minuten oder Sekunden, Minuten und Tage bis zu Jahren (die 6 Teile / Segmente enthalten würden) erhalten können. Wenn Sie die Top 2 angeben und diese älter als ein Jahr sind, wird "vor 1 Jahr und 3 Monaten" zurückgegeben und der Rest wird nicht zurückgegeben, da Sie zwei Segmente angefordert haben. Wenn es nur ein paar Stunden alt ist, wird es nur "vor 2 Stunden und 1 Minute" zurückgegeben. Natürlich gelten dieselben Regeln, wenn Sie 1, 2, 3, 4, 5 oder 6 Segmets angeben (maximal 6, da Sekunden, Minuten, Stunden, Tage, Monate, Jahre nur 6 Typen ergeben). Es werden auch Grammatikprobleme wie "Minuten" und "Minute" korrigiert, je nachdem, ob es 1 Minute oder mehr ist, für alle Typen gleich, und die generierte "Zeichenfolge" ist immer grammatikalisch korrekt.
Hier einige Beispiele zur Verwendung: bAllowSegments gibt an, wie viele Segmente angezeigt werden sollen ... dh: Wenn 3, wäre die Rückgabezeichenfolge (als Beispiel) ... "3 years, 2 months and 13 days"
(ohne Stunden, Minuten und Sekunden als Top-3-Zeit Kategorien werden zurückgegeben), wenn das Datum jedoch ein neueres Datum war, z. B. vor einigen Tagen, wird "4 days, 1 hour and 13 minutes ago"
stattdessen die Angabe derselben Segmente (3) zurückgegeben , sodass alles berücksichtigt wird!
Wenn bAllowSegments 2 ist, wird es zurückgegeben "3 years and 2 months"
und wenn 6 (Maximalwert) zurückgegeben wird. Beachten Sie "3 years, 2 months, 13 days, 13 hours, 29 minutes and 9 seconds"
jedoch, dass NEVER RETURN
dies in "0 years, 0 months, 0 days, 3 hours, 2 minutes and 13 seconds ago"
etwa so ist, da es keine Datumsdaten in den oberen 3 Segmenten enthält und diese ignoriert, selbst wenn Sie 6 Segmente angeben Also mach dir keine Sorgen :). Wenn sich ein Segment mit 0 darin befindet, wird dies natürlich beim Bilden des Strings berücksichtigt und als "3 days and 4 seconds ago"
Teil "0 Stunden" angezeigt und ignoriert! Viel Spaß und bitte kommentieren Sie, wenn Sie möchten.
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
Natürlich benötigen Sie eine "ReplaceLast" -Funktion, die eine Quellzeichenfolge und ein Argument verwendet, das angibt, was ersetzt werden muss, und ein weiteres Argument, das angibt, durch was ersetzt werden soll, und das nur das letzte Vorkommen dieser Zeichenfolge ersetzt ... Ich habe meine aufgenommen, wenn Sie keine haben oder sie nicht implementieren möchten. Hier funktioniert sie also "wie sie ist", ohne dass Änderungen erforderlich sind. Ich weiß, dass die Umkehrfunktion nicht mehr benötigt wird (existiert in .net), aber die Funktionen ReplaceLast und ReverseIt wurden aus den Tagen vor.net übernommen. Bitte entschuldigen Sie, wie alt sie aussehen könnten (funktioniert immer noch zu 100%, obwohl sie verwendet wurden) em seit über zehn Jahren, kann garantieren, dass sie fehlerfrei sind) ... :). Prost.
<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