vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#

https://www.vbarchiv.net
Rubrik: Verschiedenes / Sonstiges   |   VB-Versionen: VB.NET04.04.07
Verbalisierte Datumsangaben in Benutzer-Dialogen

Ersetzung von Datumsangaben durch relative Begriffe wie "gestern", "in drei Tagen" usw.

Autor:   Manfred BohnBewertung:  Views:  11.668 
ohne HomepageSystem:  WinNT, Win2k, WinXP, Win7, Win8, Win10, Win11 Beispielprojekt auf CD 

Problemstellung:
Wenn man in einem Dialog dem Benutzer eine Liste von Datumsangaben zur Bearbeitung vorlegt - z.B. für die Terminplanung oder zur Ereignisüberwachung - ist es oftmals günstiger, die reinen Datumswerte im Format Tag/Monat/Jahr - soweit sie in der Nähe des aktuellen Datums liegen - zu ersetzen oder zu ergänzen durch aussagekräftigere Bezeichnungen wie "heute", "vorgestern" oder "kommenden Dienstag".
Auch bei der Anzeige von Datums-Spalten in Datenbanktabellen kann eine Option zur Darstellung der Einträge in Form von solchen Begriffen nützlich sein.

In Dialogen, bei deren Bearbeitung es vor allem auf die Zeitspanne ankommt, kann man statt dessen Benennungen wie "vor drei Tagen" oder "in 14 Tagen" ausgeben.

Da Visual Basic einen Kalender, den speziellen Datentyp "DateTime" und dafür zahlreiche Datumsfunktionen bereit hält, ist die Programmierung relativ einfach. Die benötigten Methoden sind im Namespace "Microsoft.Visualbasic" enthalten. (Im Code werden die Methoden "voll qualifiziert" aufgerufen).

Zu beachten ist dabei insbesondere, dass Instanzen der Datenstruktur "System.DateTime" IMMER einen "tick"-genauen Zeitpunkt enthalten, also ein Datum UND eine Uhrzeit umfassen. Das gilt auch für die aktuelle Version des "klassischen" VB-Datentyps "Date", der in VB 2005 als ein Ableger von "DateTime" enthalten ist und dessen Instanzen ebenfalls die entsprechenden Methoden bereit stellen (vgl. unten).

Details zu den VB-Methoden:
Den aktuellen Zeitpunkt, dessen Datum den Bezugspunkt bei Bildung der strukturierten Angaben darstellt, liefert die Eigenschaft "System.DateTime.Now".
Sie ruft ein DateTime-Objekt ab, das auf das aktuelle Datum und die aktuelle Zeit auf dem lokalen Rechner als lokale Zeit festgelegt ist (VB-Doku). Allerdings wird die Kind-Eigenschaft dabei nicht auf "DateTimeKind:Local“ gesetzt, sondern bleibt unspezifiziert.

Die Now-Eigenschaft ist nicht zu verwechseln mit der auf Modulebene verfügbaren Now-Funktion (Microsoft.Visualbasic), die das Systemdatum und die Systemzeit abfragt.

Für jedes im Dialog angezeigte Datum ist die Zahl der Tageswechsel zu bestimmen, durch die sie vom Now-Datum abweichen. Liegt kein Tageswechsel vor, ist das Datum durch "Heute" verbal zu etikettieren.

Die Funktion "DateDiff" berechnet das Intervall zwischen zwei Zeitpunkten in einem vorzugebenden Maßstab - in unserem Fall sind das Tage.
"DateDiff" berücksichtigt dabei den genauen Zeitpunkt der übergebenen Parameter. Das bedeutet, zwischen dem 1.1.2007 23:00:00 und dem 2.1.2007 01:00:00 liegen zwei Stunden, also weniger als ein Tag - d.h. die Methode errechnet 0 Tage, obwohl ein Tageswechsel stattgefunden hat.
Als Übergabeparameter muss deshalb die Rückgabe der "DateTime“-Eigenschaft "Date" verwendet werden. Diese Eigenschaft liefert den Zeitwert stets als 00:00:00. Der obige Vergleich gestaltet sich als Differenz der Zeitpunkte 1.1.2007 00:00:00 und 2.1.2007 00:00:00 - und liefert somit korrekt den benötigten einen Tageswechsel.
Bei Bestimmung der Tageswechsel ist zu beachten, ob der übergebene "DateTime"-Wert in lokaler Zeit (einschließlich Sommerzeit) oder in Weltzeit angegeben worden ist (Abfrage der Kind-Eigenschaft). Die Routine „SetToLocalTime“ stellt ggf. die lokale Zeit her – ignoriert aber die unspezifizierte Kind-Eigenschaft!.

