2016-10-20 28 views
1

Ich habe eine Frage über Zonen in Java. Ich habe einen Benutzerfall, wenn Benutzer Zeitzone und etwas Zeitplan einstellen kann. Führen Sie die Aufgabe beispielsweise montags und sonntags um 23:00 Uhr mit der Zeitzone America/Los_Angeles aus. Wenn meine Server-Zeitzone UTC + 0: 00 ist, habe ich ein Problem, wie man einen Wochentag und eine neue Uhrzeit richtig erkennt (es wird etwa Dienstag und Montag um 6 Uhr morgens sein). Also meine Frage ist, wie man Benutzeraufgaben entsprechend der Server-Zeitzone und der Benutzer-Zeitzone korrekt ausführt.Java 8 zoned Daten Umwandlung

aktualisieren

Ich habe einen Cron-Ausdruck, wo ich Stunden, Minuten und Wochentag eingestellt. Wenn der Benutzer eine neue Aufgabe erstellt, kann er eine benutzerdefinierte Zeitzone einstellen (zum Beispiel um die Aufgabe am Montag um 23:00 Uhr mit benutzerdefinierter Zeitzone UTC-7: 00 zu starten.) Wenn mein Verständnis stimmt, muss ich seine Stundeneinstellung (11pm) auf den entsprechenden Server umstellen Zeit. Also, wenn meine Server-Zeitzone UTC + 3: 00 ist, muss ich 11pm auf 9am konvertieren und es wird nicht Montag (sondern Dienstag) auf meinem Server sein. Wenn ich dann Cron am Dienstag um 9 Uhr morgens laufen lasse, wird es am Montag um 23:00 Uhr aussehen, als würde der Benutzer die Aufgabe ausführen. Ist meine Vorgehensweise korrekt? Ich hoffe du verstehst meine Frage. Danke im Voraus.

+4

Also können Sie uns sagen, was das Problem ist? Können Sie uns Ihren Code zeigen? Die Systemuhr ist immer um UTC, deshalb gibt es keinen Grund, dass es ein Problem geben muss. –

+0

@PeterLawrey Ich habe meine Frage bearbeitet – jahra

+0

Sie müssen die Uhrzeit und Wochentag zusammen konvertieren. Beachten Sie bei der Sommerzeit, dass Sie nicht nur einmal rechnen können und davon ausgehen, dass dies immer richtig ist. Sie müssen das nächste Mal berechnen und eine Aufgabe hinzufügen, die zu diesem Zeitpunkt ausgeführt werden soll. z.B. Wenn sie sich in New York für 1 Uhr morgens entscheiden, wird es zu verschiedenen Zeiten des Jahres 21 Uhr UTC-4 und 20 Uhr UTC-5 sein. –

Antwort

0

Die kurze Antwort: Zählen in Millisekunden seit der Epoche. Die lange Antwort:
Zuerst ist es sehr wichtig zu verstehen, wie Computerzeit funktioniert. Ich würde empfehlen this article., Aber das Wesentliche ist, dass alles seit der Epoche, 1.1.1970 berechnet wird. Zweitens dachte ich, ein Beispiel wird Ihnen sagen mehr als 1000 Worte:

ZonedDateTime dateTime = ZonedDateTime.parse("2016-10-20T11:34:57+02:00[Europe/Zurich]"); // UTC + 2 
long millisEurope = dateTime.toInstant().toEpochMilli(); 
System.out.println(millisEurope); // 1476956097000 

dateTime = dateTime.withZoneSameLocal(ZoneId.of("America/Los_Angeles")); // UTC - 7 
long millisAmerica = dateTime.toInstant().toEpochMilli(); 
System.out.println(millisAmerica); // 1476988497000 

// The difference between UTC + 2 and UTC - 7 == -9 
System.out.println((millisEurope - millisAmerica)/1000/60/60); 

Die ZonedDateTime immer UTC verwenden (+ 0) sowie die definierte Zeitzone.

EDIT (nach dem Update):
Ja, wenn Sie die Zeit und die Zeitzone vom Benutzer erhalten, würden Sie es zu Ihrer eigenen Zeitzone konvertieren müssen auf dem gleichen Zeitpunkt ausgeführt werden sollen, .

0

Die Zeitzoneneinstellung des Betriebssystems Ihres Servers und JVM sollte für Ihre Programmierung nicht relevant sein. Beide können sich jederzeit ändern, während Laufzeit, also nicht darauf verlassen. Geben Sie immer die gewünschte/erwartete Zeitzone im optionalen Argument für die verschiedenen Datum/Uhrzeit-Methoden an.

Beachten Sie, dass zeitzonenempfindliche Momente nicht im Voraus geplant werden können. Politiker sind berüchtigt dafür, die Zeitzonendefinitionen oft mit sehr wenig Vorankündigung zu ändern.

Wenn Sie einen Alarm für den nächsten Montag um 11:00 Uhr im Kontext der Zeitzone des Benutzers einrichten möchten, benötigen Sie zuerst die Zeitzone des Benutzers. Möglicherweise können Sie eine Standardzeitzone erkennen, aber letztlich ist der einzige zuverlässige Weg, den Benutzer nach der gewünschten/erwarteten Zeitzone zu fragen.

Festlegen eines proper time zone name im Format von continent/region wie America/Montreal, Africa/Casablanca oder Pacific/Auckland. Verwenden Sie niemals die 3-4 Buchstaben Abkürzung wie EST oder IST, da sie keine echten Zeitzonen sind, nicht standardisiert und nicht einmal eindeutig (!).

Halten Sie den Wochentag des Alarms als DayOfWeek Enum-Objekt.

DayOfWeek alarmDow = DayOfWeek.MONDAY ; 

der Time-of-Tages-Alarm halten als LocalTime.

LocalTime alarmTimeOfDay = LocalTime.parse("11:00:00"); 

Diese Klasse enthält kein Datum und keine Offset-von-UTC- oder Zeitzone. Es hat also keine Bedeutung, bis man sich in eine Zeitzone einstellt.

Halten Sie die Alarmzeitzone als ZoneId.

ZoneId z = ZoneId.of("America/Montreal"); 

Mit diesen Teilen können Sie den Alarm planen.

Erhalten Sie den aktuellen Moment als Instant. Die Instant Klasse repräsentiert einen Moment auf der Timeline in UTC mit einer Auflösung von nanoseconds (bis zu neun (9) Ziffern eines Dezimalbruchteils).

Instant now = Instant.now(); 

Wenden Sie die gewünschte Zeitzone an, um eine ZonedDateTime zu erhalten.

ZonedDateTime zdtNow = instant.atZone(z); 

Um die Zukunft Moment des Alarms zu bestimmen, verwenden Sie die TemporalAdjuster Schnittstelle Datum-Zeit-Werte zu manipulieren. Die Klasse TemporalAdjusters (beachten Sie die Plural s) bietet Implementierungen. Extrahieren Sie zuerst einen Nur-Datumswert, da wir die Alarmzeit LocalTime als Uhrzeit zuweisen.

LocalDate today = zdtNow.toLocalDate(); 
LocalDate dateOfNextOrSameDow = today.with(TemporalAdjusters.withNextOrSame(alarmDow)); 

Die gewünschte Tageszeit anwenden.

ZonedDateTime zdtAlarm = ZonedDateTime.of(dateOfNextOrSameDow , alarmTimeOfDay , z) ; 

Diese spezielle Alarmdatumszeit ist möglicherweise heute schon früher vergangen. Also teste. Wenn ja, fügen Sie eine Woche hinzu, um das nächste Vorkommen des gewünschten Wochentags zu erhalten.

if(zdtAlarm.isBefore(zdtNow)) { // If already passed… 
    zdtAlarm = zdtAlarm.plusWeeks(1); // …go to next day-of-week occurrence. 
}