Kalender Differenzen

Übersicht Monkey Codearchiv

Neue Antwort erstellen

 

DukeS87

Betreff: Kalender Differenzen

BeitragSa, Feb 28, 2015 14:45
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo, da ich für ein aktuelles Projekt die Differenz zwischen 2 Tagen in Sekunden brauchte, habe ich mich mal im Internet schlau gemacht, wie man da was zu berechnen hat.
Im Forum: http://www.a-m-i.de/tips/datetime/datetime.php hab dazu sehr nützliche Algorithmen gefunden. (allerdings in C++)
Meine eigentliche Arbeit lag jetzt quasi nur darin, das in Monkey zu übersetzen.
Und es funktioniert. Ein paar Werte habe ich mithilfe der Seite: http://www.knaak.bplaced.de/So...hp#Rechner überprüft, und die Zeit seit meinem Geburtstag ist auf die Sekunde Deckungsgleich mit den Werten auf der Homepage. (Daher gehe ich erstmal davon aus, dass die Funktionen, zumindest im Zeitraum -27 Jahre bis heute funktionieren. (Ihr könnt das ganze ja auch mal ausprobieren.)

BlitzMax: [AUSKLAPPEN]

#Rem
Converted from C++ To Monkey.
original Code posted on: http://www.a-m-i.de/tips/datetime/datetime.php
Die Parameter der Differenzenfunktionen (Int-Arrays) erwarten mind. ein Int[6]
Man kann somit auch einfach GetDate() aus der Mojo-Lib benutzen um die Aktuelle Zeit zu nutzen
date1[0] << Jahr
date1[1] << Monat (1-Januar bis 12 Dezember)
date1[2] << Tag (1 - 31)
date1[3] << Stunde (0 - 24)
date1[4] << Minute (0-59)
date1[5] << Sekunden (0-59)

#End

Function DiffYear:Int(date1:Int[],date2:Int[])
If (date2[1] > date1[1])
Return date2[0] - date1[0]
EndIf

If (date2[1] < date1[1])
Return (date2[0] - date1[0] - 1 )
EndIf

' // Monate sind identisch.
If (date2[2] > date1[2])
Return date2[0] - date1[0]
EndIf
If (date2[2] < date1[2])
Return date2[0] - date1[0] - 1
EndIf

'// Tag ist bei beiden identisch.
If (date2[3] > date1[3])
Return date2[0] - date1[0]
EndIf
If (date2[3] < date1[3])
Return date2[0] - date1[0] - 1
EndIf

'// Stunde ist identisch
If (date2[4] > date1[4])
Return date2[0] - date1[0]
EndIf

If (date2[4] < date1[4])
Return date2[0] - date1[0] - 1
EndIf

If (date2[5] > date1[5])
Return date2[0] - date1[0]
EndIf

If (date2[5] < date1[5])
Return date2[0] - date1[0] - 1
EndIf

Return date2[0] - date1[0] - 1
End Function


Function DiffDays:Int(date1:Int[],date2:Int[])

'// Ist die Ende-Uhrzeit auch hinter der Startuhrzeit ? Das ist der Normalfall.
'// Andernfalls müssen wir nachher noch eins abziehen!
Local lAbzug:Int = 0

If ( (date2[3] < date1[3]) Or ((date2[3] = date1[3]) And (date2[4] < date1[4])) Or ( (date2[3] = date1[3]) And (date2[4] = date1[4]) And (date2[5] < date1[5])))

Else
lAbzug = 1
EndIf

'// Im gleichen Jahr ? Dann nutzen wir "getTagDesJahres":
If (date2[0] = date1[0])
Return getDayOfYear(date2[2], date2[1],date2[0]) - getDayOfYear(date1[2], date1[1], date1[0]) - lAbzug

ElseIf (date2[0] > date1[0])

'// Wir starten mit der Anzahl Tage im Endejahr:
Local lErgebnis:Int = getDayOfYear(date2[2], date2[1],date2[0]) - lAbzug

Local uJahr:Int = date2[0] - 1

