GregorianCalendar.getTimeInMillis()

kodela

Bekanntes Mitglied
Hallo,

ich muss die Differenz an Tagen zwischen dem aktuellen und einem zurück liegendem Datum berechnen. Dafür habe ich mir folgende Methode geschrieben:

Java:
    private int getDiff2heute(int jr, int mn, int tg) {
        GregorianCalendar jubeltag = new GregorianCalendar(jr, mn, tg);
        GregorianCalendar is_heute = new GregorianCalendar(jahr, monat, tag);
        long jt = jubeltag.getTimeInMillis();
        long ht = is_heute.getTimeInMillis();
        if (jt >= ht) {
            return (int) ((jt - ht) / 86400000L);            // 1000 / 60 / 60 / 24
        } else {
            return -1;
        }
    }

Ausgehend von heute (26.03.2023) erhalte ich für alle Tage bis zum 31.03.2023 die richtige Differenz, für den 31.03.2023 also 5 Tage. Ab dem 01.04.23 erhalte ich dann aber ebenso 5 Tage und für alle Folgetage ebenfalls einen Tag zu wenig.

Ich verwende diese Methode schon seit vielen Jahren und mir ist bisher noch nie ein solcher Berechnungsfehler aufgefallen. Hat jemand eine Idee, was die Ursache dieses Problems sein könnte? An den übergebenen Daten kann es nicht liegen, die sind korrekt.

kodela
 

Oneixee5

Top Contributor
Falls es wirklich GregorianCalendar sein muss:
Java:
        Calendar calendar = Calendar.getInstance();
        // calendar.setTimeInMillis(0);
        calendar.set(Calendar.YEAR, jr);
        calendar.set(Calendar.MONTH, mn);
        calendar.set(Calendar.DAY_OF_MONTH, tg);

        Calendar today = Calendar.getInstance();
        // today.set(Calendar.HOUR_OF_DAY, 0);
        // today.set(Calendar.MINUTE, 0);
        // today.set(Calendar.SECOND, 0);
        // today.set(Calendar.MILLISECOND, 0);

        return calendar.get(Calendar.DAY_OF_YEAR) - today.get(Calendar.DAY_OF_YEAR);
 

Oneixee5

