Theorie zur Datumsberechnung

Wunderschönen Guten Tag,

ich habe mal eine ganz interessante Sache festgestellt, die mir aber besonders die Nerven raubt.
Ich habe in Java und in Apple Swift je ein Programm entwickelt, welches die Anzahl von Sekunden zwischen zwei Datumsangaben berechnet.
Beide zeigen den gleichen Abstand. Bis auf exakt 392 Sekunden Abstand.

Dann habe ich mich ran gemacht selbst nachzurechnen und das mit Numbers (das Apple Excel Programm) einmal nachrechnen lassen und dann einmal selbst in der Tabelle zusammengerechnet.
Numbers und ich kommen auf haargenau das gleiche Ergebnis, nur ebenfalls ein weiteres drittes Ergebnis.

Nun, ohne euch jetzt mit irgendwelchen Quellcodes zu „belasten“ würde mich mal in der Theorie interessieren, ob ihr eine Ahnung habt, was bei diesen drei unterschiedlichen Berechnungsweisen der Unterschied sein könnte.

Ich hab mal ein Bildschirmfoto aus meiner Tabelle angehängt.

Also ich möchte den Abstand zwischen zwei Beispieldaten haben, 6. April 1821 um 3:14:15 Uhr und dem 4.Oktober 2015 um 13:00:50 (war vorhin :slight_smile: ).
Der Tabelle entnehmen könnt ihr was Swift und Java ausgerechnet haben und rechts daneben der Abstand.
Unter den beiden Datumsangaben steht, was Numbers vollautomatisch über die Formel =B3-B2 berechnet hat.

So und in dem Feld daunter hab ich mich versucht.
Sind dann immer drei Spalten. Die Anzahl der Vorkommnisse, die Anzahl der Sekunden eines Vorkommnisses und das Produkt daraus.
Also Beispielsweise 194 vergangene Jahre mal 31.536.000 Sekunden pro Jahr gleich 6.117.984.000.
Am Ende summiere ich einfach die letzte Spalte auf und komme auf das gleiche was Numbers ausgerechnet hat.

Die Abweichung zu Java beträgt glatt 30 Tage und eine Stunde, die zu Swift nochmal 392 Sekunden dazu.

Mich würde an der Stelle interessieren:
Fällt euch irgendwas auf, was den Unterschied ausmachen könnte? Irgendetwas, was ich in meiner Berechnungsweise nicht beachtet haben könnte?

Vielen Dank im Voraus! :slight_smile:

Gruß
Lukas

Ein online-Rechner bringt das gleiche Ergebnis, wie das manuell ausgerechnete.

Ansonsten kann es bei Datumsberechnungen beliebige Überraschungen geben. (Zuerst denkt man: Joa, Datum. Einfach. Alles klar. Jahr. Monat. Tag. Stunde. Minute. Sekunde. Ach ja, Schaltjahre. Auch einfach: Alle 4 Jahre. Ach nee… 4/100/400, auch OK. Ach ja, Sommer/Winterzeit. OK, das muss man wissen. Dann stolpert man über ISO 8601, und … ach ja, die Zeitzone. Und früher oder später merkt man, dass es bei Daten richtig schräge Sachen gibt).

Ein bißchen Code könnte helfen, schon allein um zu sehen, ob du die “alten” oder “neuen” Date/Time-Klassen verwendest…

Hallihallöle und Danke für Deine Antwort,

ja manchmal verfluche ich es, dass die Menschheit da nicht von Anfang an was seriöses einfaches erschaffen hat. Aber das konnte ja auch niemand ahnen.

Also meine ersten beiden Vermutungen waren ja:

  1. Schaltsekunden. Die 392 Sekunden Unterschied kommen durch Schaltsekunden, Swift beachtet sie und Java nicht, oder andersherum. Dann habe ich gegooglet, ne so viele gab es ja auch noch gar nicht.
  2. Zeitzone und Winterzeit. Ne das war auch irgendwie Quatsch, weil 392 Sekunden Unterschied kommen nicht dadurch.

Und ansonsten, die 30 Tage und 1 Stunde Unterschied zum Menschlich berechneten, höchst seltsam ist das. Konnte keine Erklärung finden.

Okay, dann will ich mal ein wenig Code posten, vielleicht fällt ja daran etwas auf.
Für Java:

	
	private DateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
	private Calendar gregKalender = new GregorianCalendar(/*1821,4,6,3,14,15*/2015,8,9,0,0,0);
	private long unix0 = new GregorianCalendar(1970,0,1,1,0,0).getTimeInMillis();
    private long unixNap = new GregorianCalendar(1821,4,6,3,14,15).getTimeInMillis();
    private long dorZeit;
    private boolean meldung = false;
    
    public void gregZuDOR(String einlesedatum) {
    	try {
			gregKalender.setTime(dateFormat.parse(einlesedatum));
			if(gregKalender.get(Calendar.YEAR)<1583 && !meldung) {
				meldung = true;
			} else if(!(gregKalender.get(Calendar.YEAR)<1583)) {
				meldung = false;
				long gregLong = gregKalender.getTimeInMillis()/1000;
				long zeitabstand;
				if(gregKalender.getTimeInMillis()>0) {
					zeitabstand = unix0/1000 - unixNap/1000 + gregLong;
				} else {
					zeitabstand = gregLong - unixNap/1000;
				}
				dorZeit = zeitabstand;
			}
        } catch (ParseException e) {}
    }
    
    public void dorZuGreg(long dorLong) {
        long zeitabstand = unixNap + dorLong*1000;
        long oldMillis = gregKalender.getTimeInMillis();
        if(zeitabstand != oldMillis) {
            gregKalender.setTimeInMillis(zeitabstand);
        }
    }

	public DateFormat getDateFormat() {
		return dateFormat;
	}

	public Calendar getGregKalender() {
		return gregKalender;
	}

	public long getDorZeit() {
		return dorZeit;
	}
}```

Er berechnet auch hier die Anzahl an Sekunden Unterschied zwischen dem von mir festgelegten, rein zufälligen Datum im Jahr 1821 und einem zweiten festgelegten Tag. Hier im Beispiel DORzeit genannt.

Und für die Leute, die vielleicht mal an Swift interessiert sind:
```let userCalendar = NSCalendar.currentCalendar()
        let napTimeComp = NSDateComponents()
        napTimeComp.year = 1821
        napTimeComp.month = 5
        napTimeComp.day = 6
        napTimeComp.hour = 3
        napTimeComp.minute = 14
        napTimeComp.second = 15
        let napTime = userCalendar.dateFromComponents(napTimeComp)!
        let dorTime = Int(NSDate().timeIntervalSinceDate(napTime))
        print(dorTime)```

Sieht etwas kürzer aus. ;)

Die Java Variante hatte ich schon mal hier in dem Thema ein wenig besprochen: http://forum.byte-welt.net/java-forum-das-java-welt-kompetenz-zentrum-wir-wissen-und-helfen-/allgemeine-themen/17300-gregorianischer-kalender-textfield.html
Da gings aber nicht um dem Algorithmus an sich, sondern die graphische Oberfläche eines Rechners.


Also das sind die Theorien in den beiden Programmiersprachen.

Ich schau’ wohl morgen nochmal drüber, würde dir aber dringend empfehlen, dir mal die neue Date/Time API von Java 8 anzusehen. Alles, was mit “Calendar” zu tun hat, ist ziemlich “broken” (wie man so sagt). Trotzdem immer wieder spannend, zu sehen, wo sowas wie diese 392 Sekunden herkommen. (Eine gezielte Websuche danach brachte übrigens nichts spezielles… ;-))

Hallihallöle,
das wäre großartig, wenn Du Dir das mal ansehen könntest. :wink:
Aber auch wenn das mit Java falsch wäre, wenn Swift doch immer noch (fast) das gleiche anzeigt, was deutlich von meinen Rechnen abweicht, ist da immer noch was faul.
Zu den 392 Sek. konnte ich auch nichts finden. Wohl niemand. :smiley:

Ich habe aktuell mal meinen Java-Rechner gestartet und rechne in 4jahres Schritten einfach manuell im PC-Taschenrechner mit.
Ich konnte von 1821 bis 1940 keine Abweichungen feststellen.
Und hier wird es interessant. 1940 Abweichung um eine Stunde.
Konnte in Wikipedia das hier finden:

Im NS-Deutschland wurde die Sommerzeit ab 1940 ohne Rückstellung auch im Winter benutzt. Und zu Besatzungszeichen hatten die Russen und die Briten eigene Regelungen…
Ach Gottchen, dass die damals nicht mitgedacht haben, was das in der IT für Probleme gibt. :wink:

Ich schaue morgen mal weiter, was es da so gibt.

mach halt eine Schleife draus: dann solltest du den exakten Tag finden, an dem die Abweichung das erste mal auftaucht…was da wohl war??

Habe mir den Code und auch die Vergleichsrechnungen nicht im Einzelnen angeschaut, aber 30 Tage Unterschied (ziemlich genau 1 Monat) könnte durch eine falsche Monatsangabe kommen. Im Calendar hat Januar den Wert 0 und nicht 1. Entsprechend wäre der Wert 9 der Oktober und nicht (wie evtl. vermutet) der September.

Ähnliches gilt für Wochentage. Montag hat hier z.B. den Wert 2. (In Deinem Code glaube ich nicht verwendet, nur der Vollständigkeit halber der Hinweis.)

Deswegen solltest Du auf die Magic Numbers (die ganzen direkten Zahlangaben im Code) verzichten und lieber die Konstanten aus Calendar verwenden: Calendar (Java Platform SE 7 ) (scrolle runter zur Field Summary)

Joa, heißer Kandidat…1821,4,6 für “6. April” stimmt eben nicht - war es das vielleicht schon?

O Sancta Simplicitas! Haha. Ich bin entsetzt. Ein Fehler den ich versucht habe auszuräumen direkt doch nochmal begangen.
Ich will nämlich genau den 6. Mai haben. Was ich ja mit 1821,4,6 auch erreiche.:smiley: Und dann hab ich beim selbst berechnen knallhart aus der vier April zurückgeleitet…

Schock.
Übrigens, in Swift musste ich direkt 5 geschrieben, die Dokumentation dazu sagt:

Day, week, weekday, month, and year numbers are generally 1-based, but there may be calendar-specific exceptions. Ordinal numbers, where they occur, are 1-based. Some calendars may have to map their basic unit concepts into the year/month/week/day/… nomenclature. The particular values of the unit are defined by each calendar and are not necessarily consistent with values for that unit in another calendar.
Listing 4 shows how you can create a date components object that you can use to create the date where the year unit is 2004, the month unit is 5, and the day unit is 6 (in the Gregorian calendar this is May 6th, 2004). You can also use it to add 2004 year units, 5 month units, and 6 day units to an existing date. The value of weekday is undefined since it is not otherwise specified.

Alles 1-basierend.
Nun denn, es bleibt also ein Unterschied von glatt einer Stunde zu Java und nochmal 392 Sekunden zu Swift.
Die 392 Sekunden? Keine Ahnung. Ihr wahrscheinlich auch nicht.
Die eine Stunde? Ich tippe ganz klar auf die Sommerzeit.

Du hattest angeboten Dir einmal meinen Quellcode anzusehen. Könntest Du mal beim Javacode nachschauen, ob ich da was ungünstig unbeachtet lies? Das wäre großartig. :slight_smile: Die Zeitzone soll übrigens immer Berlin (bei Dabendorf) sein. Durch currentCalendar() dachte ich auch, er liest es aus meinem PC so aus.

In bezug auf die Stunde hätte ich noch einen weiteren Tipp

private long unix0 = new GregorianCalendar(1970,0,1,1,0,0).getTimeInMillis();
                                                    ^ Tipp  

Kannst du nochmal den Code (d.h. den letzten Stand) posten, wo genau diese 392 herkommen? Am besten mit einer kleinen “main” - im Moment ist mir nicht mal klar, welche Methode dort wann aufgerufen wird.

Aber nebenbei: Sowas wie “gregKalender.setTimeInMillis(zeitabstand)” ist gefährlich und vermutlich sinnlos, und könnte schon beliebig schräge Effekte erklären. Nicht umsonst gibt es in https://docs.oracle.com/javase/tutorial/datetime/iso/index.html eine explizite Unterscheidung zwischen “Instant” und “Duration”…

(Und noch mehr nebenbei: Was ist “DOR”, und was soll die Klasse überhaupt machen?)

Auch noch zwei Tipps zur Fehlersuche bzw. mögl. Fehlerursache:
1.)

                meldung = false;
                long gregLong = gregKalender.getTimeInMillis()/1000;
                long zeitabstand;
                if(gregKalender.getTimeInMillis()>0) {
                    zeitabstand = unix0/1000 - unixNap/1000 + gregLong;
                } else {
                    zeitabstand = gregLong - unixNap/1000;
                }
                dorZeit = zeitabstand;
            }

Hier machst Du diverse Ganzzahldivisionen mit entsprechendem Genauigkeitsverlust. Absicht?

2.)
Rufe direkt nach Erzeugung der GregorianCalendars setLenient(false) auf (ist defaultmäßig true). So bemerkst Du eventuell unbeabsichtigte “Überläufe” einzelner Felder beim Setzen (bspw. 32. Januar, 65 Sekunden, 1095 Millisekunden o.ä.)

Wunderschönen Guten Tag euch beiden,

ich möchte das einmal kurz erklären, was eure Fragen angeht.
Mein Projekt hat zwei Klassen, das sind eine Berechnungsklasse und eine Grafikklasse. Ich hatte der Einfachheit halber nur die Berechnungsklasse gepostet, weil die ja maßgeblich dafür relevant ist.

Die Grafikklasse mit Hauptmethode liest nur ein.

	
	private JFrame frame1 = new JFrame("Zeitrechner");
	private NumberFormat format1 = NumberFormat.getInstance(); 
	private NumberFormatter formatter1 = new NumberFormatter(format1);
	private JFormattedTextField gregKalenderTF;
	private JFormattedTextField dorZeitTF = new JFormattedTextField(formatter1);
	private JRadioButton gregRadio = new JRadioButton("Greg.-Zeit");
    private JRadioButton dorRadio = new JRadioButton("DOR-Zeit");
    private ButtonGroup bg = new ButtonGroup();
    private ArrayList<JFormattedTextField> textfelder = new ArrayList<JFormattedTextField>();
    private DORZeit dorZeit;
	
	public Zeitrechner() {
		dorZeit = new DORZeit();
		gregKalenderTF = new JFormattedTextField(dorZeit.getDateFormat());
		frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame1.setPreferredSize(new Dimension(260,80));
		frame1.setMinimumSize(new Dimension(260,80));
		frame1.setMaximumSize(new Dimension(390,120));
		frame1.setResizable(true);
		Container cp = frame1.getContentPane();
		cp.setLayout(new GridLayout(2,1));
		
		JPanel panelGreg = new JPanel();
		panelGreg.setLayout(new BorderLayout());
		panelGreg.add(gregRadio,BorderLayout.LINE_START);
		panelGreg.add(gregKalenderTF,BorderLayout.CENTER);
		JPanel panelDOR = new JPanel();
		panelDOR.setLayout(new BorderLayout());
		panelDOR.add(dorRadio,BorderLayout.LINE_START);
		panelDOR.add(dorZeitTF,BorderLayout.CENTER);
		cp.add(panelGreg);
		cp.add(panelDOR);
		textfelder.add(gregKalenderTF);
		textfelder.add(dorZeitTF);
		
		bg.add(gregRadio);
	    bg.add(dorRadio);
		gregRadio.setSelected(true);
		gregKalenderTF.setText("06.05.1821 03:14:15");
		dorZeitTF.setText("0");
		for(JFormattedTextField jftf:textfelder) {
			jftf.getDocument().addDocumentListener(new DocumentListener() {
	            @Override
	            public void changedUpdate(DocumentEvent e) {
	            }
	            @Override
	            public void insertUpdate(DocumentEvent e) {
	                SwingUtilities.invokeLater(new Runnable() {
	                    @Override
	                    public void run() {
	                    	umrechnen();
	                    }
	                });
	            }
	            @Override
	            public void removeUpdate(DocumentEvent e) {
	            }
	        });
		}
		format1.setGroupingUsed(false);
	    formatter1.setAllowsInvalid(false);
		frame1.pack();
		frame1.setLocationRelativeTo(null);
		frame1.setVisible(true);
	}
	
	/**
	 * Diese Methode prueft, welcher Radiobutton als Ursprungszeit ausgewaehlt wurde.
	 * Anschliessend liest sie den Wert ein, rechnet die Zeit um und fuegt den errechneten Wert in das Textfeld ein.
	 */
	private void umrechnen() {
        if(gregRadio.isSelected()) {
        	dorZeit.gregZuDOR(gregKalenderTF.getText());
        	long neu = dorZeit.getDorZeit();
        	if(String.valueOf(neu)!=dorZeitTF.getText()) {
        		dorZeitTF.setText(String.valueOf(neu));
        	}
        } else {
        	try {
	        	dorZeit.dorZuGreg(Long.valueOf(dorZeitTF.getText()));
	        	if(dorZeit.getGregKalender().getTime()!=dorZeit.getDateFormat().parse(gregKalenderTF.getText())) {
	        		gregKalenderTF.setValue(dorZeit.getGregKalender().getTime());
	        	}
        	} catch (ParseException e) {
        		JOptionPane.showMessageDialog(null, "Du hast falsche Werte eingetragen."+System.getProperty("line.separator")+"Wenn Du dies nicht korrigierst"+System.getProperty("line.separator")+"bekommst Du kein Ergebnis!", "Falscheingabe", JOptionPane.WARNING_MESSAGE);
        	}
        }
    }
	
	public static void main(String[] args) {
		new Zeitrechner();
	}
}```

Man hat da ein Feld mit zwei Eingabefeldern und man wählt vorher mit einem Radiobutton die Ursprüngliche Zeit aus.
Man rechnet hier ein Datum mit Uhrzeit des gregorianischen Kalenders in eine `dorZeit` aus.
dorZeit ist hier Synonym für ein fiktives Wort, welches den Abstand in Sekunden zwischen zwei Frei gewählten Daten berechnet.

Das erste von beiden Daten hab ich festgelegt auf den 6. Mai 1821 um 3:14:15 Uhr. Hat keine tiefere Bedeutung, einfach nur mal, damit ich ein festes Datum hatte, solange ich mit der Berechnung nicht sicher bin. Das Projekt ist älter, ich müsste in meinen alten Dateien blättern, wieso ich das damals DOR genannt habe.:D Das tut aber hier hoffentlich nichts zur Sache. :) 

Zum Überlauf:
Also wenn ich ein Datum einlese im Gregorianischen Feld, dann macht er auch wirklich den Überlauf von allein. Hab ich getestet.
Wenn ich 32.13.2015 eingebe, dann überschlägt er auf den 1. Februar 2016, weil er einen Monat und einen Tag zu viel hat.

Zur ganzzahligen Division:
Ich möchte ja die Sekunden haben. Und da ich ja auch nur Werte mit Sekundenwert ohne Millisekundenwert abrufe, bekomme ich ja eh immer einen TimeStamp der auf 000 endet. Daher muss ich alles durch 1000 teilen.


======
Lange Rede kurzer Sinn, das Problem ist hier einfach, dass ich nicht weiß, wo die 392 Sekunden her kommen. Aber nach meinem selbst nachrechnen scheint der Fehler tatsächlich bei Apple Swift und nicht bei Java zu sein.
Mein Problem wäre dann nur noch die eine falsche Stunde.

Ich müsste Java, wenn euch nicht irgendwas anderes auffällt nur noch dazu kriegen die eine falsche Stunde richtig zu rechnen. Meine ganz klare Vermutung ist nach wie vor die Sommerzeit.
Das mit der Zeitzone ist etwas kompliziert. Wie stelle ich denn dem Kalender klar, dass er das ganze Jahr über mit Zeitzone Berlin (bei Dabendorf) rechnet, und auf Sommerzeit achtet?

wieso gerade Berliner Zeit, ist ja egal wo

nutze z.B. TimeZone.getTimeZone(“GMT”), das ist ohne Sommerzeit,
da kommt bei mir bis zu einem Datum im Januar dasselbe raus, bis Juni 1 Stunde Abweichung

falls auch absolute Werte wichtig, kann man sicherlich noch eine Zeitzone wählen, “GMT+1” geht bei mir gerade,
evtl. genauer nachschauen


zu den ominösen 392 sec:
kannst du in Swift auch andere Werte testen?
wie ist denn da die Differenz gestern zu heute und wiederum Java im Vergleich,

bei kleinen Werten muss es doch (besser) stimmen und dann an konkreten Punkten ansteigen,
so wie die Sommerzeitumstellung in Java genau zu finden,

hast du dazu schon etwas untersucht?

[QUOTE=SlaterB]zu den ominösen 392 sec:
kannst du in Swift auch andere Werte testen?
wie ist denn da die Differenz gestern zu heute und wiederum Java im Vergleich,

bei kleinen Werten muss es doch (besser) stimmen und dann an konkreten Punkten ansteigen,
so wie die Sommerzeitumstellung in Java genau zu finden,

hast du dazu schon etwas untersucht?[/QUOTE]

Hallöle,
habe mich heute damit befasst. Musste erst mein Programm umentwickeln, bin leider noch nicht so lange bei Swift dabei.
Das Worst Case Szenario wäre natürlich, wenn die Sekunden alle einzeln auftreten und ich irgendeinen komplizierten Algorithmus basteln müsste, der das irgendwie berechnet, wann die kommen. Dazu kam es glücklicherweise nicht.

Meine Recherchen zeigen folgendes:
1880: 1861920000
1890: 2177452800
1900: 2492985208

Hier kommt auf einen Schlag alles raus, was das Problem ausmacht.
Also irgendwo zwischen 1890 und 1900.
Der falsche Übergang ist am folgenden Zeitpunkt:

  1. April 1893 um 00:06:32 Uhr (genau 392 Sekunden nach Mitternacht)
    00:06:31 Uhr zeigt 2.269.111.936
    00:06:32 Uhr zeigt 2.269.111.545

Da springt er also nochmal 392 Sekunden zurück.
Und siehe da:

Welch Farce, welch Farce…

Interpretation des ganzen: Bezüglich meines nicht gerade weltrelevanten Programms, wie viele Sekunden vergangen sind, hat Java die Nase vorn. Bezüglich der korrekten Uhrzeit eher Swift?

Zur Zeitzone:
Ich krieg’s in keiner der beiden Programme hin dieses Problem mit der einen Stunde zu beheben.
Swift können hier wohl die wenigsten. Daher zu Java:
Hatte es damit versucht: gregKalender.setTimeZone("GMT")
Habe auch gemäß dieser Webseite hier Java’s java.util.TimeZone | tutorials.jenkov.com einfach mal völlig andere Sachen probiert. Es kam nie eine andere Zeit raus.
Völlig andere zieht besonders auf die Liste unten ab.

zur Zeitzone gibt es jedenfalls

    public static void main(String[] args)  throws Exception  {
        Calendar c = new GregorianCalendar();
        c.set(2015, 6, 1, 1, 1, 1);
        System.out.println(c.getTime());

        TimeZone tz = TimeZone.getTimeZone("GMT+1");
        c.setTimeZone(tz);
        c.set(2015, 6, 1, 1, 1, 1);
        System.out.println(c.getTime());

        String date = "01.06.2015 03.45.59";
        SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy HH.mm.ss");
        System.out.println(df.parse(date));
        df.setTimeZone(tz);
        System.out.println(df.parse(date));
    }
}

mit Ausgabe

Wed Jul 01 01:01:01 CEST 2015
Wed Jul 01 02:01:01 CEST 2015
Mon Jun 01 03:45:59 CEST 2015
Mon Jun 01 04:45:59 CEST 2015

beim zweiten Calendar-Setzen wird Uhrzeit 1:00 in GMT+1 gesetzt, in CET bzw. dannt CEST ausgegeben ist das 2:00

wenn an einer Stelle mit SimpleDateFormat geparst, dann ist Zeitzone in Calender wenig wichtig,
dann im SimpleDateFormat zu setzen

Interessant. Interesse an ein paar hunderttausend Punkten auf StackOverflow? :smiley:

Ansonsten hatte ich zwar nochmal über den Code geschaut, aber WAS er da genau ausrechnen sollte, war nicht ganz klar. Einfach eine Umrechnung zwischen dem angegebenen Datumsformat und den Sekunden in Unix-Zeit? Wie auch immer, hatte auch mal kurz mit den neuen Date/Time-Funktionen rumprobiert, aber das ist jetzt wohl…

…irrelevant

package bytewelt;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
 
public class AndererZeitrechner 
{
   
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }
    
    private static void createAndShowGUI()
    {
        JFrame f = new JFrame("Zeitrechner");
        
        JPanel p0 = new JPanel(new GridLayout(2,1));
        p0.add(new JLabel("Gregorian"));
        p0.add(new JLabel("DOR"));
        
        DateTimeFormatter formatter = 
            DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss");
        JFormattedTextField gregTextField = 
            new JFormattedTextField(formatter.toFormat());
        JTextField dorTextField = new JTextField();
        
        JPanel p1 = new JPanel(new GridLayout(2,1));
        p1.add(gregTextField);
        p1.add(dorTextField);
        
        JPanel p = new JPanel(new BorderLayout());
        p.add(p0, BorderLayout.WEST);
        p.add(p1, BorderLayout.CENTER);
        f.getContentPane().add(p);
        
        gregTextField.getDocument().addDocumentListener(new DocumentListener()
        {
            @Override
            public void removeUpdate(DocumentEvent e)
            {
                updateDor();
            }
            
            @Override
            public void insertUpdate(DocumentEvent e)
            {
                updateDor();
            }
            
            @Override
            public void changedUpdate(DocumentEvent e)
            {
                updateDor();
            }
            
            private void updateDor()
            {
                try
                {
                    LocalDateTime t = 
                        LocalDateTime.parse(gregTextField.getText(), formatter);
                    gregTextField.setBackground(Color.WHITE);
                    long epoch = t.toEpochSecond(ZoneOffset.ofHours(0));
                    String s = String.valueOf(epoch);
                    if (!s.equals(dorTextField.getText()))
                    {
                        SwingUtilities.invokeLater(new Runnable()
                        {
                            @Override
                            public void run()
                            {
                                dorTextField.setText(s);
                            }
                        });
                    }
                }
                catch (DateTimeParseException  e)
                {
                    gregTextField.setBackground(new Color(255,192,192));
                    System.out.println(e.getMessage());
                }
            }
        });
        gregTextField.setText("06.05.1821 03:14:15");
        
        dorTextField.getDocument().addDocumentListener(new DocumentListener()
        {
            @Override
            public void removeUpdate(DocumentEvent e)
            {
                updateGreg();
            }
            
            @Override
            public void insertUpdate(DocumentEvent e)
            {
                updateGreg();
            }
            
            @Override
            public void changedUpdate(DocumentEvent e)
            {
                updateGreg();
            }
            
            private void updateGreg()
            {
                try
                {
                    long epoch = Long.parseLong(dorTextField.getText());
                    LocalDateTime t = 
                        LocalDateTime.of(1970, 1, 1, 0, 0).plusSeconds(epoch);
                    String s = formatter.format(t);
                    if (!gregTextField.getText().equals(s))
                    {
                        SwingUtilities.invokeLater(new Runnable()
                        {
                            @Override
                            public void run()
                            {
                                gregTextField.setText(s);
                            }
                        });
                    }
                    dorTextField.setBackground(Color.WHITE);
                }
                catch (NumberFormatException  e)
                {
                    dorTextField.setBackground(new Color(255,192,192));
                    System.out.println(e.getMessage());
                }
            }
        });
        
        
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(300, 100);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
   
}```

eher weniger:-)

java - Odd results in Joda DateTime for 01.04.1893 - Stack Overflow