German [B4A] "DateTime.DateFormat" greift nicht immer?!

Tan

Member
Licensed User
Longtime User
Hallo zusammen,

hat einer von euch eine Idee, warum manchmal ein gesetztes DateTime.DateFormat nicht greift?
Ich setze jetzt schon an jeder nur erdenklichen Stelle das DateFormat neu, trotzdem kommt es in meiner App immer mal wieder vor, dass das Format plötzlich in der Form z.B. "2016-04-14" zurückgegeben wird?!?

----
java.text.ParseException: Unparseable date: "2016-04-06" (at offset 4)
at java.text.DateFormat.parse(DateFormat.java:555)
at anywheresoftware.b4a.keywords.DateTime.DateParse(DateTime.java:148)
at de.tuerel.fahrtenplaner.main._btndateminus_click(main.java:723)

----

Ich habe sicherherheitshalber vor DateTime.Date und DateTime.Parse Operationen immer das Format neu gesetzt... aber manchmal (selten) ignoriert er das. Der Fehler ist nicht reproduzierbar...

Z.B.

Sub btnDatePlus_Click
DateTime.DateFormat = "dd.MM.yyyy"
Dim ticks, ticks2 As Long
ticks = DateTime.DateParse(Starter.SelectedDate)
ticks2 = DateTime.Add(ticks,0,0,1)
Starter.SelectedDate = DateTime.Date(ticks2)
ReloadDB(True)
End Sub


Irgendjemand eine Idee?

VG
Tan
 

KMatle

Expert
Licensed User
Longtime User
Wenn Du das Datum auf das deutsche Format einstellst, dann erwartet DateParse auch das deutsche. Andere Formate gehen dann nicht (gerade ausprobiert).

Die Frage ist, warum Starter.SelectedDate "YYYY-MM-DD" enthält. Wahrscheinlich kommt das Format aus der DB. Also: Entweder oder...
 

Tan

Member
Licensed User
Longtime User
Hi, genau das ist ja der Punkt. Datum habe ich in der Datenbank als String im deutschen Format gespeichert und an JEDER Stelle, wo ich "Starter.SelectedDate" (String!) neu schreibe und ein DateParse mache, setze ich vorher das Datumsformat sicherheitshalber neu... z.B.

DateTime.DateFormat = "dd.MM.yyyy"
Starter.SelectedDate = DateTime.Date(DateTime.Now)


Das klappt auch zu 99,9%, aber ganz sporadisch ignoriert die App plötzlich das Format und spuckt ein englisches aus!?!
Ich habe jetzt schon eine "Hilfsfunktion" an jeder Stelle dazwischen gesetzt, um im Notfall das Datum manuell zu konvertieren... aber das muss ja trotzdem einen Grund haben!?!

---

Wenn Du das Datum auf das deutsche Format einstellst, dann erwartet DateParse auch das deutsche. Andere Formate gehen dann nicht (gerade ausprobiert).

Die Frage ist, warum Starter.SelectedDate "YYYY-MM-DD" enthält. Wahrscheinlich kommt das Format aus der DB. Also: Entweder oder...
 

RauchG

Active Member
Licensed User
Longtime User
Beim öffnen einer neuen Activity ist das DateFormat immer yyyy-MM-dd. Auch wenn in den Einstellungen das deutsche Format eingestellt ist. In meinen db3 erstelle ich immer DateTime Felder. Das US Format speichere ich auch im Format yyyy-MM-dd weg.

DateTime.DateFormat = "dd.MM.yyyy"
Starter.SelectedDate = DateTime.Date(DateTime.Now)

Das müsste heißen:

DateTime.DateFormat = "yyyy-MM-dd
Starter.SelectedDate = DateTime.Date(DateTime.Now)

Damit kannst du rechnen.

Wenn du zur Anzeige in einem Formular das deutsche Format brauchst, musst du wieder das Format in deutsch setzen.

DateTime.DateFormat = "yyyy-MM-dd"
DateTick = DateTime.DateParse(BSS.mBesuchsdatum)
DateTime.DateFormat = "dd.MM.yyyy"
BSS.mBesuchsdatum = DateTime.Date(DateTick)

Wenn du nach diesem Parsen für die Anzeige im Formular wieder speichern willst, muss du wieder in das US Format parsen.

Solange eine Activity geöffnet ist, gilt immer das zuletzt gesetzte Format.

Das hin- und her Parsen ist echt nervig. Da ich für meine Apps mehrere Formate brauche, habe ich mir eine kleine Class geschrieben mit der man das Format eines Datums ausliest und dann in das gewünschte Format parsen kann. Wenn du Interesse hast kann ich es hier reinstellen.

Gruß
RauchG
 

Tan

Member
Licensed User
Longtime User
Hallo RauchG,

ich hatte mich jetzt auf das deutsche Format festgelegt, aber eigentlich sollte das ja auch völlig egal sein, wenn ich dies konsequent in der gesamten APP beibehalte. Es funktioniert ja auch alles einwandfrei... das Handling mit DateFormat ist mir auch klar... NUR: manchmal wird das vorgegebene DateFormat einfach ignoriert, und wenn ich nun ein deutsches Format erwarte, mein Datedialog aber nach konvertierung eigentlich ein deutsches Format ausgeben sollte, stattdessen aber das englische, dann knallt es natürlich beim parsen... und das verstehe ich nicht! Warum wird das Format manchmal ignoriert (Memory Leak?, Android Bug?)?

z.B.

Sub btnDateSelect_Click
DateTime.DateFormat = "dd.MM.yyyy"
Dim ret As Int
ret = dd.Show("", "Tagesdatum", "Ok", "Abbrechen", "", Null)
If ret = -1 Then ' if -1 then reload database with new date
Starter.ShowAll = False
Starter.SelectedDate = Functions.CheckDate(DateTime.Date(dd.DateTicks))
ReloadDB(True)
End If
End Sub


Im Moment prüfe ich mit der Function CheckDate und konvertiere ggf., wenn es doch im englischen Format kommt, obwohl dies eigentlich nicht passierden dürfte! Dafür setze ich ja vorher nochmal das DateFormat auf MEINE zu erwartende Variante...

Das ist wirklich seltsam... die App User nutzen die Anwendung den ganzen Tag und es kommt nur wirklich SELTEN vor, aber es kommt vor...

Viele Grüße
Tan
 

RauchG

Active Member
Licensed User
Longtime User
(Memory Leak?, Android Bug?)?

Das glaube ich nicht. Wenn du den Fehler nicht reproduzieren kannst gehst du beim testen deiner App, nicht den Weg der den Fehler produziert. Je umfangreicher eine App ist, desto schwerer ist es versteckte Bugs zu finden. Nach meiner Erfahrung finden die Tester, egal wieviele nicht alle Bugs. Wer die Bugs findet, sind die User. Und da musst du ansetzen.

Hier ist eine Anleitung von Erel, damit wird der Fehler auf jeden Fall gefunden. Vorrausetzung ist, du kannst deine User mit einbinden.
https://www.b4x.com/android/forum/threads/uncaught-exceptions.59805/#content

Hier ist meine Version von Erels Vorlage. Eingebaut in die Starter.

B4X:
#Region  Service Attributes
    #StartAtBoot: False
    #ExcludeFromLibrary: True
#End Region

Sub Process_Globals

    Dim aktuelleActivity As Object                'CrashTakeScreenShot
    Private logs As StringBuilder
    Private logcat As LogCat
    Private const emailAddress As String = "[email protected]"                '####################### geht nur, wenn im Release Modus debug #######################

End Sub

Sub Service_Create
    logs.Initialize
#if RELEASE
    logcat.LogCatStart(Array As String("-v","raw","*:F","B4A:v"), "logcat")
#end if
End Sub

Sub Service_Start (StartingIntent As Intent)

End Sub

Private Sub logcat_LogCatData (Buffer() As Byte, Length As Int)
    logs.Append(BytesToString(Buffer, 0, Length, "utf8"))
    If logs.Length > 5000 Then
        logs.Remove(0, logs.Length - 4000)
    End If
End Sub

'Return true to allow the OS default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    'wait for 500ms to allow the logs to be updated.
    Dim jo As JavaObject
    Dim l As Long = 500
    jo.InitializeStatic("java.lang.Thread").RunMethod("sleep", Array(l))
    logcat.LogCatStop
    logs.Append(StackTrace)

    LogWrite(logs)
    SendEMail

    Return True
End Sub

Sub Service_Destroy

End Sub

Sub LogWrite(Eventslog As String)

    Dim TextWriter2 As TextWriter
    Dim sdRoot As String
    Dim now As Long
    now = DateTime.now

    sdRoot = File.DirRootExternal & "/"

    If File.Exists(File.DirRootExternal, "crashlog.txt") = True Then
        File.Delete(File.DirRootExternal, "crashlog.txt")
    End If

    Optionen.LoadOptionen

    DateTime.DateFormat = "dd.MM.yyyy HH:mm"

    File.WriteString(File.DirRootExternal, "crashlog.txt", "")
    TextWriter2.Initialize(File.OpenOutput(sdRoot, "crashlog.txt", True))
    TextWriter2.WriteLine("***************************" & CRLF & _
                            Application.VersionName & Application.VersionCode & CRLF & _
                            "apk_datum: " & Optionen.mapk_datum & CRLF & _
                            "Crash Datum: " & DateTime.Date(now) & CRLF & _
                            "Combera ID: " & HDB.mCombera_ID & CRLF & _
                            "***************************" & CRLF & _
                            CRLF & now & CRLF & "- " & Eventslog & CRLF)

    TextWriter2.Close
'    Log(    Application.VersionCode)            '40
'    Log(    Application.VersionName)            'cp

End Sub

Sub SendEMail

    Dim email As Email
    Dim filename As String = CallSub(aktuelleActivity,"MakeScreenshot")                'CrashTakeScreenShot

    Optionen.LoadOptionen

    email.To.Add(emailAddress)
    email.Subject = "Programm-Fehler: " & Main.mActionName & ", " & Optionen.mgebiet_intern & ", " & Optionen.mvorname & " " & Optionen.mnachname

    email.Body = "Fehler Text in der Anlage." & Chr(13) & "Der Fehler wird an COMBERA gesendet."
    email.Attachments.Add(File.Combine(File.DirRootExternal, "crashlog.txt"))
    email.Attachments.Add(filename)                'CrashTakeScreenShot

    StartActivity(email.GetIntent)

End Sub

Gruß
RauchG
 
Last edited:

Tan

Member
Licensed User
Longtime User
Das habe ich schon lange in meiner App eingebaut (sehr hilfreiches Feature). :)
Jegliche Exception wird abgefangen, in ein Log File (inkl. Stacktrace) geschrieben, und dem User eine Möglichkeit gegeben, einen Fehlerbericht via E-mail zu senden.

StackTrace: java.text.ParseException: Unparseable date: "2016-04-06" (at offset 4)
at java.text.DateFormat.parse(DateFormat.java:555)
at anywheresoftware.b4a.keywords.DateTime.DateParse(DateTime.java:148)
at de.tuerel.fahrtenplaner.main._btndateminus_click(main.java:723)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:157)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:153)
at anywheresoftware.b4a.objects.ViewWrapper$1.onClick(ViewWrapper.java:78)
at android.view.View.performClick(View.java:4448)
at android.view.View$PerformClick.run(View.java:18459)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5135)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:606)
at dalvik.system.NativeStart.main(Native Method)


---

Sub btnDateMinus_Click
DateTime.DateFormat = "dd.MM.yyyy"
Dim ticks, ticks2 As Long
ticks = DateTime.DateParse(Starter.SelectedDate)
ticks2 = DateTime.Add(ticks,0,0,-1)
Starter.SelectedDate = DateTime.Date(ticks2)
ReloadDB(True)
End Sub


Mehr ist das nicht... und es gibt KEINE Stelle im Code, wo ich Starter.SelectedDate (String) setze, ohne auf das deutsche Format zu achten!

Ich glaube irgendwie doch, das es sich um einen Bug handeln muss...
Vielleicht sollte ich auch einfach alle Daten als Ticks abspeichern.

Ich weiß, es gibt undendlich viele Fehlerquellen in einer komplexen App, die eigentlich nur von den Benutzern selber gefunden werden können... aber in diesem Fall gibt es nicht so viele Stellen im Code, die das verursachen könnten!

Und es taucht nur sehr sehr selten auf.. die Abläufe in der App sind aber immer die gleichen (ist eine App für Krankenfahrdienste).

Vielen Dank für deine Mühe!!!

VG
Tan

Das glaube ich nicht. Wenn du den Fehler nicht reproduzieren kannst gehst du beim testen deiner App, nicht den Weg der den Fehler produziert. Je umfangreicher eine App ist, desto schwerer ist es versteckte Bugs zu finden. Nach meiner Erfahrung finden die Tester, egal wieviele nicht alle Bugs. Wer die Bugs findet, sind die User. Und da musst du ansetzen.

