SQLite-Frage zu Zeitzone und Ausgabe

  • Antworten:11
anamollo
  • Forum-Beiträge: 24

26.12.2016, 13:18:40 via Website

Hallo zusammen,

ich bin am Verzweifeln...seit Stunden versuche ich folgende Probleme meiner App zu beheben, weshalb ich nun auf eure Hilfe hoffe:

Ich habe eine App geschrieben, welche drei Buttons besitzt.
Das Ganze ist eine App, mit der ich meine Arbeitszeit erfassen möchte.
Diese soll durch Drücken auf Button "Kommen" in die Spalte-2 der SQLite-DB die derzeitige Systemzeit und das aktuelle Datum in Spalte-1 der SQLite-DB schreiben. Beim Drücken auf "Gehen", soll die aktuelle Uhrzeit in Spalte-3 in die SQLite-DB geschrieben werden.
Drückt man auf "Zeitnachweis anzeigen", soll in der TextView die gesamte Tabelle mit Datum, Kommen-Zeit und Gehen-Zeit über einen längeren Zeitraum (sprich so oft eben auf Kommen und Gehen gedrückt wurde) angezeigt werden.

Nun zu den für mich nicht lösbaren Problemen:
- Laut Internetrecherche soll es möglich sein, die Zeitzone, die die SQLite-DB beim Schreiben der Werte verwenden soll, vorzugeben.
Beim Drücken auf "Kommen" oder "Gehen" wird immer eine Uhrzeit einer anderen Zeitzone in die DB geschrieben, und zwar immer eine Stunde zu früh als die "Systemzeit" des Systems ist (Beispiel: Es ist in Deutschland 09:00 Uhr, in meine SQLite-DB wird aber 08:00 geschrieben).
Was mache ich falsch?

Zweites Problem:
- Wie ich oben beschrieben habe, sollen beim Drücken auf "Zeitnachweis anzeigen" ALLE DB-Einträge in der TextView angezeigt werden. Dies geschieht aber nicht. Es wird immer nur EIN Werte-Eintrag (Datum, Kommen, Gehen) angezeigt.
Was mache ich da falsch, damit die Werte der gesamten DB-Tabelle nicht angezeigt werden?

Im Anhang befindet sich der Quellcode und ein Screenshot vom Layout der App.

Quellcode

image

Vielen Dank schonmal für eure Hilfe!

Grüße
Joh

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

26.12.2016, 14:24:08 via Website

Hallo Joh,
kann sein, dass SQLite die falsche Zeitzone verwendet, aber warum liest du nicht die Zeit in der passenden Zeitzone im JavaCode und machst dann ein Insert anstatt die vorgefertigten konstanten zu nehmen - geht einfacher.
bzw. je nachdem in welchem Format du die Zeit speicherst würde ich eifnach System.currentMillis() nehmen. ist eine Long und gibt die die millisek sei 1.1.1970 zurück. Damit bist du immer in der Zeitzone in der sich dein Gerät befindet.
Musst dann halt beim Anzeigen in deutsches Zeitformat umrechen...

Aber ich denke ein direktinsert der Zeit ohne SQLite konstantent dürfte gehen.

Deine schleife zum auswerten würde ich anders gestalten:

if(c.moveToFirst()){
        do
                {
                        buffer.append(c.getString(0) + "   ");
                        buffer.append(c.getString(1) + "   ");
                        buffer.append(c.getString(2) + "\n");

                } while (c.moveToNext());
txt_zeitnachweis.setText(buffer.toString());
  }
c.close();

Sind deine Datenbankfelder alle strings??
Ich weiß nicht ob getString nicht nur String felder zurückgibt sondern alle, aber du sagtest ja dass nur einer angezeigt wird.

LG Pascal //It's not a bug, it's a feature. :) ;)

anamollo

Antworten
anamollo
  • Forum-Beiträge: 24

26.12.2016, 16:08:14 via Website

Hallo Pascal!

Vielen Dank für deine schnelle und nette Antwort! :)
Ah, das ist natürlich eine sehr gute Idee, manchmal kommt man nicht aufs Einfachste.

Ich habe das Problem mit der Zeitzone dank deiner Hilfe beheben können. Vielen Dank! :)

Nun besteht noch das Problem mit der Ausgabe aller DB-Einträge.
Ich habe deinen Code-Snippet mit der If-Anweisung/Schleife in meinem Code implementiert, leider wird immer noch nur der letzte DB-Eintrag (und somit eine Zeile a la: "2016-12-26 16:06 16:09") angezeigt.
Irgendwas scheint da noch nicht zu stimmen :-/

