You are not logged in.

OlimilO

Intermediate

  • "OlimilO" is male
  • "OlimilO" started this thread

Posts: 277

Date of registration: Jan 18th 2009

Location: Germany

Occupation: software engineer

  • Send private message

1

Wednesday, July 22nd 2009, 11:41pm

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

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

OlimilO

Intermediate

  • "OlimilO" is male
  • "OlimilO" started this thread

Posts: 277

Date of registration: Jan 18th 2009

Location: Germany

Occupation: software engineer

  • Send private message

2

Wednesday, July 22nd 2009, 11:43pm

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

A1880

Intermediate

  • "A1880" is male

Posts: 500

Date of registration: Jan 1st 2009

Location: Hanover, Germany

Occupation: Software Engineer

Hobbies: Hilbert Curves

  • Send private message

3

Thursday, July 23rd 2009, 1:06pm

Hi,
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

OlimilO

Intermediate

  • "OlimilO" is male
  • "OlimilO" started this thread

Posts: 277

Date of registration: Jan 18th 2009

Location: Germany

Occupation: software engineer

  • Send private message

4

Thursday, July 23rd 2009, 2:49pm

Hi A1880,

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. :D



Viele Grüße

OlimilO

A1880

Intermediate

  • "A1880" is male

Posts: 500

Date of registration: Jan 1st 2009

Location: Hanover, Germany

Occupation: Software Engineer

Hobbies: Hilbert Curves

  • Send private message

5

Thursday, July 23rd 2009, 3:15pm

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

A1880

Intermediate

  • "A1880" is male

Posts: 500

Date of registration: Jan 1st 2009

Location: Hanover, Germany

Occupation: Software Engineer

Hobbies: Hilbert Curves

  • Send private message

6

Thursday, July 23rd 2009, 5:05pm

Hallo,
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

OlimilO

Intermediate

  • "OlimilO" is male
  • "OlimilO" started this thread

Posts: 277

Date of registration: Jan 18th 2009

Location: Germany

Occupation: software engineer

  • Send private message

7

Thursday, July 23rd 2009, 9:37pm

Hallo A1880,



Danke für den Code das sieht ja wirklich gleich viel besser aus! :thumbup:

Ich werde das noch ein wenig testen und dann vermutlich so übernehmen.

Vielen Dank nochmal



OlimilO

theuserbl

Intermediate

Posts: 436

Date of registration: Dec 20th 2008

  • Send private message

8

Thursday, July 23rd 2009, 11:13pm

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ß?

Manuel

Administrator

  • "Manuel" is male

Posts: 256

Date of registration: Jul 16th 2008

Location: Erlangen, Germany

Occupation: Software Developer

Hobbies: Jabaco, game theory, text-mining

  • Send private message

9

Thursday, July 23rd 2009, 11:40pm

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ß?
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.

Rate this thread
WoltLab Burning Board