Willkommen zu meinem nächsten Beitrag direkt aus meinem Fundus merkwürdiger Java-Lösungen für nicht ganz so alltägliche Programmierprobleme. Normalerweise würde ich meine kreativen Fehltritte sicher NIE veröffentlichen, aber dieses Mal mache ich noch eine Ausnahme, da ich glaube, es könnte den einen oder anderen auf die richtige Spur bringen, wenn er nicht weiter weiß.
Kürzlich war ich dabei, einen kleinen Indexer für dies und das zu schreiben, der einmal am Tag zu einer bestimmten Tageszeit Datensätze aus einer Datenbank zieht. Wofür genau spielt hier natürlich keine Rolle. Jedenfalls wollte ich dafür einen TimerTask verwenden, und der wird beispielsweise mit einem Delay (Verzögerung in Millisekunden bis zum ersten Start), und einem Intervall (Verzögerung in Millisekunden für alle darauffolgenden Starts) gefüttert. Randbedingung war, dass der Indexer einmal am Tag um dieselbe Uhrzeit läuft. Diese Uhrzeit soll man hinterlegen können. Den TimerTask-Kram habe ich weggelassen, und den eigentlichen Indexer-Code auch, um das Beispiel möglichst auf das Essentielle zu reduzieren.
Mein Problem war nämlich, dass ich auf Anhieb nicht wusste, wie ich herausfinden könnte, wann der nächstmögliche Zeitpunkt für eine festgelegte Uhrzeit ist, also ob beispielsweise 14:30 Uhr noch am selben Tag ist, oder erst am darauffolgenden Tag. Wieviele Millisekunden muss ich als Verzögerung des initialen Starts angeben, damit der Indexer zur nächsten Gelegenheit um eine bestimmte Uhrzeit losläuft?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
; html-script: false ]public int[] timeToNextIndexTask(){ int indexHour = 14; int indexMinute = 30; GregorianCalendar now = new GregorianCalendar(); boolean carryHour = false; int hourOfTheDay = now.get(Calendar.HOUR_OF_DAY); int minuteOfTheDay = now.get(Calendar.MINUTE); int hoursUntil = hourOfTheDay - indexHour; int minutesUntil = indexMinute - minuteOfTheDay; if(minutesUntil < 0){ carryHour = true; minutesUntil = 60 + minutesUntil; } // Next scheduled index still today? if(hoursUntil < 0) hoursUntil = Math.abs(hoursUntil); // Next scheduled index tomorrow? else if(hoursUntil >= 0) hoursUntil = 24 - hoursUntil; // Remove one hour if there are minutes left to the hour if(carryHour) hoursUntil--; if(minutesUntil != 0 && hoursUntil == 24) hoursUntil = 0; return new int[]{hoursUntil, minutesUntil}; } |
Nach einer Weile habe ich mir die obige Lösung für mein simples Problem auserdacht. Die Methode timeToNextIndexTask() gibt einen int-Array zurück, der die Zeit in Stunden und Minuten beinhaltet. Das lässt sich ohne Schwierigkeiten in Millisekunden umrechnen.
Aber wie das so ist, fällt einem schon kurze Zeit später auf, wie sinnlos man sich den Kopf darüber zerbrochen hat, und dass diese Lösung zwar funktioniert, aber eigentlich viel zu aufwändig und der Code ziemlich wackelig ist. Meine Frage lässt sich mit zwei GregorianCalendar-Objekten sehr einfach beantworten:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
; html-script: false ]public int[] timeToNextIndexTask(){ long minuteMilliseconds = 60 * 1000; long hourMilliseconds = minuteMilliseconds * 60; int indexHour = 14; int indexMinute = 30; GregorianCalendar now = new GregorianCalendar(); GregorianCalendar nextTime = new GregorianCalendar(); nextTime.set(Calendar.HOUR_OF_DAY, indexHour); nextTime.set(Calendar.MINUTE, indexMinute); if(now.after(nextTime)) nextTime.add(Calendar.DAY_OF_MONTH, 1); long millisecondDiff = nextTime.getTimeInMillis() - now.getTimeInMillis(); int hoursUntil = (int) (millisecondDiff / hourMilliseconds); millisecondDiff -= hoursUntil * hourMilliseconds; int minutesUntil = (int) (millisecondDiff / minuteMilliseconds); return new int[]{hoursUntil, minutesUntil}; } |
Kurzgesagt, man legt einen GregorianCalender für den aktuellen Zeitpunkt an, und verstellt einfach die Uhrzeit, behält das Datum jedoch bei. Nun muss man lediglich mit Hilfe der Methode after() bzw. before() vergleichen, ob das verstellte Calendar-Objekt in der Vergangenheit oder in der Zukunft liegt. Falls es in der Vergangenheit liegt, muss man einen Tag dazuzählen, und schon hat man seinen gewünschten Zeitpunkt.