DateDiff, DateSerial
Hi,
ich hab fürs Framework zwei Funktionen zur Komplettierung von DateTime nachprogrammiert:
DateDiff und DateSerial,
Leider verrechnet es sich um eine Stunde bzw 60minuten.
Weiß jemand warum? Hat das mit der Sommerzeit zu tun?
Bzw hat jemand einen Verbesserungsvorschlag?
Modul MDateTime
OlimilO
ich hab fürs Framework zwei Funktionen zur Komplettierung von DateTime nachprogrammiert:
DateDiff und DateSerial,
Leider verrechnet es sich um eine Stunde bzw 60minuten.
Weiß jemand warum? Hat das mit der Sommerzeit zu tun?
Bzw hat jemand einen Verbesserungsvorschlag?
Modul MDateTime
|
|
Jabaco Source |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
Option Explicit 'http://msdn.microsoft.com/de-de/library/b5xbyt6f(VS.80).aspx Public Enum DateInterval DateInterval_Second ' "s" Sekunde DateInterval_Minute ' "n" Minute DateInterval_Hour ' "h" Stunde DateInterval_Day ' "d" Tag DateInterval_DayOfYear ' "y" Tag DateInterval_Weekday ' "w" Woche DateInterval_WeekOfYear ' "ww" Kalenderwoche DateInterval_Month ' "m" Monat DateInterval_Quarter ' "q" Quartal DateInterval_Year ' "yyyy" Jahr End Enum Public Function Now() As Date 'Dim C As New java#util#GregorianCalendar 'Now = C.getTime Now = New java#util#GregorianCalendar.getTime End Function Public Function DateDiff(Interval As DateInterval, Date1 As Date, Date2 As Date) As Long 'Gibt die Anzahl der Zeitintervalle zwischen zwei Datumsangaben zurück 'returns the amount of timespans between the two dates 'Interval: a string representing the kind of time 'Date1: one end of the timespan 'Date2: the other end of the timepsan DateDiff = CLng(CDbl(GetDiff(Date1, Date2)) / GetFact(Interval)) End Function Public Function DateDiff(Interval As String, Date1 As Variant, Date2 As Variant) As Long DateDiff = GetDiff(Date1, Date2) / CLng(GetFact(CIntv(Interval))) End Function Private Function GetDiff(Date1 As Date, Date2 As Date) As Long Dim d1 As java#util#Date = Date1 Dim d2 As java#util#Date = Date2 GetDiff = d2.getTime - d1.getTime End Function Private Function GetFact(Interval As DateInterval) As Double GetFact = 1000 If Interval = DateInterval_Second Then Exit Function GetFact = GetFact * 60 If Interval = DateInterval_Minute Then Exit Function GetFact = GetFact * 60 If Interval = DateInterval_Hour Then Exit Function GetFact = GetFact * 24 If Interval = DateInterval_Day Or _ Interval = DateInterval_DayOfYear Then Exit Function End If GetFact = GetFact * 7 If Interval = DateInterval_Weekday Then Exit Function GetFact = GetFact * 4.3482142857 '142857142857142857143 ' If Interval = DateInterval_Month Then Exit Function GetFact = GetFact * 3 If Interval = DateInterval_Quarter Then Exit Function GetFact = GetFact * 4 If Interval = DateInterval_Year Then Exit Function End Function Private Function CIntv(s As String) As DateInterval If s = "s" Then CIntv = DateInterval_Second: Exit Function If s = "n" Then CIntv = DateInterval_Minute: Exit Function If s = "h" Then CIntv = DateInterval_Hour: Exit Function If s = "d" Then CIntv = DateInterval_Day: Exit Function If s = "y" Then CIntv = DateInterval_DayOfYear: Exit Function If s = "w" Then CIntv = DateInterval_Weekday: Exit Function If s = "ww" Then CIntv = DateInterval_WeekOfYear: Exit Function If s = "m" Then CIntv = DateInterval_Month: Exit Function If s = "q" Then CIntv = DateInterval_Quarter: Exit Function If s = "yyyy" Then CIntv = DateInterval_Year: Exit Function End Function Public Function DateSerial(year As Integer, month As Integer, day As Integer) As Date 'beim Java#util#GregorianCalendar ist der Monat nullbasiert, d.h. Januar = 0 DateSerial = New GregorianCalendar(year, month - 1, day).getTime End Function |
OlimilO
zum testen hab ich folgenden Code verwendet, der läuft auch unter VB6:
|
|
Jabaco Source |
1 2 3 4 5 6 7 8 |
Private Sub Command1_Click() Dim d1 As Date: d1 = DateSerial(2009, 1, 1) '"01.01.2009" Dim d2 As Date: d2 = Now Dim ts As Long: ts = DateDiff("n", d1, d2) Label1.Caption = CStr(ts) Label2.Caption = CStr(d1) Label3.Caption = CStr(d2) End Sub |
Hi,
außer an der Sommerzeit kann es auch an der aktuellen Zeitzone liegen, die Dein System annimmt.
Zur Kontrolle:
Bei Deiner DateDiff-Implementierung gibt es noch einen Haken:
Man kann die Zeitdifferenzen nicht einfach auf einen Faktor zurückführen.
Beispiel: Wenn die Kalenderwochen als Intervall gefragt sind, muss man für beide Daten jeweils die Kalenderwochen ermitteln und die resultierenden Wochenangaben voneinander abziehen. So ergibt sich zwischen "Montag 20.07.2009 00:05" und "Sonntag 19.07.2009 23:55" eine Wochendifferenz von 1, obwohl nur 10 Minuten dazwischen liegen.
Bei der Syntax der neu implementierten Funktionen hätte ich am liebsten die pure vertraute VB6-Syntax und nicht die davon abweichenden VB.Net-Varianten.
In Functions würde ich grundsätzlich nie mit dem Funktionwert selbst operieren. Das sieht mir zu sehr nach Rekursion aus.
Gruß!
A1880
außer an der Sommerzeit kann es auch an der aktuellen Zeitzone liegen, die Dein System annimmt.
Zur Kontrolle:
|
|
Source code |
1 2 3 4 5 6 7 8 9 |
Dim tz As TimeZone
Dim dst
Dim calendar = java#util#Calendar.getInstance
tz = TimeZone.getDefault
dst = (calendar.get(java#util#Calendar.DST_OFFSET))/1000
Label1.Caption = now & " " & tz.getDisplayName & " " & dst & "s"
|
Bei Deiner DateDiff-Implementierung gibt es noch einen Haken:
Man kann die Zeitdifferenzen nicht einfach auf einen Faktor zurückführen.
Beispiel: Wenn die Kalenderwochen als Intervall gefragt sind, muss man für beide Daten jeweils die Kalenderwochen ermitteln und die resultierenden Wochenangaben voneinander abziehen. So ergibt sich zwischen "Montag 20.07.2009 00:05" und "Sonntag 19.07.2009 23:55" eine Wochendifferenz von 1, obwohl nur 10 Minuten dazwischen liegen.
Bei der Syntax der neu implementierten Funktionen hätte ich am liebsten die pure vertraute VB6-Syntax und nicht die davon abweichenden VB.Net-Varianten.
In Functions würde ich grundsätzlich nie mit dem Funktionwert selbst operieren. Das sieht mir zu sehr nach Rekursion aus.
Gruß!
A1880
Hi A1880,
Ja, Danke für den Hinweis, das muß ich mir nochmal genauer anschauen, ein Verbesserungsvorschlag wäre willkommen.
wovon sprichst Du?
hmm ich hatte da zwar nie Probleme aber stimmt schon manch einer wertet das als schlechten Programmierstil. Das hat aber seine Grundlagen in C ähnlichen Sprachen wo der Vorwurf seine Berechtigung hat. Der Kern des Problems liegt darin, daß es in Jabaco kein Return-Schlüsselwort gibt, wie in VB.net oder in Java. Naja Jabaco wird nunmal nach Java übersetzt. Weil es in VB6 keinen Return-Befehl gibt, deswegen legt der VB6-Kompiler für Jede Funktion grundsätzlich eine Variable im gleichen Namen wie die Funktion an. Wenn man also noch eine Variable mehr hat so findet am Ende der Funktion eine doppelte Kopiererei statt was in meinen Augen sehr ineffektiv ist. Sicherlich mag man argumentieren daß in einer Funktion wie DateDiff Geschwindigkeit keine Rolle spielt, aber ich habe mir unter VB6 numal angewöhnt effektiv zu programmieren.
Viele Grüße
OlimilO
Quoted
Bei Deiner DateDiff-Implementierung gibt es noch einen Haken:
Man kann die Zeitdifferenzen nicht einfach auf einen Faktor zurückführen.
Beispiel: Wenn die Kalenderwochen als Intervall gefragt sind, muss man für beide Daten jeweils die Kalenderwochen ermitteln und die resultierenden Wochenangaben voneinander abziehen. So ergibt sich zwischen "Montag 20.07.2009 00:05" und "Sonntag 19.07.2009 23:55" eine Wochendifferenz von 1, obwohl nur 10 Minuten dazwischen liegen.
Ja, Danke für den Hinweis, das muß ich mir nochmal genauer anschauen, ein Verbesserungsvorschlag wäre willkommen.
Quoted
Bei der Syntax der neu implementierten Funktionen hätte ich am liebsten die pure vertraute VB6-Syntax und nicht die davon abweichenden VB.Net-Varianten
wovon sprichst Du?
Quoted
In Functions würde ich grundsätzlich nie mit dem Funktionwert selbst operieren. Das sieht mir zu sehr nach Rekursion aus
hmm ich hatte da zwar nie Probleme aber stimmt schon manch einer wertet das als schlechten Programmierstil. Das hat aber seine Grundlagen in C ähnlichen Sprachen wo der Vorwurf seine Berechtigung hat. Der Kern des Problems liegt darin, daß es in Jabaco kein Return-Schlüsselwort gibt, wie in VB.net oder in Java. Naja Jabaco wird nunmal nach Java übersetzt. Weil es in VB6 keinen Return-Befehl gibt, deswegen legt der VB6-Kompiler für Jede Funktion grundsätzlich eine Variable im gleichen Namen wie die Funktion an. Wenn man also noch eine Variable mehr hat so findet am Ende der Funktion eine doppelte Kopiererei statt was in meinen Augen sehr ineffektiv ist. Sicherlich mag man argumentieren daß in einer Funktion wie DateDiff Geschwindigkeit keine Rolle spielt, aber ich habe mir unter VB6 numal angewöhnt effektiv zu programmieren.
Viele Grüße
OlimilO
Hi,
grundsätzliche müsste DateDiff so funktionieren:
Je nach gewähltem Intervall werden für beide Zeitpunkte die Einzelwerte berechnet.
Beispiel: bei "d" die Tage, bei "yyyy" die Jahre, bei "ww" die Kalenderwochen, etc.
Das Ergebnis ist dann die Differenz dieser beiden Werte.
Vermutlich liegt das Hauptproblem bei der Realisierung darin, dass sich die Implementation genau so verhält, wie die von VB6.
Was geschieht bei nicht existierenden oder vertauschten Datumsangaben? Wie wird genau gerundet? Einflüsse von Zeitzonen, Sommer-/Winterzeit, erster Tag der Kalenderwoche, etc.
Deine Implementation bietet DateDiff() in zwei public Varianten. Die eine ist von VB6 inspiriert, die andere von VB.Net.
Mir reicht die eine von VB6. Motto: keep it simple!
Statt den Function Identifier zu nutzen, führe ich in Functions immer eine Return-Variable ein, die ich dann ganz am Ende der Function dem Function Identifier zuweise. Ich bemühe mich im Sinne von strukturierter Programmierung auch darum, die Function möglichst nur über ein Ende zu verlassen, statt über diverse exits.
Gruß!
A1880
grundsätzliche müsste DateDiff so funktionieren:
Je nach gewähltem Intervall werden für beide Zeitpunkte die Einzelwerte berechnet.
Beispiel: bei "d" die Tage, bei "yyyy" die Jahre, bei "ww" die Kalenderwochen, etc.
Das Ergebnis ist dann die Differenz dieser beiden Werte.
Vermutlich liegt das Hauptproblem bei der Realisierung darin, dass sich die Implementation genau so verhält, wie die von VB6.
Was geschieht bei nicht existierenden oder vertauschten Datumsangaben? Wie wird genau gerundet? Einflüsse von Zeitzonen, Sommer-/Winterzeit, erster Tag der Kalenderwoche, etc.
Deine Implementation bietet DateDiff() in zwei public Varianten. Die eine ist von VB6 inspiriert, die andere von VB.Net.
Mir reicht die eine von VB6. Motto: keep it simple!
Statt den Function Identifier zu nutzen, führe ich in Functions immer eine Return-Variable ein, die ich dann ganz am Ende der Function dem Function Identifier zuweise. Ich bemühe mich im Sinne von strukturierter Programmierung auch darum, die Function möglichst nur über ein Ende zu verlassen, statt über diverse exits.
Gruß!
A1880
Hallo,
hier ist mein Vorschlag für DateDiff() und Co.
Gruß!
A1880
hier ist mein Vorschlag für DateDiff() und Co.
|
|
Source code |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
Option Explicit
'http://msdn.microsoft.com/de-de/library/b5xbyt6f(VS.80).aspx
Public Function DateDiff(Interval As String, Date1 As Variant, Date2 As Variant) As Long
'Gibt die Anzahl der Zeitintervalle zwischen zwei Datumsangaben zurück
'returns the amount of timespans between the two dates
'Interval: a string representing the kind of time
'Date1: one end of the timespan
'Date2: the other end of the timespan
' note: does not consider different first days of the week
DateDiff = DateVal(Interval, Date2) - DateVal(Interval, Date1)
End Function
Private Function DateVal(Interval As String, d As Variant) As Long
Dim d1 As java#util#Date = d
Dim sec As Long = CLng(d1.getTime() * 0.001)
Dim y As Integer = d1.getYear
Dim ret As Long
Select Case Interval
Case "s": ret = sec
Case "n": ret = CLng(sec / 60.0)
Case "h": ret = CLng(sec / 3600.0)
Case "d", "y": ret = CLng(sec / (24 * 3600.0))
Case "w", "ww": ret = y * 52 + GetWeekShort(d1) ' quick hack! not correct for multiple-year diffs
Case "m": ret = 12 * y + d1.getMonth
Case "q": ret = 4 * y + d1.getMonth / 4
Case "yyyy": ret = y
Case Else
debug.Print "DateVal: unknown interval '" & Interval & "'"
ret = 0
End Select
DateVal = ret
End Function
Public Function Now() As Date
Now = java#util#Calendar.getInstance().getTime
End Function
Public Function DateSerial(year As Integer, month As Integer, day As Integer) As Date
'beim Java#util#GregorianCalendar ist der Monat nullbasiert, d.h. Januar = 0
DateSerial = New GregorianCalendar(year, month - 1, day).getTime
End Function
Private Function getWeekLong(d As Date) As Integer
' Return year of the week
Dim week As Integer = getWeekShort(d)
Dim cal As Calendar = java#util#Calendar.getInstance()
Dim month As Integer
Dim year As Integer
cal.setTime d
month = cal.get(Calendar.MONTH)
year = cal.get(Calendar.YEAR)
If (week = 1) And (month = Calendar.DECEMBER) Then
year = year + 1
Else If (week >= 52) And (month = Calendar.JANUARY) Then
year = year - 1
End If
getWeekLong = 100 * (year Mod 10) + week
End Function
Private Function getWeekShort(d As Date) As Integer
Dim cal As java#util#Calendar = Calendar.getInstance
cal.setTime d
getWeekShort = cal.get(Calendar.WEEK_OF_YEAR)
End Function
Public Sub DateDiffTest
ddt "s", "01.07.2009 10:00:00", "01.07.2009 10:01:00", 60
ddt "n", "01.07.2009 10:00:00", "01.07.2009 10:01:00", 1
ddt "h", "01.07.2009 10:00:00", "01.07.2009 11:00:00", 1
ddt "d", "01.07.2009 10:00:00", "02.07.2009 10:01:00", 1
ddt "d", "01.07.2009 10:00:00", "12.07.2009 10:01:00", 11
ddt "y", "01.07.2009 10:00:00", "02.07.2009 10:01:00", 1
ddt "w", "01.07.2009 10:00:00", "09.07.2009 10:01:00", 1
ddt "ww", "01.07.2009 10:00:00", "09.07.2009 10:01:00", 1
ddt "m", "01.07.2009 10:00:00", "01.08.2009 10:01:00", 1
ddt "q", "01.07.2009 10:00:00", "01.10.2009 10:01:00", 1
ddt "yyyy", "01.07.2009 10:00:00", "01.07.2010 10:01:00", 1
ddt "yyyy", "01.07.2009 10:00:00", "01.07.2011 10:01:00", 2
End Sub
Private Sub ddt(Interval As String, ds1 As String, ds2 As String, ret As Long)
Dim df As DateFormat = New SimpleDateFormat("dd.MM.yyyy HH:mm:ss")
Dim d1 As Date = df.parse(ds1)
Dim d2 As Date = df.parse(ds2)
Dim d As Long = DateDiff(Interval, d1, d2)
If d <> ret Then
debug.Print "d1: " & d1
debug.Print "d2: " & d2
debug.Print Interval & ": " & ds1 & " - " & ds2 & " = " & d & " <> " & ret
End If
End Sub
|
Gruß!
A1880
Sowas wird auf jeden Fall in's Framework übernommen. Ab der nächsten Version wird es eine "get latest snapshot"-Funktion geben. Damit sind dann alle Jabaco-Entwickler immer up-to-date.
Quoted
Sieht suupi aus.
Aber was mich mal wieder interessiert:
Wird das auch ins offizielle Framework wandern oder ist es wieder einer der Dinge, die man nach jeder neuen Jabaco-Version bei sich selber neu am Framework nachrüsten muß?
Similar threads
-
General topics, questions and discussions »-
Framework bugs
(Jul 19th 2009, 6:29pm)
-
Allgemeine Themen, Fragen und Diskussionen »-
datediff
(Jun 21st 2009, 7:42pm)
