Changement de Date lors de la conversion de XMLGregorianCalendar de Calendrier
Lors de l'essai d'un service web que les cartes de types datetime entre les systèmes, j'ai remarqué que l'envoi de n'importe quelle date avant le calendrier Grégorien, l'heure de début a entraîné une perte de précision lors de la conversion vers le type final, avec le résultat final toujours légèrement en avance dans le temps dans l'intervalle de quelques jours.
J'ai réduit le problème à la ligne exacte, mais je n'arrive toujours pas à comprendre pourquoi c'est être jeté comme si, à partir de la la documentation il affirme que le calendrier Julien est utilisé pour datetimes avant le calendrier Grégorien début: 15 octobre 1582.
Le problème est à la distribution de XMLGregorianCalendar
à GregorianCalendar
, ligne 78: calendarDate = argCal.toGregorianCalendar();
Lorsque le temps est pris de calendarDate
sur la ligne 86: cal.setTime(calendarDate.getTime());
vient Le temps de retour de 2 jours à l'avance de ce qu'il devrait être, Janv. 03 au lieu de Janv. 01, comme vous allez le voir à partir de la sortie dans le programme ci-dessous.
Voici un exemple de programme que j'ai fait pour montrer le processus de moulage à la fin:
import java.sql.Date;
import java.util.Calendar;
import java.util.GregorianCalendar;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
public class TestDateConversions {
public static void main(String[] args)
{
TestDateConversions testDates = new TestDateConversions();
try
{
XMLGregorianCalendar testDate1 = DatatypeFactory.newInstance().newXMLGregorianCalendar();
testDate1.setYear(0001);
testDate1.setMonth(01);
testDate1.setDay(01);
System.out.println("Start date: "+testDate1.toString() +"\n**********************");
testDates.setXMLGregorianCalendar(testDate1);
System.out.println("\nNull given \n"+ "**********");
testDates.setXMLGregorianCalendar(null);
}
catch(Exception e)
{
System.out.println(e);
}
}
public void setXMLGregorianCalendar(XMLGregorianCalendar argCal)
{
GregorianCalendar calendarDate;
if (argCal != null)
{
calendarDate = argCal.toGregorianCalendar();
System.out.println("XMLGregorianCalendar time: " + argCal.getHour() + ":"+argCal.getMinute()+":"+argCal.getSecond());
System.out.println("XMLGregorianCalendar time(ms): "+argCal.getMillisecond());
System.out.println("XMLGregorianCalendar -> GregorianCalendar: "+calendarDate.get(GregorianCalendar.YEAR) + "-"+(calendarDate.get(GregorianCalendar.MONTH)+1) + "-"+calendarDate.get(GregorianCalendar.DAY_OF_MONTH));
System.out.println("!!!!PROBLEM AREA!!!!");
Calendar cal = Calendar.getInstance();
System.out.println("-- New Calendar instance: "+cal.get(Calendar.YEAR) + "-"+(cal.get(Calendar.MONTH)+1)+"-"+cal.get(Calendar.DAY_OF_MONTH));
System.out.println("-- Calling Calendar.setTime(GregorianCalendar.getTime())");
cal.setTime(calendarDate.getTime());
System.out.println("-- calendarDate.getTime() = " + calendarDate.getTime() + " <-- time is incorrect");
System.out.println("-- Calendar with time set from GregorianCalendar: "+cal.get(Calendar.YEAR) + "-"+(cal.get(Calendar.MONTH)+1)+"-"+cal.get(Calendar.DAY_OF_MONTH) + " <-- day is increased here");
setCalendar(cal);
}
else
{
setCalendar(null);
}
}
public void setCalendar(Calendar argCal)
{
if (argCal != null)
{
Date date = new Date(argCal.getTimeInMillis());
System.out.println("Calendar to Date: "+date);
setDate(date);
}
else
{
setDate(null);
}
}
public void setDate(Date argDate)
{
try
{
if (argDate == null)
{
Calendar cal = new GregorianCalendar(1,0,1);
Date nullDate = new Date(cal.getTimeInMillis());
System.out.println("Null Calendar created: "+cal.get(Calendar.YEAR) + "-"+(cal.get(Calendar.MONTH)+1)+"-"+cal.get(Calendar.DAY_OF_MONTH));
System.out.println("Null Date created: "+nullDate);
}
else
{
System.out.println("Final date type: "+argDate);
}
}
catch (Exception ex)
{
System.out.println(ex);
}
}
}
Je ne dis pas que tout est loin, j'ai juste souligné que toute date avant le Grégorien, le temps est en cours de modification. Mon exemple précis est assez évident qu'il y dans le code du programme, la date
0001-01-01
est en cours de modification pour 0001-01-03
, et il ne devrait pas être.Bon, pour être honnête, ça ressemble à un problème dans la bibliothèque. Comme une hypothèse, disons que c'est en essayant de la Proleptic Calendrier. Il est encore hors de Julien par le montant est erroné. Vous avez totalement raison. calendars.wikia.com/wiki/Proleptic_Gregorian_calendar --
Merci Jim. Si c'est le cas, alors je suis honnêtement pas trop sûr de l'endroit où aller à partir d'ici, je suppose que je pourrais le signaler.
Il y a peut être quelque chose de mal avec les fuseaux horaires. Sur un projet lorsque nous avons converti
Date => LocalDate => Date
(JodaTime dans le milieu) nous avons obtenu un résultat qui était de 15 minutes au large de la date initiale. La chose est que TZ de données de Java était plus vieux que ce Joda a (manquant 15min maj déclaré en 1891). Ce genre de choses peut se produire si vous travaillez avec une date et un mélange d'horodatage de représentation et de calendrier terrain de la représentation. Retour ensuite nous avons résolu notre problème avec Joda grâce à une méthode dédiée à cet effet -> joda-time.sourceforge.net/apidocs/org/joda/time/LocalDate.html .
OriginalL'auteur JWiley | 2013-05-01
Vous devez vous connecter pour publier un commentaire.
Extrait de
XMLGregorianCalendar.toGregorianCalendar()
JavaDoc sur la façon dont ils créent laGregorianCalendar
exemple:Cela signifie, que le calendrier de création sera proleptic et de ne pas passer à calendrier Julien comme il le fait par défaut pour les anciennes dates. Le problème est ici:
argCal.toGregorianCalendar()
de conversion de XMLGregorianCalendar à GregorianCalendar à l'aide du champ de la représentation (Julien système n'est pas utilisé - voir ci-dessus)cal.setTime(calendarDate.getTime());
Il y a quelques façons de résoudre ce problème:
LocalDate#fromCalendarFiels
si vous êtes intéressé à la dateconvertir les calendriers à l'aide d'accès sur le terrain et de ne pas le#getTime
méthodeMise à JOUR Veuillez noter que Java Date et Calendar Api ne sont pas très bien conçu et peut être (et sont) parfois assez déroutant. C'est aussi pourquoi Java 8 contient complètement retravaillé date-time library JSR 310 (basé sur JodaTime par la voie).
Maintenant, vous avez à réaliser, que vous pouvez stocker et de travailler avec un instant (calendrier indépendant mot-clé) par l'intermédiaire de deux approches très différentes:
La première approche est ce qui est utilisé sous le capot dans
java.util.Date
. Cependant, cette représentation est généralement non-humain amical. L'homme travailler avec des dates de calendrier, pas les horodatages. La conversion des horodateurs pour les champs de date est où Calendrier des étapes. Aussi c'est là le plus drôle, la partie commence... si vous voulez représenter date par ses champs, vous devez réaliser qu'il y a toujours plusieurs façons de le faire. Une nation peut décider d'utiliser les mois lunaires, d'autres pourront dire que l'année 0 a à peine 10 ans. Et le calendrier grégorien est juste un moyen de conversion réel instantané à de véritables champs de date.Un peu sur XMLGregorianCalendar vs GregorianCalendar:
Maintenant la partie intéressante:
Si l'Julian interrupteur ne pas être désactivé, GregorianCalendar suppose que le calendrier des champs sont de Julian système et il va les passer en 3 jours. Vous pensiez que la date a été décalée de 3 jours et quelque chose doit se passait mal, non? Non, la date était en fait tout le temps correct et il contenait estampillage, sous le capot! Seul le calendrier avait présenté vous Julian champs au lieu du chant Grégorien champs. Et c'est assez déroutant, je dirais 🙂 [JSR 310 de rire dans le fond].
Donc, si vous voulez travailler avec pure calendrier grégorien (c'est à dire à utiliser proleptic grégorien pour les anciennes dates de), vous devez initialiser le calendrier comme ceci:
Vous pourriez dire:
calendar.getTime()
est encore de me donner de date incorrect. Eh bien, c'est parce quejava.util.Date.toString()
(appelé parSystem.out.println
) est à l'aide de la valeur par défautCalendar
, qui va passer à Julian système pour les anciennes dates. Confus? Peut-être en colère (je sais que je suis :))?Mise à JOUR 2
Clause de non-responsabilité: ce code est faux (le résultat instantané n'est pas la même que celle dans le fichier XML), mais l'OP comprend le problème et de ses conséquences (voir la discussion en vertu de cette réponse).
J'ai mis à jour la réponse avec quelques informations de base sur la Date et le Calendrier des interactions. Aussi, j'ai supprimé le deuxième point que ce n'était pas correct de conseils et de vous conduire à plus de problèmes.
Cette dernière partie fait juste plus de confusion. Comment appliquer votre solution à ce que j'ai? En d'autres termes, où aurais-je intégrer
((GregorianCalendar) calendar).setGregorianChange(new Date(Long.MIN_VALUE));
dans monsetXMLGregorianCalendar
de la méthode et de l'utiliser pour obtenir la date de laGregorianCalendar
variable?Vous devez appeler cette méthode à chaque fois que vous créez ou obtenir un nouveau Calendrier de l'instance.
Aussi le point que j'essayais de faire était que de la date n'a jamais été incorrect... c'était juste affiché dans le système. La Conversion à proleptic Grégorien peut être faite juste avant de l'afficher à l'utilisateur si nécessaire. Mais il n'y a rien de mal si vous avez la force de chaque année civile de votre demande à être proleptic. Cependant
Date#toString
sera probablement toujours passer à Julian et à l'affichage de "incorrect" de la valeur.OriginalL'auteur Pavel Horal
Il semble que si vous êtes accidentellement la conversion du Calendrier Grégorien, le Calendrier Julien. Le jour de l' (par extrapolation ou proleptic) du Calendrier Grégorien, qui désigne comme 0001-01-01 est, en effet, 0001-01-03 dans le Calendrier Julien. Si vous modifiez votre date de 1001-01-01, vous trouverez que votre résultat final est 1000-12-26. Ceci est cohérent avec la date de conversions à partir de la Grégorienne à Julien, que le décalage des changements au fil du temps. Il a été positive avant le 4ème siècle, mais a été négative (et de plus en plus négative au cours du temps) depuis.
L'instance de
XMLGregorianCalendar
- je obtenir est en fait uncom.sun.org.apache.xerces.internal.jaxp.datatype.XMLGregorianCalendarImpl
et latoGregorianCalendar()
méthode inclut ces lignes:Cela rend le calendrier purement proleptic GregorianCalendar, afin que les dates avant 1583 sont encore convertis à partir de l'époque de temps (en millisecondes depuis 1970) par le chant Grégorien de l'algorithme. Ce qui signifie que le problème est probablement dans
GregorianCalendar
...Qui est effectivement le cas. Essayez cet exemple de programme et vous verrez:
Le domaine des valeurs allant en sont interprétés comme Grégorien en raison de la valeur de
getGregorianChange()
... mais en sortant (conversion de l'époque millisecondes) que le terrain semble être transgressée. LeDate
qui sort degetTime()
a aucun concept de ce que la Grégorienne passage de la valeur a été. Cela peut ou peut ne pas être un bug, mais c'est certainement un comportement inattendu.OriginalL'auteur dcsohl