tl; dr
Existe-t-il un moyen, dans le code ou avec des arguments JVM, de remplacer l'heure actuelle, telle que présentée via System.currentTimeMillis, autre que de modifier manuellement l'horloge système sur la machine hôte?
Oui.
Instant.now(
Clock.fixed(
Instant.parse( "2016-01-23T12:34:56Z"), ZoneOffset.UTC
)
)
Clock
Dans java.time
Nous avons une nouvelle solution au problème d'un remplacement d'horloge enfichable pour faciliter les tests avec de fausses valeurs de date-heure. Le package java.time de Java 8 comprend une classe abstraite java.time.Clock
, avec un objectif explicite:
pour permettre le branchement d'horloges alternatives au fur et à mesure des besoins
Vous pouvez brancher votre propre implémentation de Clock
, bien que vous puissiez probablement en trouver une déjà conçue pour répondre à vos besoins. Pour votre commodité, java.time inclut des méthodes statiques pour produire des implémentations spéciales. Ces implémentations alternatives peuvent être utiles pendant les tests.
Cadence modifiée
Les différentes tick…
méthodes produisent des horloges qui incrémentent le moment actuel avec une cadence différente.
La valeur par défaut Clock
signale une heure mise à jour aussi souvent que des millisecondes en Java 8 et en Java 9 aussi bien que des nanosecondes (selon votre matériel). Vous pouvez demander que le moment réel soit signalé avec une granularité différente.
Fausses horloges
Certaines horloges peuvent mentir, produisant un résultat différent de celui de l'horloge matérielle du système d'exploitation hôte.
fixed
- Signale un seul moment inchangé (non incrémentiel) comme moment actuel.
offset
- Rapporte le moment actuel mais décalé par l' Duration
argument passé .
Par exemple, verrouillez le premier moment du premier Noël de cette année. en d'autres termes, lorsque le Père Noël et ses rennes font leur premier arrêt . Le fuseau horaire le plus ancien de nos jours semble être Pacific/Kiritimati
à +14:00
.
LocalDate ld = LocalDate.now( ZoneId.of( "America/Montreal" ) );
LocalDate xmasThisYear = MonthDay.of( Month.DECEMBER , 25 ).atYear( ld.getYear() );
ZoneId earliestXmasZone = ZoneId.of( "Pacific/Kiritimati" ) ;
ZonedDateTime zdtEarliestXmasThisYear = xmasThisYear.atStartOfDay( earliestXmasZone );
Instant instantEarliestXmasThisYear = zdtEarliestXmasThisYear.toInstant();
Clock clockEarliestXmasThisYear = Clock.fixed( instantEarliestXmasThisYear , earliestXmasZone );
Utilisez cette horloge fixe spéciale pour toujours renvoyer le même moment. Nous obtenons le premier moment du jour de Noël à Kiritimati , avec UTC indiquant une horloge murale de quatorze heures plus tôt, 10 heures du matin à la date précédente du 24 décembre.
Instant instant = Instant.now( clockEarliestXmasThisYear );
ZonedDateTime zdt = ZonedDateTime.now( clockEarliestXmasThisYear );
instant.toString (): 2016-12-24T10: 00: 00Z
zdt.toString (): 2016-12-25T00: 00 + 14: 00 [Pacifique / Kiritimati]
Voir le code en direct sur IdeOne.com .
Heure vraie, fuseau horaire différent
Vous pouvez contrôler le fuseau horaire attribué par l' Clock
implémentation. Cela peut être utile dans certains tests. Mais je ne le recommande pas dans le code de production, où vous devez toujours spécifier explicitement l'option ZoneId
ou les ZoneOffset
arguments.
Vous pouvez spécifier que UTC soit la zone par défaut.
ZonedDateTime zdtClockSystemUTC = ZonedDateTime.now ( Clock.systemUTC () );
Vous pouvez spécifier n'importe quel fuseau horaire particulier. Indiquez un nom de fuseau horaire approprié dans le format continent/region
, tels que America/Montreal
, Africa/Casablanca
ou Pacific/Auckland
. N'utilisez jamais l'abréviation de 3 à 4 lettres telle que EST
ou IST
car ce ne sont pas de vrais fuseaux horaires, non standardisés et même pas uniques (!).
ZonedDateTime zdtClockSystem = ZonedDateTime.now ( Clock.system ( ZoneId.of ( "America/Montreal" ) ) );
Vous pouvez spécifier que le fuseau horaire par défaut actuel de la machine virtuelle Java doit être celui par défaut pour un Clock
objet particulier .
ZonedDateTime zdtClockSystemDefaultZone = ZonedDateTime.now ( Clock.systemDefaultZone () );
Exécutez ce code pour comparer. Notez qu'ils rapportent tous le même moment, le même point sur la chronologie. Ils ne diffèrent que par l' heure de l'horloge murale ; en d'autres termes, trois façons de dire la même chose, trois façons d'afficher le même moment.
System.out.println ( "zdtClockSystemUTC.toString(): " + zdtClockSystemUTC );
System.out.println ( "zdtClockSystem.toString(): " + zdtClockSystem );
System.out.println ( "zdtClockSystemDefaultZone.toString(): " + zdtClockSystemDefaultZone );
America/Los_Angeles
était la zone par défaut actuelle de la JVM sur l'ordinateur qui exécutait ce code.
zdtClockSystemUTC.toString (): 2016-12-31T20: 52: 39.688Z
zdtClockSystem.toString (): 2016-12-31T15: 52: 39.750-05: 00 [Amérique / Montréal]
zdtClockSystemDefaultZone.toString (): 2016-12-31T12: 52: 39.762-08: 00 [America / Los_Angeles]
La Instant
classe est toujours en UTC par définition. Donc, ces trois Clock
usages liés à la zone ont exactement le même effet.
Instant instantClockSystemUTC = Instant.now ( Clock.systemUTC () );
Instant instantClockSystem = Instant.now ( Clock.system ( ZoneId.of ( "America/Montreal" ) ) );
Instant instantClockSystemDefaultZone = Instant.now ( Clock.systemDefaultZone () );
instantClockSystemUTC.toString (): 2016-12-31T20: 52: 39.763Z
instantClockSystem.toString (): 2016-12-31T20: 52: 39.763Z
instantClockSystemDefaultZone.toString (): 2016-12-31T20: 52: 39.763Z
Horloge par défaut
L'implémentation utilisée par défaut pour Instant.now
est celle renvoyée par Clock.systemUTC()
. Il s'agit de l'implémentation utilisée lorsque vous ne spécifiez pas de fichier Clock
. Voyez par vous -Instant.now
même dans le code source de Java 9 pré-version pour .
public static Instant now() {
return Clock.systemUTC().instant();
}
La valeur Clock
par défaut pour OffsetDateTime.now
et ZonedDateTime.now
est Clock.systemDefaultZone()
. Voir le code source .
public static ZonedDateTime now() {
return now(Clock.systemDefaultZone());
}
Le comportement des implémentations par défaut a changé entre Java 8 et Java 9. Dans Java 8, le moment actuel est capturé avec une résolution en millisecondes seulement malgré la capacité des classes à stocker une résolution de nanosecondes . Java 9 apporte une nouvelle implémentation capable de capturer le moment actuel avec une résolution de nanosecondes - en fonction, bien sûr, de la capacité de l'horloge matérielle de votre ordinateur.
À propos de java.time
Le framework java.time est intégré à Java 8 et versions ultérieures. Ces classes supplantent les anciens gênants hérités des classes date-heure tels que java.util.Date
, Calendar
, et SimpleDateFormat
.
Pour en savoir plus, consultez le didacticiel Oracle . Et recherchez Stack Overflow pour de nombreux exemples et explications. La spécification est JSR 310 .
Le projet Joda-Time , désormais en mode maintenance , conseille la migration vers les classes java.time .
Vous pouvez échanger des objets java.time directement avec votre base de données. Utilisez un pilote JDBC compatible avec JDBC 4.2 ou version ultérieure. Pas besoin de chaînes, pas besoin de java.sql.*
classes. Hibernate 5 et JPA 2.2 prennent en charge java.time .
Où obtenir les classes java.time?