Top Contributor
Ich verwende diese Methode schon seit vielen Jahren
Dann hast du schon seit vielen Jahren ein Problem:
morgen: 1679868000000
heute: 1679785200000
morgen - heute: 82800000
jetzt sollte es auffallen: 82800000 / 86400000 == 0.958333333333333... ( // 1000 / 60 / 60 / 24 )
bei einer ganzzahligen Division, also: 82800000 / 86400000L ergibt das dann 0
Also die Tagesdifferenz zu morgen wird in deiner Berechnung schon falsch gemacht.
 

kodela

Bekanntes Mitglied
Das sieht jetzt bei mir so aus und funktioniert, wenn ich die Vorschau auf 28 Tage begrenze:

Java:
    private int getDiff2heute(int jr, int mn, int tg) {
        LocalDate now = LocalDate.now();
        LocalDate endDate = LocalDate.of(jr, mn, tg);      
        Period p = Period.between(now, endDate);
        int m = p.getMonths();
        int d = p.getDays();      
        if (m < 1 && d > 0) {
            return d;
        } else {
            return -1;
        }
    }

Auf 28 Tage muss ich die Vorschau (zur Zeit 14 Tage) begrenzen, denn wenn die Anzahl der Tage eine Monatslänge überschreitet , werden die Tage gesplittet ausgegeben. Besteht die Möglichkeit, die Tage ungesplittet abzufragen?
 

LimDul

Top Contributor
Lass dir mal jt und ht ausgeben, evtl. liegen genau 1 daneben und da die division abrundet ..

Edit: Zeitumstellung vergessen - die ist die Ursache. Der 31.3 hat nur 23 Stunden dieses Jahr
 

LimDul

Top Contributor
Die Zeitumstellung kann eig. nicht das Problem sein. Die war ja einen Tag früher.
Sogar fast eine Woche (26.3) - Brainfuck meinerseits.

Anderseits ist GregorianCalender ein deartiger Haufen Grütze, das da alles die Ursache ist. So ist nicht klar, ob überhaupt die übergebenen Daten korrekt sind. Den Monat muss ja null-Bases sein - wenn da 2023, 26, 3 übergeben wird ist der 26.4.2023. Und da der April nur 30 Tage hat ist der 31.4 gleich dem ersten 1.5 (Zumindest glaube ich das GregorianCalender das so handelt)
 

vup

Mitglied
ich muss die Differenz an Tagen zwischen dem aktuellen und einem zurück liegendem Datum berechnen.

Hier, bitte (ungetestet):

Java:
    public static int getDiff2heute(final int jr, final int mn, final int tg) {
        LocalDateTime ldt1 = LocalDateTime.of(jr, mn, tg, 0, 0);
        LocalDateTime ldt2 = LocalDateTime.now();
        return (int) Duration.between(ldt1, ldt2).toDays();
    }
 

LimDul

Top Contributor
PS: Selbst die Doku ist bescheiden: https://docs.oracle.com/en/java/jav...egorianCalendar.html#equals(java.lang.Object)

Wann sind 2 Gregorian Kalender Objekte gleich?
Spoiler, es reicht nicht diese Doku zu lesen, sondern man muss Calender#equals lesen

Erfahrung aus der Praxis:

Java:
MyEntity e = erzeugeEntity();
e.setDatum(someDatum);
MyEntity e2 = entityManger.persist(e);
System.out.println(e.getDatum().equals(e2.getDatum());
System.out.println(e.getDatum().compareTo(e2.getDatum());
Was kommt raus?

compareTo gibt immer 0 zurück.
Aber equals kann ggf. auch false liefern. Hängt davon ab, ob das Objekt aus dem Cache kommt oder neu aus der DB gelesen wird. Und davon welche Zeitzoneneinstellung auf dem Application-Server & DB Server sind und wie das Feld in der Datenbank angelegt ist.

Intuitiv? Nein. Sauber dokumentiert: Ja, wenn ich von Calender & GregorianCalender die Doku zu equals & compareTo genau lese. Wenn ich bei einer Klasse aber die Doku + Doku der Oberklassen von equals & compareTo lesen muss - dann kann mir keiner erzählen, dass das eine gute API ist.
 

kodela

Bekanntes Mitglied
Danke für Eure Antworten und das rege Interesse an meinem Problem!

Mittlerweile habe ich eine Lösung, mit der ich gut leben kann. Hier der Code:

Java:
    private int getDiff2heute(int jr, int mn, int tg) {
        LocalDate now = LocalDate.now();
        LocalDate endDate = LocalDate.of(jr, mn, tg);
        Period p = Period.between(now, endDate);
        int m = p.getMonths();
        int d = p.getDays();
        // Vorschau maximal 28 Tage - wenn mehr als 31 Tage, dann wg. Splittung in Monate und Tage mit Sicherheit falsches Ergebnis 
        if (m < 1 && d >= 0) {
            return d;
        } else {
            return -1;
        }
    }

@vup: Von Deinem ungetesteten Vorschlag habe ich mir viel versprochen, aber ich musste darauf verzichten. Die Differenz von heute auf heute war 0, was ja richtig ist, aber auch die Differenz von heute auf morgen war 0 und so etwas geht natürlich nicht. Auch mit vertauschten Parametern lieferte Duration.between(ldt1, ldt2).toDays() falsche Werte. Ich werde trotzdem diesen Weg noch einmal genauer untersuchen.

@LimDul: Auch Deinen Vorschlag werde ich mir noch einmal genauer ansehen, im Augenblick bleibe ich aber bei meinem oben gezeigten Code, damit gibt es keine Probleme wenn ich die zu berücksichtigende Zeitspanne für die Vorschau auf 28 Tage begrenze. Als Voreinstellung habe ich 14 Tage gewählt.
 

vup

Mitglied
int m = p.getMonths(); int d = p.getDays();
Die zusätzliche Anforderung, Monate oder Tage, hast du uns verschwiegen

if (m < 1 && d >= 0) {
Das sieht noch nicht richtig aus

Die Differenz von heute auf heute war 0, was ja richtig ist, aber auch die Differenz von heute auf morgen war 0 und so etwas geht natürlich nicht.
Warum geht das denn nicht? Die Zeitspanne wäre beides Mal < 24 h...

Aber ich denke, du wirst nun fündig werden.

PS: Selbst die Doku ist bescheiden

Man hat sich schwergetan mit der Einführung der neuen Zeit-Api, weil die alte eigentlich gut war ... Dann hat man die neue Zeit-Api aber leider fast verhunzt. Beides ist noch nicht das "Gelbe" vom Ei. Wenn massive Zeitprobleme zu lösen hat, ist auch ein Blick auf die Joda Time-Api wert.
 

Oneixee5

Top Contributor
@vup: Von Deinem ungetesteten Vorschlag habe ich mir viel versprochen, aber ich musste darauf verzichten. Die Differenz von heute auf heute war 0, was ja richtig ist, aber auch die Differenz von heute auf morgen war 0 und so etwas geht natürlich nicht. Auch mit vertauschten Parametern lieferte Duration.between(ldt1, ldt2).toDays() falsche Werte. Ich werde trotzdem diesen Weg noch einmal genauer untersuchen.
Das der Vorschlag einfach falsch ist sollte klar sein. Da wird bei ldt2 die aktuelle Zeit mit einbezogen und bei ldt1 nicht. Versuch es mal ohne Zeit:
Java:
    private static long getDiff2heute(int jr, int mn, int tg) {

        LocalDate ldt1 = LocalDate.of(jr, mn, tg);
        LocalDate ldt2 = LocalDate.now();
        return ldt1.getDayOfYear() - ldt2.getDayOfYear();
        
    }
 

Oneixee5

Top Contributor
Man hat sich schwergetan mit der Einführung der neuen Zeit-Api, weil die alte eigentlich gut war ... Dann hat man die neue Zeit-Api aber leider fast verhunzt. Beides ist noch nicht das "Gelbe" vom Ei. Wenn massive Zeitprobleme zu lösen hat, ist auch ein Blick auf die Joda Time-Api wert.
Zu der Aussage hätte ich gern mal Quellen! Es ist allgemein bekannt und Konsens, dass die "alte Zeit-Api" unübersichtlich und schwer zu handhaben ist. Die "neue Zeit-Api" wurde praktisch bei der "Joda Time-Api" abgeschrieben. Schwergetan hat man sich wegen der Kompatibilität der beiden API's.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
B SimpleDateFormat oder doch lieber GregorianCalendar Allgemeine Java-Themen 3
kodela Eigenartige Datumsberechnung über GregorianCalendar Allgemeine Java-Themen 15
Q GregorianCalendar Methode add liefert komische Werte Allgemeine Java-Themen 3
E GregorianCalendar Wochentag Allgemeine Java-Themen 3
P Fehler im GregorianCalendar Allgemeine Java-Themen 8
T Liste mit GregorianCalendar-Objekten in List einlesen, mit Collection sortieren und ausgeben Allgemeine Java-Themen 3
M Problem mit dem GregorianCalendar Allgemeine Java-Themen 2
J GregorianCalendar wil nich so recht as ick wol will Allgemeine Java-Themen 6
T GregorianCalendar - kein Februar Allgemeine Java-Themen 6
L Probleme mit GregorianCalendar Allgemeine Java-Themen 4
C Calendar bzw. GregorianCalendar Klasse Allgemeine Java-Themen 12
M Seltsamer Fehler bei GregorianCalendar Allgemeine Java-Themen 2
T KW=1 Jahr=2008 Monat=Dezember => GregorianCalendar Allgemeine Java-Themen 8
B GregorianCalendar UNIX Allgemeine Java-Themen 6
ARadauer GregorianCalendar Allgemeine Java-Themen 8
A Verständnisproblem mit GregorianCalendar Allgemeine Java-Themen 10
A Fehler bei Rechnung mit GregorianCalendar Allgemeine Java-Themen 6
D GregorianCalendar std zurück Allgemeine Java-Themen 7
F GregorianCalendar wirft keine Fehler bei z.b. Monat 17 Allgemeine Java-Themen 3
N GregorianCalendar Allgemeine Java-Themen 2
L String ==> Date ==> GregorianCalendar Allgemeine Java-Themen 3
F Zeit errechnen mit GregorianCalendar Allgemeine Java-Themen 8
F Datum in GregorianCalendar Allgemeine Java-Themen 3
N Unterschied Calendar und GregorianCalendar Allgemeine Java-Themen 9
S GregorianCalendar.getInstance() Allgemeine Java-Themen 7
G Probleme mit getTimeInMillis Allgemeine Java-Themen 2

Ähnliche Java Themen

Neue Themen


Oben