Was mache ich nur falsch :(
Danke vielmals!

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

26.12.2016, 16:31:43 via Website

Debugge das mal durch - schau mit count() wieviele Zeilen im Cursor sind, das mal zuerst
Dann setzt du in der While einen Breakpoint und schaust wie ob er da durchkommt.
Eigentlich geht das so, habe es selbst so verwendet...

LG Pascal //It's not a bug, it's a feature. :) ;)

anamollo

Antworten
anamollo
  • Forum-Beiträge: 24

27.12.2016, 11:00:32 via Website

Guten Morgen!

Dank Dir gibt er nun immerhin schon mehrere Zeilen im TextView aus.
Ich habe nun die UPDATEs in der Kommen.ClickListener() auf INSERT INTO umgeändert.
Bei UPDATE verändert er ja nur bestehende Werte, weshalb er auch immer nur eine Zeile angelegt hat..(cool)
Ich habe wie du sagtest auch einen Toast eingefügt, der jedoch je einfachem Drücken auf Kommen und Gehen sich um "2" erhöht und komischerweise nicht nur um "1".

Die Einträge in der Ausgabe der TextView stimmen aber leider noch immer nicht.
Drücke ich einmalig auf "Kommen", kurz danach auf "Gehen" und dann auf "Zeitnachweis anzeigen", wird mir folgendes in der TextView angezeigt:

2016-12-27 2016-12-27 11:23:46 11:25
2016-12-27 11:23:46 11:23 2016-12-27
11:23:46

Warum macht der diese komische Ausgabe, obwohl ich in der do-While-Schleife ja eigentlich jeden Wert nur einmal ausgebe?
Im Anfang des Programms mache ich nun übrigens zum Testen der App eine "DROP TABLE" (Tabelle bei jedem Start der App löschen), sonst habe ich zig Einträge.

Ich habe nochmal den jetzigen Quellcode hochgeladen, der ist unter folgendem Link verfügbar:
Link

Die App soll einfach nur sämtliche Einträge (Datum, Kommen, Gehen) nebeneinander zeilenweise anzeigen. Aber das macht er nicht.

Hast du noch Tipps?

Grüße und Danke!

— geändert am 27.12.2016, 11:32:12

Antworten
anamollo
  • Forum-Beiträge: 24

31.12.2016, 21:51:21 via Website

Habt ihr noch einen Tipp für mich?
Wäre Euch sehr dankbar...

Einen guten Rutsch wünsche ich!

Antworten
Andy N.
  • Forum-Beiträge: 22.375

31.12.2016, 22:42:40 via Website

Hallo anamollo

Bitte nicht pushen. Ich Ich bin mir sicher, dass sich hier jemand melden wird, sobald er weitere Tipps für dich hat. Danke (smug)

PS: guten Rutsch

Viele Grüße,
Andy


OnePlus 3 (Resurrection Remix 5.8.2)
LG G Watch

Regeln | unsere Mods & Admins

swa00

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

06.01.2017, 14:12:08 via Website

So ich hab mir den Code jetzt nochmal angeschaut.

  1. Die Datenbankstruktur (Tabelle) ist grauenhaft ist aber für die funktion erstmal egal.
  2. Ich habe mir die App mal installiert und Daten in die Tabelle geschrieben.

Danach habe ich mir die DB datei auf meinen Rechner gezogen und mir den Inhalt angeschaut:
image
Da brauch man sich nicht wundern, wenn in der Ausgabe ganu das rauskommt was in der DB steht...

Zuerstmal:
1. Baue dir eine gescheite DB
z.b.
ID int autoincrement [Für Datensatzidentifizierung]
Datum DATE NOT NULL -- Datumsfeld darf nicht null sein!
Kommen TIME null -- Zeiten speichert man immer im passendne Datentyp und nciht als String!
Gehen TIME null
[Arbeitszeit TIME null] - kannst du dir aus den Zeiten auch immer neu berechnen

So jetzt musst du mit den Inserts etc. aufpassen.
Android hat extra Methoden wo man nicht mir SQL Queries hantieren muss, vlt ist das die bessere Wahl.

Ansonsten musst du die Fälle unterscheiden:
1. Es gibt noch keinen Eintrag für heutiges Datum -> Datum anlegen und kommen Zeit schreiben.
2. Gehen: Gehen Zeit ins Gehen Feld schreiben - Where Datum='Heute' and Gehen is null -- Gerade damit du in die Zeile schreibst, wo Gehen noch leer ist, damit du an einem Tag mehrmals kommen und gehen kannst, ohne dir eine Daten zu überschreiben.
3. Überprüfungen: Z.b. wurde vor dem Gehen auf kommen gedrückt? Jemand der nciht anwesen ist kann nicht Gehen,
4. Zur darstellung würde ich keine TextView sondern eine ListView etc.. nehmen, aber das ist dann mehr oder weniger Designsache

LG Pascal //It's not a bug, it's a feature. :) ;)

swa00

Antworten
anamollo
  • Forum-Beiträge: 24

06.01.2017, 14:51:18 via Website

Ok, Danke erstmal Pascal.

Ich habe nun folgendes gemacht:

  1. Baue dir eine gescheite DB
    z.b.
    ID int autoincrement [Für Datensatzidentifizierung]

Dies habe ich nun so gelöst:
db.execSQL("CREATE TABLE IF NOT EXISTS Zeiterfassung(ID INTEGER PRIMARY KEY AUTOINCREMENT, Datum DATE , Kommen TIME , Gehen TIME , Arbeitszeit TIME);");

  1. Es gibt noch keinen Eintrag für heutiges Datum -> Datum anlegen und kommen Zeit schreiben.

Dies sollte mit dem Code nach Klicken auf "Kommen" passieren:

db.execSQL("INSERT INTO Zeiterfassung (Datum) VALUES (DATE(\'now\'));");
db.execSQL("INSERT INTO Zeiterfassung (Kommen) VALUES (\'" + time + "\');");
  1. Gehen: Gehen Zeit ins Gehen Feld schreiben - Where Datum='Heute' and Gehen is null -- Gerade damit du in die Zeile schreibst, wo Gehen noch leer ist, damit du an einem Tag mehrmals kommen und gehen kannst, ohne dir eine Daten zu überschreiben.

Wenn ich auf "Gehen" drücke, soll er nun diesen Code ausführen:

db.execSQL("UPDATE Zeiterfassung SET Gehen = \'" + time + "\' WHERE Datum = DATE(\'now\') AND Gehen = null;");

Zu Punkt 3) Habe ich noch nicht implementiert, aber das macht Sinn, das stimmt. :)
Zu Punkt 4) Gute Idee, dann hätte ich gleich die tabellenähnliche Darstellung.

Führe ich nun die App aus, erhalte ich im (derzeit noch) TextView:

2017-01-06 | null | null null | 14:46 | null

Hier nochmal meine SQLite-Statements:

1) Erstellen der Tabelle:

db.execSQL("CREATE TABLE IF NOT EXISTS Zeiterfassung(ID INTEGER PRIMARY KEY AUTOINCREMENT, Datum DATE , Kommen TIME , Gehen TIME , Arbeitszeit TIME);");

2) Bei Klick auf "Kommen":

db.execSQL("INSERT INTO Zeiterfassung (Datum) VALUES (DATE(\'now\'));");
db.execSQL("INSERT INTO Zeiterfassung (Kommen) VALUES (\'" + time + "\');");

3) Bei Klick auf "Gehen":

 db.execSQL("UPDATE Zeiterfassung SET Gehen = \'" + time + "\' WHERE Datum = DATE(\'now\') AND Gehen = null;");

Die Ausgabe der Tabelle:

if(c.moveToFirst())
            {
               do
              {
                    buffer.append(c.getString(1) + " | ");
                    buffer.append(c.getString(2) + " | ");
                    buffer.append(c.getString(3) + "  ");


               } while (c.moveToNext());
                Toast.makeText(getApplicationContext(), Integer.toString(c.getCount()), Toast.LENGTH_LONG).show();
                txt_zeitnachweis.setText(buffer.toString());

Leider funktioniert es bei mir nicht so wie es soll...

Grüße

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

06.01.2017, 15:07:07 via Website

Der insert ist ja auch noch falsch...
Hier mal etwas Pseudocode:
Cursor c = db.execSQL("Select * from Zeiterfassung Where Datum=Date(\'now\') and Gehen is not null");

if(c.count()!=0)
{
//Meldung dass man noch Anwesen sei
}
else{

db.execSQL("INSERT INTO Zeiterfassung (Datum,Kommen) VALUES (DATE(\'now\'),"time")"); // Datum und kommen gleichzeitig
in eine Zeile schreiben
}

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
anamollo
  • Forum-Beiträge: 24

06.01.2017, 15:20:44 via Website

Ich denke, dass der Cursor c schon stimmt, da ja in der TextView ALLE bisher gebuchten Kommen und Gehenzeiten am jeweiligen Datum ausgegeben werden sollen und nicht nur das von heute ("now").

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

06.01.2017, 15:23:25 via Website

Das beispiel oben war die Abfrage ob man noch anwesen ist, das hat mit deiner TextView auswertung rein garnichts zutun ;)

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten