J'ai 2 fichiers Dans mon code:
Contenu du fichier 1:
sdf.format(formatter.parse("2015-02-02")));
Contenu du fichier 2:
public static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); public static final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Problème: la ligne ci-dessus dans le fichier 2 imprime "2015-02-02 12:00:00" initialement pendant quelques heures, mais après cela, elle affiche "2015-02-01 06:00:00". Toute idée de ce qui pourrait être le problème ici.
Informations supplémentaires:
Mon serveur fonctionne sur une machine cloud située aux États-Unis.
new java.util.Date ()
donne la valeur du fuseau horaire UTC correctement tout le temps.
Le serveur est démarré à l'aide de la commande java -jar xyz.jar
.
Il existe d'autres fichiers qui utilisent les variables sdf
et formatter
.
Je ne parviens pas à reproduire ceci sur la machine locale.
Une fois que le problème commence à se produire sur les serveurs, il affiche une date erronée jusqu'au redémarrage du serveur.
3 Réponses :
Si vous consultez la documentation officielle d'Oracle, cela indique que
Les formats de date ne sont pas synchronisés. Il est recommandé de créer instances de format distinctes pour chaque thread. Si plusieurs threads accèdent un format simultanément, il doit être synchronisé en externe.
En regardant votre code, vous semblez réutiliser la même instance sur plusieurs threads. C'est incorrect !!!
Soit maintenir un pool de formateurs OU synchroniser l'accès (non recommandé) OU vous pouvez créer une nouvelle instance à chaque fois.
Ou mieux, utilisez la nouvelle API, qui a un formateur threadsafe.
Aptly dit Nathan.
// api start -> SimpleDateFormat sdf = new SimpleDateFormat ("aaaa-MM-jj"); Formateur SimpleDateFormat = nouveau SimpleDateFormat ("aaaa-MM-jj"); sdf.format (formatter.parse ("02/02/2015"))); // api end -> créer une nouvelle instance comme ci-dessus donne également la même sortie? Quelque chose ne va pas avec ça? @CuriousMind
@Ajay dépend de la lenteur de votre serveur.
@NathanHughes DateTimeFormatter
n'est pas seulement thread-safe, comme vous l'avez déjà dit, il est également immuable. N'importe quel morceau de code peut modifier le fuseau horaire d'un SimpleDateFormat
, une autre explication potentielle du comportement observé. Une telle astuce n'est pas possible avec DateTimeFormatter
.
Le fuseau horaire était défini pour sdf
par un morceau de code dans une autre API, ce qui causait le problème. Voici un exemple d'exemple pour reproduire le problème localement:
import java.text.SimpleDateFormat; import java.util.TimeZone; public class SimpleDateFormatTExample { private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); private static SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); private static String timeZone = "CST"; public static void main(String[] args) { //-Duser.timezone=UTC try { String dateTimeString1 = sdf.format(formatter.parse("2018-01-01")); System.out.println("Thread Main->> " + dateTimeString1); //output : Thread Main->> 2018-01-01 12:00:00 } catch (Exception e) { e.printStackTrace(); } new Thread(() -> { try { //timezone is changed by another thread sdf.setTimeZone(TimeZone.getTimeZone(timeZone)); String dateTimeString = sdf.format(formatter.parse("2018-01-01")); System.out.println("Thread child->> " + dateTimeString); //output : Thread child->> 2017-12-31 06:00:00 } catch (Exception e) { e.printStackTrace(); } }).start(); try { Thread.sleep(1000); String dateTimeString1 = sdf.format(formatter.parse("2018-02-15")); System.out.println("Thread Main:After timezone changes by another thread->> " + dateTimeString1); //output : Thread Main:After timezone changes by another thread->> 2018-02-14 06:00:00 } catch (Exception e) { e.printStackTrace(); } }
}
Les commentaires de Nathan Hughes et de moi-même sont assez bons pour être combinés en une réponse: utilisez java.time, l'API de date et heure moderne, et plus particulièrement son DateTimeFormatter
.
String stringToPrint = LocalDate.parse("2015-02-02") .atStartOfDay(ZoneOffset.UTC) .format(printFormatter); System.out.println(stringToPrint);
Je vous recommande de ne pas utiliser
SimpleDateFormat
. Cette classe est mal conçue et notoirement gênante. Utilisez plutôtDateTimeFormatter
de java.time, la date et l'heure Java modernes API .Ce comportement particulier a-t-il été observé une fois ou combien de fois environ? Pouvez-vous le reproduire systématiquement?
@ OleV.V. Je ne peux pas le reproduire localement. Une fois que le problème commence à se produire sur les serveurs, il affiche une date incorrecte jusqu'à ce que le serveur soit redémarré.Utilisé DateTimeFormatter et il a résolu le problème.
@ OleV.V. Je m'excuse pour la confusion ici. J'avais utilisé hh: mm: ss dans mon code qui affichait l'heure au format 12 heures.