Hier ist eine Anleitung von Erel, damit wird der Fehler auf jeden Fall gefunden. Vorrausetzung ist, du kannst deine User mit einbinden.
https://www.b4x.com/android/forum/threads/uncaught-exceptions.59805/#content

Hier ist meine Version von Erels Vorlage. Eingebaut in die Starter.

B4X:
#Region  Service Attributes
    #StartAtBoot: False
    #ExcludeFromLibrary: True
#End Region

Sub Process_Globals

    Dim aktuelleActivity As Object                'CrashTakeScreenShot
    Private logs As StringBuilder
    Private logcat As LogCat
    Private const emailAddress As String = "[email protected]"                '####################### geht nur, wenn im Release Modus debug #######################

End Sub

Sub Service_Create
    logs.Initialize
#if RELEASE
    logcat.LogCatStart(Array As String("-v","raw","*:F","B4A:v"), "logcat")
#end if
End Sub

Sub Service_Start (StartingIntent As Intent)

End Sub

Private Sub logcat_LogCatData (Buffer() As Byte, Length As Int)
    logs.Append(BytesToString(Buffer, 0, Length, "utf8"))
    If logs.Length > 5000 Then
        logs.Remove(0, logs.Length - 4000)
    End If
End Sub

'Return true to allow the OS default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    'wait for 500ms to allow the logs to be updated.
    Dim jo As JavaObject
    Dim l As Long = 500
    jo.InitializeStatic("java.lang.Thread").RunMethod("sleep", Array(l))
    logcat.LogCatStop
    logs.Append(StackTrace)

    LogWrite(logs)
    SendEMail

    Return True
End Sub

Sub Service_Destroy

End Sub

Sub LogWrite(Eventslog As String)

    Dim TextWriter2 As TextWriter
    Dim sdRoot As String
    Dim now As Long
    now = DateTime.now

    sdRoot = File.DirRootExternal & "/"

    If File.Exists(File.DirRootExternal, "crashlog.txt") = True Then
        File.Delete(File.DirRootExternal, "crashlog.txt")
    End If

    Optionen.LoadOptionen

    DateTime.DateFormat = "dd.MM.yyyy HH:mm"

    File.WriteString(File.DirRootExternal, "crashlog.txt", "")
    TextWriter2.Initialize(File.OpenOutput(sdRoot, "crashlog.txt", True))
    TextWriter2.WriteLine("***************************" & CRLF & _
                            Application.VersionName & Application.VersionCode & CRLF & _
                            "apk_datum: " & Optionen.mapk_datum & CRLF & _
                            "Crash Datum: " & DateTime.Date(now) & CRLF & _
                            "Combera ID: " & HDB.mCombera_ID & CRLF & _
                            "***************************" & CRLF & _
                            CRLF & now & CRLF & "- " & Eventslog & CRLF)

    TextWriter2.Close
'    Log(    Application.VersionCode)            '40
'    Log(    Application.VersionName)            'cp

End Sub

Sub SendEMail

    Dim email As Email
    Dim filename As String = CallSub(aktuelleActivity,"MakeScreenshot")                'CrashTakeScreenShot

    Optionen.LoadOptionen

    email.To.Add(emailAddress)
    email.Subject = "Programm-Fehler: " & Main.mActionName & ", " & Optionen.mgebiet_intern & ", " & Optionen.mvorname & " " & Optionen.mnachname

    email.Body = "Fehler Text in der Anlage." & Chr(13) & "Der Fehler wird an COMBERA gesendet."
    email.Attachments.Add(File.Combine(File.DirRootExternal, "crashlog.txt"))
    email.Attachments.Add(filename)                'CrashTakeScreenShot

    StartActivity(email.GetIntent)

End Sub

Gruß
RauchG
 

Tan

Member
Licensed User
Longtime User
Nimm besser deine E-Mail Adresse aus dem Code Schnipsel :)

Die Screenshot Funktion ist interessant :), die habe ich nur in meinem Errorhandler in der Windows Applikation. Funktioniert das zuverlässig auf unterschiedlichen Android Handys???
 
Last edited:

RauchG

Active Member
Licensed User
Longtime User
Nimm besser deine E-Mail Adresse aus dem Code Schnipse
;) Hab ich gemacht.

Die Screenshot Funktion ist eigentlich eine Spielerei. Je nachdem wo der Bug sitzt, kann der Screenshot auch mal leer sein. In der Crash Mail sieht man ja auch wo es passiert. Läuft auf allen Geräten.

Ich will aber doch nicht glauben, dass es außerhalb deiner App liegt. Was passiert denn bei btnDateMinus_Click. Log dochmal das Datum an dieser Stelle. Hat es da schon das deutsche Format?
 

Tan

Member
Licensed User
Longtime User
Ja, das Format ist IMMER das korrekte.... ganz selten (ich sag jetzt mal, alle 100 Klicks) steht dann aber anscheinend das englische Format in der Variable SelectedDate, obwohl ich diese Variable nur an 5 (!!) Stellen in meiner App setze:

upload_2016-4-16_19-37-57.png


Und hier habe ich jetzt schon hundertmal geprüft, ob ich auch immer das 100% richtige DateFormat vorher setze! :-/
(Btw: Die CheckDate Funktion habe ich jetzt notdürftig eingebaut, um im Fehlerfall on the fly konvertieren zu können...)

Würdest du die Screenshot Funktion evtl. öffentlich machen? :)
 

KMatle

Expert
Licensed User
Longtime User
Apropos Datenbank: Bist Du WIRKLICH sicher, dass das Datum immer gleich geliefert wird? (ich habe mich auch schon oft selbst vera.....). Ist das MySQL via php? Vielleicht irgendeine Kleinigkeit im php Script? Ich glaube nicht, dass das ein Bug sein kann, weil die Funktionen sehr oft genutzt werden und noch kein Bug festgestellt wurde.
 

Tan

Member
Licensed User
Longtime User
Hi,

JA! :)

Aus diesem Grunde sende ich im Crash Report auch eine Kopie der lokalen SQLite DB mit und hier passt das Format auch!
Daten kommen per Push/GCM und werden über einen Service in eine DB geschrieben und erst bei Bedarf dem User in der App angezeigt:

upload_2016-4-17_11-28-52.png


Column Typ: TEXT

Ich weiß, es gibt Fehler, die nur unter ganz ungünstigen Bedingungen auftauchen und kaum nachvollziehbar sind, aber in diesem Fall gibt es kaum Fehlerquellen...
 

Tan

Member
Licensed User
Longtime User
Alles klar... ich kann mit dem "Problem" auch leben (mit meiner Helper Funktion).
Wollte nur wissen, ob dieses Phänomen bekannt ist!

Danke für den Link!
 

Tan

Member
Licensed User
Longtime User
BTW: Kann es sein, das LogCat innerhalb der App (wie im ErrorLog Thread von Erel beschrieben) ab Android 5.x nicht mehr funktioniert?
Ich bekome zwar eine Ausgabe via ADB und B4A, aber innerhalb der App wird leider nichts protokolliert (DataEvent löst nicht aus)!?!

Nachtrag:

Es scheint nur bei meinem Huawei P8 Lite nicht zu funktionieren, bei meinem Samsung Galaxy Tab S2 bekomme ich ein LogCat!
 

RauchG

Active Member
Licensed User
Longtime User
Auf Galaxy Note 4 (Android 5.1.1), Sony Ixperia (Android 5.1.1) und One Plus 1 (Android 5.1.1) geht es.
 

Tan

Member
Licensed User
Longtime User
Meinst du wirklich den LogCat Auszug im Error Report oder nur den Stacktrace??
Der Stacktrace geht auf jeden Fall! Aber bei meinem Huawei wird der LogCat-Auszug nicht mit erzeugt...

Bei dem Huawei habe ich auch nur eine Logging Ausgabe innerhalb der IDE via ADB USB, nicht aber über die B4A Bridge, keine Anhnung, was Huawei da gebastelt hat!
 

RauchG

Active Member
Licensed User
Longtime User
Ich meine den "LogCat Auszug im Error Report".

Der Error Report funktioniert nur im Release Compile. Schreib doch mal einen Fehler ins Script (wie Erel).
 

Tan

Member
Licensed User
Longtime User
Ich habe in meiner App eine "Test-Exception" eingebaut, die ich dann zum Testen auslösen kann... wie gesagt, auf meinem Huawei wird kein LogCat (im Relase Mode) gesammelt... das scheint aber an der FW von Huawei zu liegen, auf anderen Geräten scheint es ja zu gehen! Vielen Dank für deine Hilfe! :)

Ich meine den "LogCat Auszug im Error Report".

Der Error Report funktioniert nur im Release Compile. Schreib doch mal einen Fehler ins Script (wie Erel).
 
Top