Beträgt die Zeitdistanz zwischen einem Dialog-Datum und dem aktuellen Datum mehr als zwei, aber weniger als acht Tage, kann man in Dialogen den zugehörigen Wochentag ausgeben, z.B. "vergangener Freitag" bzw. "kommender Freitag".

Die VB-Funktion "WeekDay" liefert zu einem Datum eine Integer-Kennung für den Wochentag, bei der gemäß Voreinstellung 1 = Sonntag und 7 = Samstag codiert ist.

Man könnte über die VB-Funktion "WeekdayName" die Bezeichnung des Wochentags entsprechend der Windows-Spracheinstellung auslesen. Da im vorliegenden Fall die Wochentage mit eigenen Bezeichnungen kombiniert werden sollen, ist das nicht unbedingt zu empfehlen. Bei der Windows-Einstellung ENGLISCH ergäbe sich dann z.B. "kommender Wednesday".

Der Einfachheit halber wird deshalb eine Funktion verwendet, die die deutschen Wochentags-Bezeichnungen sicher stellt.
Die Übersetzung deutscher Relativzeit-Bezeichnungen in andere Sprachen ist z.T. nicht unbedingt sinnvoll: Z.B. wird der Begriff "vorgestern" ins Englische normalerweise als "the day before yesterday" übersetzt. In dieser Sprache sollte man statt dessen den entsprechenden Wochentag angeben.

Vorschlag:
Die Funktion "VerbalisiertesDatum" wertet die Datumsangabe in einer Instanz der „DateTime“-Struktur aus. Zurückgegeben wird entweder das gegebene Datum als deutscher Standard-Datums-String (Funktion: "NurDatum") oder dessen Ersetzung durch einen aussagekräftigen Begriff .
Der zweite optionale Parameter entscheidet, ob bei einem Datum, das weiter als eine Woche vom gegenwärtigen Datum entfernt liegt, dieses Datum als String (bei: false) oder ein Leerstring (bei: true) zurückgegeben wird. Letzteres ist dann zweckmäßig, wenn das verbale Etikett des Datums nur zusätzlich im Dialog angezeigt werden soll.

Die Funktion "VerbalisiertesDatum_PlusUhrzeit" hängt die Zeitangabe an die Rückgabe des Datums als Standard-Zeitstring (Funktion: "NurUhrzeit") an. Von Bedeutung ist das z.B. bei der Anzeige von Dateilisten. Es kommt häufig vor, dass mehrere Versionen einer Datei am gleichen Tag erstellt worden sind und deshalb erst durch die ergänzende Anzeige der Uhrzeit ('letzte Änderung') vom Benutzer sicher identifiziert werden können (vgl. Funktion „VerbalisierteDateizeit“)

Die Funktion "´VerbalisiertesDatum_Intervall" ersetzt das übergebene Datum durch eine Intervallangabe in Tagen, falls die absolute Differenz zum aktuellen Datum maximal 30 Tageswechsel beträgt.
Solche Angaben sind sinnvoll z.B. bei der Bearbeitung von Bestellungen. Dabei ist es wichtig zu wissen, wie viele Tage seit Auftragseingang bereits vergangen, bzw. wie viele Tage bis zum Erreichen eines vereinbarten Liefertermins noch übrig sind.

Die Routine "Demo_VerbalisiertesDatum" demonstriert Aufruf und Rückgabe dieser Funktionen.

Es versteht sich, dass es kaum Sinn macht, solche Angaben in einer Datei oder Datenbank zu speichern oder sie vom Benutzer im Dialog direkt manipulieren zu lassen.

