2015-07-16 1 views
2

J'ai un programme Java dans lequel je dois définir un objet Calendar comme étant minuit. J'ai donc suivi les instructions d'un autre enregistrement sur how to create a Java Date object of midnight today and midnight tomorrow, où vous définissez les champs comme 0, comme donc:Comportement incohérent avec la configuration de l'objet de calendrier Java à minuit

calStart.set(Calendar.HOUR_OF_DAY, 0); 
calStart.set(Calendar.MINUTE, 0); 
calStart.set(Calendar.SECOND, 0); 
calStart.set(Calendar.MILLISECOND, 0); 

Cependant, je reçois des résultats incohérents en utilisant Java 1.7.0_51. (S'il vous plaît pas de suggestions sur l'utilisation Jodatime, comme je voudrais utiliser uniquement la bibliothèque de base.)

Voici mon programme de test:

import java.text.SimpleDateFormat; 
import java.util.Calendar; 
import java.util.TimeZone; 

public class MidnightTester { 

    public static void runTestMidnight1() { 

     System.out.printf("runTestMidnight1() called\n"); 

     TimeZone tz = TimeZone.getTimeZone("UTC"); 
     Calendar cal = Calendar.getInstance(); 
     cal.setTimeInMillis(1437004800000L); 
     cal.setTimeZone(tz); 

     System.out.printf("Original timestamp:\n"); 
     printCalendarWithTimeZone(cal, tz); 

     cal.set(Calendar.HOUR_OF_DAY, 0); 
     cal.set(Calendar.MINUTE, 0); 
     cal.set(Calendar.SECOND, 0); 
     cal.set(Calendar.MILLISECOND, 0); 

     System.out.printf("Timestamp after setting to midnight:\n"); 
     printCalendarWithTimeZone(cal, tz); 
    } 

    public static void runTestMidnight2() { 

     System.out.printf("runTestMidnight2() called\n"); 

     TimeZone tz = TimeZone.getTimeZone("UTC"); 
     Calendar cal = Calendar.getInstance(); 
     cal.setTimeZone(tz); 
     cal.setTimeInMillis(1437004800000L); 

     System.out.printf("Original timestamp:\n"); 
     printCalendarWithTimeZone(cal, tz); 

     cal.set(Calendar.HOUR_OF_DAY, 0); 
     cal.set(Calendar.MINUTE, 0); 
     cal.set(Calendar.SECOND, 0); 
     cal.set(Calendar.MILLISECOND, 0); 

     System.out.printf("Timestamp after setting to midnight:\n"); 
     printCalendarWithTimeZone(cal, tz); 
    } 

    public static void printCalendarWithTimeZone(Calendar cal, TimeZone tz) { 
     SimpleDateFormat sdf = new SimpleDateFormat("EEEE, MMMM dd, yyyy, hh:mm:ss aaa"); 
     sdf.setTimeZone(tz); 
     System.out.printf("%d= %s\n", cal.getTimeInMillis(), sdf.format(cal.getTime())); 
    } 

    public static void main(String argv[]) { 

     runTestMidnight1(); 
     runTestMidnight2(); 
    } 
} 

Voici la sortie:

runTestMidnight1() called 
Original timestamp: 
1437004800000= Thursday, July 16, 2015, 12:00:00 AM 
Timestamp after setting to midnight: 
1436918400000= Wednesday, July 15, 2015, 12:00:00 AM 

runTestMidnight2() called 
Original timestamp: 
1437004800000= Thursday, July 16, 2015, 12:00:00 AM 
Timestamp after setting to midnight: 
1437004800000= Thursday, July 16, 2015, 12:00:00 AM 

Comme vous pouvez voir, dans runTestMidnight1(), la journée change du 16 juillet au 15 juillet après avoir réglé l'heure à minuit! Je ne comprends pas.

De plus bizarre est que dans runTestMidnight2(), j'échange seulement deux lignes, et le jour reste correctement le même le 16 Juillet

cal.setTimeZone(tz); 
cal.setTimeInMillis(1437004800000L); 

Je suis en Amérique/heure du Pacifique, dans le cas qui compte .

Quelqu'un peut-il m'aider à comprendre ce qui se passe?

+1

Impossible de reproduire votre erreur; il montre 'Jeudi 16 Juillet 2015, 12:00:00 AM' 4 fois. J'utilise "jdk1.7.0_ 25" et suis dans le fuseau horaire Asie/Singapour. Seulement si je laisse tomber le premier appel à 'cal.setTimeZone' je reçois quelque chose d'un peu similaire, mais alors le deuxième timestamp est le 15 juillet, 16 heures. –

+0

J'utilise java 1.7.0_51. – stackoverflowuser2010

+0

Pouvez-vous exécuter avec '-Duser.timezone = America/Los_Angeles' pour définir le fuseau horaire de votre JVM (à partir de http://stackoverflow.com/questions/2627992/force-java-timezone-as-gmt-utc)? – stackoverflowuser2010

Répondre

3

EDIT: meilleure explication

Lorsque nous appelons setTimeInMillis(), les valeurs longues passées est supposé être en UTC. et il calcule l'heure de l'objet de l'agenda en utilisant le fuseau horaire de l'utilisateur ou si un fuseau horaire est déjà disponible avec l'objet Calendrier.

Si aucun fuseau horaire n'est passé, le fuseau horaire de l'utilisateur est défini sur l'objet de calendrier. Donc, la valeur '1437004800000L' considérée comme étant dans le fuseau horaire PST et l'heure est calculée avec le fuseau horaire PST. L'appel de setTimeZone() après le réglage de millis modifie le fuseau horaire dans l'objet Calendar. L'heure de l'objet du calendrier est donc déplacée vers l'UTC. C'est le cas de runTestMidnight1(). Et c'est pourquoi nous voyons un changement de date parce que le temps original était en TVP.

Alors que dans la deuxième méthode, le fuseau horaire est d'abord défini par setTimeZone() à UTC. La valeur de temps est donc '1437004800000L' et le fuseau horaire considéré est UTC et l'heure calculée est en UTC. Et vous obtenez seulement l'heure UTC.

Et ce problème n'est reproduit que si l'utilisateur est dans le fuseau horaire derrière le fuseau horaire UTC.

Espérons que cela soit clair.