'// Jetzt summieren wir alle dazwischenliegenden Jahre:
While (uJahr > date1[0])
lErgebnis += getDaysOfYear(uJahr)
uJahr -=1
End

'// und addieren schließlich noch die Anzahl der Tage aus dem Start - Jahr:
lErgebnis += (getDaysOfYear(date1[0]) - getDayOfYear(date1[2], date1[1], date1[0]))

Return lErgebnis

Else
Return -1 '; // Die Endezeit liegt vor der Startzeit !
EndIf
End Function


Function DiffSeconds(date1:Int[], date2:Int[])

Local lErgebnis:Int = date2[5] - date1[5]
' // lErgebnis kann durchaus negativ sein ! Wird aber gleich korrigiert.
lErgebnis += (date2[4] - date1[4]) * 60
lErgebnis += (date2[3] - date1[3]) * 3600

'// Im gleichen Jahr ? Dann nutzen wir "getTagDesJahres":
If (date2[0] = date1[0])
Return (((getDayOfYear(date2[2], date2[1],date2[0]) - getDayOfYear(date1[2], date1[1],date1[0])) * 86400) + lErgebnis)

ElseIf (date2[0] > date1[0])

'// Wir starten mit der Anzahl Tage im Endejahr
lErgebnis += getDayOfYear(date2[2], date2[1],date2[0]) * 86400

Local uJahr:Int = date2[0] - 1

'// Jetzt summieren wir alle dazwischenliegenden Jahre:
While (uJahr > date1[0])
lErgebnis += (getDaysOfYear(uJahr) * 86400)
uJahr -=1
End

'// und addieren schließlich noch die Anzahl der Tage aus dem Start - Jahr:
lErgebnis += ((getDaysOfYear(date1[0]) - getDayOfYear(date1[2], date1[1],date1[0])) * 86400)

Return lErgebnis
Else
Return -1'; // Die Endezeit liegt vor der Startzeit !
EndIf
End Function

Function isLeapYear:Bool(_Year:Int)

#Rem
// Die Regel lautet: Alles, was durch 4 teilbar ist, ist ein Schaltjahr.
// Es sei denn, das Jahr ist durch 100 teilbar, dann ist es keins.
// Aber wenn es durch 400 teilbar ist, ist es doch wieder eins.
#End
If ((_Year Mod 400) = 0)
Return True
Else If ((_Year Mod 100) = 0)
Return False
Else If ((_Year Mod 4) = 0)
Return True
EndIf
Return False

End Function

Function getDaysOfMonth:Int(_Month:Int , _Year:Int )

' // ungült,Jan,Feb,Mrz,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez
Local arrTageImMonat:Int[] = [ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]

If (_Month = 2)
'// Februar: Schaltjahr unterscheiden
If (isLeapYear(_Year))
Return 29
Else
Return 28
EndIf
EndIf

If ((_Month >= 1) And (_Month <= 12))
Return arrTageImMonat[_Month]
Else
'// ungültiger Monat !
Return 0
EndIf
End Function

Function getDaysOfYear(_Year:Int)

If isLeapYear(_Year)
Return 366
Else
Return 365
EndIf
End Function

Function getDayOfYear:Int(_Day:Int,_Month:Int,_Year:Int)

' // Der wievielte Tag des Jahres ist dieser Tag
If ((_Month = 0) Or (_Month > 12))
Return -1
EndIf

Local uLokalTag:Int = _Day
Local uLokalMonat:Int = _Month

While (uLokalMonat > 1)

uLokalMonat -=1
uLokalTag += getDaysOfMonth(uLokalMonat, _Year)
End

Return uLokalTag
End Function


Hier ein Kleines Beispielprogramm:
BlitzMax: [AUSKLAPPEN]

#Rem
AUTHOR: Stephan Dukerschein aka DukeS87 Translated from C++ To Monkey from http://www.a-m-i.de/tips/datetime/datetime.php
DATE: 28.02.2015

Simple Example To show how To use some of the Functions.
#End

Import mojo
Import brl
'Import duke2

#GLFW_WINDOW_TITLE="Contest Game"
#GLFW_WINDOW_WIDTH=900
#GLFW_WINDOW_HEIGHT=680
#GLFW_WINDOW_FULLSCREEN=False

'Wichtig zum einladen von benutzerspezifischen Dateien
#TEXT_FILES="*.txt|*.xml|*.json"
#IMAGE_FILES="*.png|*.jpg|*.gif|*.bmp"
#SOUND_FILES="*.wav|*.ogg|*.mp3|*.m4a"
#MUSIC_FILES="*.wav|*.ogg|*.mp3|*.m4a"
#BINARY_FILES="*.bin|*.dat|*.map"

'########################## HAUPTFUNKTION DER APPLIKATION #########################################
Function Main:Int()
New Game 'Konstruktor zum erstellen des Editors
End Function

Class Game Extends App
Field date1:Int[]


Method OnCreate:Int()
SetUpdateRate 60
date1 = New Int[6]
date1[0] = 1987
date1[1] = 8
date1[2] = 17
date1[3] = 11
date1[4] = 46
date1[5] = 0

'diffdate = CalcDateDifference(GetDate(),date2)

Print "Sekunden seit 17.08.1987 um 11:46:00 : " + DiffSeconds(date1, GetDate())
Print "Tage seit 17.08.1987 um 11:46:00 : " + DiffDays(date1,GetDate()) 'Checked with http://www.knaak.bplaced.de/Software/PHP/Datumsrechner.php#Rechner ;; Seems to be right, same amount of Days :D
Return True
End Method

Method OnUpdate:Int()

End Method


Method OnRender:Int()
Cls
Return True
End Method

End Class
 

DukeS87

Betreff: Zusatz

BeitragSa, Feb 28, 2015 23:32
Antworten mit Zitat
Benutzer-Profile anzeigen
So, ich hab schonmal die nächste funktion hinzugefügt: Wochentag.

BlitzMax: [AUSKLAPPEN]

Function getWeekday(_Day:Int, _Month:Int, _Year:Int)

'// ungült Jan Feb Mrz Apr Mai Jun Jul Aug Sep Okt Nov Dez
Local arrMonatsOffset:Int[] = [ 0, 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5]

Local nResult:Int = 0

#Rem
_ASSERT(uTag > 0);
_ASSERT(uTag <= 31);
_ASSERT(uMonat > 0);
_ASSERT(uMonat <= 12);
#End
'// Monat / Tag - Plausi prüfen:
If ((_Day > 31) Or (_Month > 12) Or (_Month <= 0) Or (_Day <= 0) Or (_Year <= 0))

Return -1
EndIf

Local cbTagesziffer:Int = (_Day Mod 7)
Local cbMonatsziffer:Int = arrMonatsOffset[_Month]
Local cbJahresziffer:Int = ((_Year Mod 100) + ((_Year Mod 100) / 4)) Mod 7
Local cbJahrhundertziffer:Int = (3 - ((_Year / 100) Mod 4)) * 2

'// Schaltjahreskorrektur:
If ((_Month <= 2) And (isLeapYear(_Year))
cbTagesziffer = cbTagesziffer + 6
EndIf
nResult = (cbTagesziffer + cbMonatsziffer + cbJahresziffer + cbJahrhundertziffer) Mod 7

#Rem
// Ergebnis:
// 0 = Sonntag
// 1 = Montag
// 2 = Dienstag
// 3 = Mittwoch
// 4 = Donnerstag
// 5 = Freitag
// 6 = Samstag
#End
Return nResult
End Function


Ich bin leider kein C++ Profi, daher mal ne kleine Frage am Rande, weiss zufällig jemand, was die Aufrufe
_ASSERT(uTag > 0);
_ASSERT(uTag <= 31);
_ASSERT(uMonat > 0);
_ASSERT(uMonat <= 12);
bewirken? ich habe sie einfach mal auskommentiert, und scheint trotzdem zu funktionieren.

Holzchopf

Meisterpacker

BeitragSo, März 01, 2015 11:35
Antworten mit Zitat
Benutzer-Profile anzeigen
Bin auch kein C++ Mensch, aber wenn ich mich nicht irre, macht die Funktion folgendes: Im Debug-Modus prüft sie, ob der Ausdruck wahr ist, sonst bricht sie die Ausführung des Programms mit einer Fehlermeldung ab.
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BY-SABinaryBorn - King's Hand ♫ (16.11.2016)
Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm

DAK

BeitragSo, März 01, 2015 11:53
Antworten mit Zitat
Benutzer-Profile anzeigen
Jup, das ist genau was es tut. Assert ist zur Input Validation da, stellt also sicher, dass man keinen Mist eingibt. Allerdings ist Assert(Tag<=31) etwas nutzlos, da so z.B. ein 31.2. durchgeht. Da müsste das Assert schon etwas komplexer sein.
Gewinner der 6. und der 68. BlitzCodeCompo
 

#Reaper

Newsposter

BeitragSo, März 01, 2015 13:39
Antworten mit Zitat
Benutzer-Profile anzeigen
Frage: Müsste bei sowas nicht eigentlich auch die Schaltsekunde mit berücksichtigt werden? Schließlich wurde ja in der Zwischenzeit alle paar Jahre mal eine Sekunde addiert - oder anders ausgedrückt: übersprungen (Oder wars doch andersrum?). Scheinen demnach aber der Rechner auf der Website auch nicht zu berücksichtigen.
AMD Athlon 64 3500+, ATI AX800 Pro/TD, 2048 MB DRR 400 von Infineon, ♥RIP♥ (2005 - Juli 2015 - sic!)
SoundBlaster X-Fi XtremeGamer Fatal1ty Profess1onal Series von Creative

Blitz3D, BlitzMax, MaxGUI, Monkey X; Win XP, Win7

Holzchopf

Meisterpacker

BeitragSo, März 01, 2015 14:02
Antworten mit Zitat
Benutzer-Profile anzeigen
Es gab ein paar Schaltsekunden, ja. Aber diese sind völlig unregelmässig (Quelle: http://de.wikipedia.org/wiki/S...ltsekunden). Daher ist die Beachtung der Schaltsekunden technisch schon mal gar nicht so trivial. Und das bezieht sich jetzt nur auf die bereits vergangenen Schaltsekunden.

Ausserdem verbietet ja niemand die Verwendung der überholten Sonnensekunde.

Die Frage auf "Müsste..?" würde ich deshalb mit nein beantworten. Bin aber auch kein Metrologe Rolling Eyes
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BY-SABinaryBorn - King's Hand ♫ (16.11.2016)
Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm
 

DukeS87

BeitragSo, März 01, 2015 15:29
Antworten mit Zitat
Benutzer-Profile anzeigen
Kommt halt drauf an wie exakt man sein moechte. Aber ueberlege mal, angenommen alle 4 jahre kommt eine schaltsekunde, waere der kalender nach 4*60 jahren um 1 minute daneben. Bis der kalender also um einen halben tag falsch laeuft, muessten 4*60*60*12 jahre vergehen.
 

#Reaper

Newsposter

BeitragSo, März 01, 2015 17:00
Antworten mit Zitat
Benutzer-Profile anzeigen
Die Schaltsekunden müsste man fest einprogrammieren, anders ginge es nicht. Dürfte nicht so schwer sein.
Ich erwähnte das Ganze aber eh nur, weil ja eben nach einer sekundengenauen Berechnung gefragt worden war. Wink I den 27 Jahren gab es ja bereits 11 Schaltsekunden. Razz
Very Happy
AMD Athlon 64 3500+, ATI AX800 Pro/TD, 2048 MB DRR 400 von Infineon, ♥RIP♥ (2005 - Juli 2015 - sic!)
SoundBlaster X-Fi XtremeGamer Fatal1ty Profess1onal Series von Creative

Blitz3D, BlitzMax, MaxGUI, Monkey X; Win XP, Win7

Neue Antwort erstellen


Übersicht Monkey Codearchiv

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group