' ====================================================================
' Start Quellcode
' ====================================================================
Public Sub Demo_VerbalisiertesDatum()
  Dim i As Integer, dt As System.DateTime
 
  ' Hier angeben, ob bei nicht durchgeführter Verbalisierung
  ' die Funktionen das Datum zurückgeben oder einen Leerstring
  Dim NurVerbalisierung As Boolean = False
 
  ' Demo-Ausgabe von verbalisierten Datumsangaben 
  ' 10 Tage vor bis 10 Tage nach dem aktuellen Datum
  Debug.Print("")
  Debug.Print("Verbalisiertes Datum: ")
  For i = -10 To 10
    ' laufenden Schleifenindex-Wert als Tagesanzahl 
    ' zum aktuellen Datum addieren
    dt = Now.Add(New System.TimeSpan(i, 0, 0, 0))
    ' Ausgabe ins Debug-Fenster
    Debug.Print(dt.ToString + " ---> " + _
    VerbalisiertesDatum(dt, NurVerbalisierung))
  Next i
 
  Debug.Print("")
  Debug.Print("Verbalisiertes Datum plus Uhrzeit: ")
  For i = -10 To 10
    ' laufenden Schleifenindex-Wert als Tagesanzahl 
    ' zum aktuellen Datum addieren
    dt = Now.Add(New System.TimeSpan(i, 0, 0, 0))
    ' Ausgabe ins Debug-Fenster
    Debug.Print(dt.ToString + " ---> " + _
    VerbalisiertesDatum_PlusUhrzeit(dt, NurVerbalisierung))
  Next i
 
 
  ' Demo-Ausgabe von verbalisierten Datumsangaben (vor x Tagen) 
  ' 32 Tage vor bis 32 Tage nach dem aktuellen Datum
  Debug.Print("")
  Debug.Print("Verbalisiertes Datum als Tagesdifferenz: ")
  For i = -32 To 32
    ' laufenden Schleifenindex-Wert als Tagesanzahl 
    ' zum aktuellen Datum addieren
    dt = Now.Add(New System.TimeSpan(i, 0, 0, 0))
    Debug.Print(dt.ToString + " ---> " + _
    VerbalisiertesDatum_Intervall(dt, NurVerbalisierung))
  Next i
End Sub
Public Function VerbalisiertesDatum( _
  ByVal dt As System.DateTime, _
  Optional ByVal NurVerbalisierung As Boolean = False) As String
 
  ' Ein Datum wird umgewandelt in Angaben wie Heute, Morgen oder
  ' den Wochentag falls es maximal eine Woche vom aktuellen Datum
  ' entfernt ist
 
  ' Bestimmung der Zahl der Tageswechsel zwischen dem aktuellem
  ' Datum und dem Inhalt des übergebenen Parameters
  Dim DatumsDifferenz As Long = _
  TagesWechsel(System.DateTime.Now, dt)
 
  ' ggf. Verbalisierung des Datums: Fallunterscheidungen
  Select Case DatumsDifferenz
    Case Is > 7
      ' zu weit in der Zukunft
      If NurVerbalisierung Then Return ("")
      Return NurDatum(dt)
    Case Is < -7
      ' zu weit in der Vergangenheit
      If NurVerbalisierung Then Return ("")
      Return NurDatum(dt)
    Case 0
      Return "Heute"
    Case -1
      Return "Gestern"
    Case -2
      Return "Vorgestern"
    Case 1
      Return "Morgen"
    Case 2
      Return "Übermorgen"
    Case Is > 2
      ' Wochentag (kommend)
      Return "kommender " + Wochentag(dt)
    Case Else
      ' Wochentag (vergangen)
      Return "vergangener " + Wochentag(dt)
  End Select
End Function
Public Function VerbalisiertesDatum_PlusUhrzeit( _
  ByVal dt As System.DateTime, _
  Optional ByVal NurVerbalisierung As Boolean = False) As String
 
  ' Bei dieser Funktion wird ggf. die Uhrzeit an den 
  ' Rückgabestring angehängt
 
  Dim datum As String
 
  datum = VerbalisiertesDatum(dt, NurVerbalisierung)
  If datum <> "" Then datum += (" " + NurUhrzeit(dt))
 
  Return datum
End Function
Public Function VerbalisiertesDatum_Intervall( _
  ByVal dt As System.DateTime, _
  Optional ByVal NurVerbalisierung As Boolean = False) As String
 
  ' Ein Datum wird umgewandelt in Angaben zur Tagesdifferenz 
  ' z.b.  'vor drei Tagen' oder 'in 14 Tagen' 
  ' falls es maximal 30 Tage vom aktuellen Datum entfernt ist
 
  ' Zahlen bis 12 werden als Zahlworte zurückgegeben
  Dim Zahlworte As String() = New String(12) _
    {"", "einem", "zwei", "drei", "vier", _
    "fünf", "sechs", "sieben", "acht", _
    "neun", "zehn", "elf", "zwölf"}
 
  ' Bestimmung der Zahl der Tageswechsel zwischen dem 
  ' aktuellen Datum und dem Inhalt des übergebenen Parameters
  Dim DatumsDifferenz As Integer = _
  TagesWechsel(System.DateTime.Now, dt)
 
  ' Fallunterscheidungen
  Select Case DatumsDifferenz
    Case Is > 30
      ' zu weit in der Zukunft
      If NurVerbalisierung Then Return ("")
      Return NurDatum(dt)
    Case Is < -30
      ' zu weit in der Vergangenheit
      If NurVerbalisierung Then Return ("")
      Return NurDatum(dt)
    Case Is > 12
      ' Anzahl der Tage als Zahl zurückgeben
      Return "in " + DatumsDifferenz.ToString + " Tagen"
    Case Is < -12
      ' Anzahl der Tage als Zahl zurückgeben 
      Return "vor " + (System.Math.Abs(DatumsDifferenz)).ToString + " Tagen"                                                                                                  
    Case 0
      Return ("Heute")
    Case 1
      Return ("in einem Tag")
    Case Is > 1
      ' Anzahl der Tage als Zahlwort zurückgeben
      Return "in " + Zahlworte(DatumsDifferenz) + " Tagen"
    Case -1
      Return ("vor einem Tag")
    Case Else
      ' Anzahl der Tage als Zahlwort zurückgeben
      Return "vor " + Zahlworte(System.Math.Abs(DatumsDifferenz)) + " Tagen"
  End Select
End Function
Public Function TagesWechsel(ByVal dt1 As System.DateTime, _
  ByVal dt2 As System.DateTime) As Long
 
  ' Zeitdifferenz, die die Zahl der Tageswechsel zwischen den 
  ' beiden Datumsangaben dt1, dt2 berechnet (Basis: lokale Zeit)
 
  dt1 = SetToLocalTime(dt1)
  dt2 = SetToLocalTime(dt2)
 
  TagesWechsel = Microsoft.VisualBasic.DateAndTime.DateDiff( _
  Microsoft.VisualBasic.DateInterval.Day, dt1.Date, dt2.Date)
End Function
Public Function SetToLocalTime(ByVal dt As Date) As Date
 
  ' falls im Parameter dt eine UTC-Zeit vorliegt,
  ' wird in die lokale Zeit umgewandelt
  ' falls Kind unbestimmt ist, erfolgt keine Änderung
 
  If dt.Kind = DateTimeKind.Utc Then
    dt = dt.ToLocalTime
  End If
  Return dt
End Function
Public Function Wochentag(ByVal dt As System.DateTime) As String
 
  ' Ermittlung des Wochentags zu einem Datum 
  ' ohne Beachtung der Windows-Systemeinstellungen (Sprache)
  ' für die Bezeichnung der Wochentage
 
  Dim Wochentage As String() = New String(7) _
    {"", "Sonntag", "Montag", "Dienstag", "Mittwoch", _
    "Donnerstag", "Freitag", "Samstag"}
 
  ' Der Parameter-Wert 'Sunday' entspricht der Voreinstellung
  Return (Wochentage(Microsoft.VisualBasic.Weekday( _
    dt, Microsoft.VisualBasic.FirstDayOfWeek.Sunday)))
End Function
Public Function NurDatum(ByVal dt As System.DateTime) As String
 
  ' Das in einer DateTime-Instanz enthaltene Datum  
  ' wird als Standardstring z.b. 24.3.2007 zurückgeben
  ' Windows-Einstellungen werden ignoriert
 
  Return (dt.Day.ToString + "." + dt.Month.ToString + "." _
    + dt.Year.ToString)
End Function
Public Function NurUhrzeit(ByVal dt As System.DateTime) As String
 
  ' Die in einer DateTime-Instanz enthaltene Uhrzeit  
  ' wird als Standardstring 00:00:00 zurückgeben
  ' Windows-Einstellungen werden ignoriert
 
  Return (dt.Hour.ToString + ":" + dt.Minute.ToString + ":" _
    + dt.Second.ToString)
End Function
Public Function VerbalisierteDateizeit( _
  ByVal PfadDatei As String) As String
 
  ' Die Funktion gibt das Datum der letzten Änderung einer 
  ' Datei, deren voller Pfad im Parameter "PfadDatei" gegeben 
  ' worden ist, zurück
 
  Err.Clear()
  Try
    With My.Computer.FileSystem
      ' Warnhinweis: Die Methode GetFileInfo löst bei 
      ' Zugriffsversuch auf eine fehlende Datei 
      ' keinen Fehler aus - 'FileExists' ist erforderlich
      If Not .FileExists(PfadDatei) Then
        Return "Fehler: Datei nicht gefunden"
      Else
        Return VerbalisiertesDatum( _
          .GetFileInfo(PfadDatei).LastWriteTime)
      End If
    End With
  Catch
    Return "Fehler: " + Err.Description
  End Try
End Function
' ====================================================================
' Ende Quellcode
' ====================================================================



Anzeige

Kauftipp Unser Dauerbrenner!Diesen und auch alle anderen Tipps & Tricks finden Sie auch auf unserer aktuellen vb@rchiv  Vol.6
(einschl. Beispielprojekt!)

Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv!
- nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten
- Symbol-Galerie mit mehr als 3.200 Icons im modernen Look
Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m.
 
 
Copyright ©2000-2024 vb@rchiv Dieter OtterAlle Rechte vorbehalten.


Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein.