Si vous êtes juste une analyse syntaxique entrée String
, il est straighforward:
LocalDate d1 = LocalDate.parse("1893-04-01");
System.out.println(d1); // 1893-04-01
LocalDate d2 = LocalDate.parse("1400-04-01");
System.out.println(d2); // 1400-04-01
La sortie est:
1893-04-01
1400-04-01
Mais si vous avez un java.util.Date
objet et besoin de le convertir, c'est un peu plus compliqué.
A java.util.Date
contains the number of milliseconds from unix epoch (1970-01-01T00:00Z
). Donc, vous pouvez dire "c'est en UTC", mais quand vous l'imprimez, la valeur est "convertie" dans le fuseau horaire par défaut du système (dans votre cas, c'est CET
). Et SimpleDateFormat
utilise également le fuseau horaire par défaut en interne (de façon obscure que je dois admettre que je ne comprends pas complètement).
Dans votre exemple, la valeur en millisecondes de -2422054800000
est équivalente à l'instant UTC 1893-03-31T23:00:00Z
. Si vous cochez cette valeur dans Europe/Berlin
fuseau horaire:
System.out.println(Instant.ofEpochMilli(-2422054800000L).atZone(ZoneId.of("Europe/Berlin")));
La sortie est:
1893-03-31T23: 53: 28 + 00: 53: 28 [Europe/Berlin]
Oui, c'est très étrange, mais tous les lieux utilisaient des décalages étranges avant 1900 - chaque ville avait son propre heure locale, avant que la norme UTC n'ait lieu. Cela explique pourquoi vous obtenez 1893-03-31
. L'objet Date
imprime April 1st
probablement parce que l'ancienne API (java.util.TimeZone
) ne contient pas tous les décalages de l'historique, donc il suppose que c'est +01:00
.
Une alternative pour faire ce travail est d'utiliser toujours UTC comme le fuseau horaire:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getTimeZone("UTC")); // set UTC to the format
Date date = sdf.parse("1893-04-01");
LocalDate d = date.toInstant().atZone(ZoneOffset.UTC).toLocalDate();
System.out.println(d); // 1893-04-01
Cela obtenir la date locale correcte: 1893-04-01
.
Mais pour les dates avant 1582-10-15
, le code ne fonctionne pas au-dessus. C'est la date à laquelle le calendrier grégorien a été introduit. Avant cela, le calendrier julien a été utilisé, et date avant lui need an adjustment.
Je pourrais le faire avec le ThreeTen Extra project (une extension de java.time
classes, créé par le même type BTW). Dans l'ensemble org.threeten.extra.chrono
il y a les classes JulianChronology
et JulianDate
:
// using the same SimpleDateFormat as above (with UTC set)
date = sdf.parse("1400-04-01");
// get julian date from date
JulianDate julianDate = JulianChronology.INSTANCE.date(date.toInstant().atZone(ZoneOffset.UTC));
System.out.println(julianDate); // Julian AD 1400-04-01
La sortie sera:
Julian AD 1400-04-01
Maintenant, nous devons convertir le JulianDate
à LocalDate
. Si je fais LocalDate.from(julianDate)
il convertit au calendrier grégorien (et le résultat est 1400-04-10
).
Mais si vous voulez créer un LocalDate
exactement 1400-04-01
, vous devez faire ceci:
LocalDate converted = LocalDate.of(julianDate.get(ChronoField.YEAR_OF_ERA),
julianDate.get(ChronoField.MONTH_OF_YEAR),
julianDate.get(ChronoField.DAY_OF_MONTH));
System.out.println(converted); // 1400-04-01
La sortie sera:
1400-04-01
Sachez que les dates avant 1582-10-15
ont cet ajustement et SimpleDateFormat
ne peut pas gérer ces cas p correctement. Si vous devez travailler uniquement avec 1400-04-01
(valeurs année/mois/jour), utilisez un LocalDate
. Mais si vous avez besoin de le convertir en java.util.Date
, sachez que ce n'est peut-être pas la même date (en raison des ajustements grégorien/julien).
Si vous ne souhaitez pas ajouter une autre dépendance, vous pouvez également effectuer toutes les opérations mathématiques à la main. J'ai adapté le code de ThreeTen, mais l'OMI l'idéal est d'utiliser l'API lui-même (comme il peut couvrir les cas de coin et d'autres choses que je manque probablement en copiant simplement un morceau de code):
// auxiliary method
public LocalDate ofYearDay(int prolepticYear, int dayOfYear) {
boolean leap = (prolepticYear % 4) == 0;
if (dayOfYear == 366 && leap == false) {
throw new DateTimeException("Invalid date 'DayOfYear 366' as '" + prolepticYear + "' is not a leap year");
}
Month moy = Month.of((dayOfYear - 1)/31 + 1);
int monthEnd = moy.firstDayOfYear(leap) + moy.length(leap) - 1;
if (dayOfYear > monthEnd) {
moy = moy.plus(1);
}
int dom = dayOfYear - moy.firstDayOfYear(leap) + 1;
return LocalDate.of(prolepticYear, moy.getValue(), dom);
}
// sdf with UTC set, as above
Date date = sdf.parse("1400-04-01");
ZonedDateTime z = date.toInstant().atZone(ZoneOffset.UTC);
LocalDate d;
// difference between the ISO and Julian epoch day count
long julianToIso = 719164;
int daysPerCicle = (365 * 4) + 1;
long julianEpochDay = z.toLocalDate().toEpochDay() + julianToIso;
long cycle = Math.floorDiv(julianEpochDay, daysPerCicle);
long daysInCycle = Math.floorMod(julianEpochDay, daysPerCicle);
if (daysInCycle == daysPerCicle - 1) {
int year = (int) ((cycle * 4 + 3) + 1);
d = ofYearDay(year, 366);
} else {
int year = (int) ((cycle * 4 + daysInCycle/365) + 1);
int doy = (int) ((daysInCycle % 365) + 1);
d = ofYearDay(year, doy);
}
System.out.println(d); // 1400-04-01
la sortie sera:
1400-04-01
Juste rappeler que tous ces calculs n'est pas nécessaire pour les dates après 1582-10-15
.
Quoi qu'il en soit, si vous avez une entrée String
et que vous voulez analyser, ne pas utiliser SimpleDateFormat
- vous pouvez utiliser LocalDate.parse()
à la place. Ou LocalDate.of(year, month, day)
si vous connaissez déjà les valeurs.
Mais la conversion de ces dates locales de/vers java.util.Date
est plus compliquée, car Date
représente l'horodatage complet millis et les dates peuvent varier en fonction du système de calendrier utilisé.
Pouvez-vous fournir la sortie de 'System.out.println (date.getTime())'? –
Et aussi 'System.out.println (TimeZone.getDefault(). ToZoneId());' –
Prenez garde que votre conversion souhaitée de 'Date' à' LocalDate' dépend du fuseau horaire. Si vous êtes sûr que votre objet 'Date' était supposé être interprété dans le fuseau horaire par défaut de votre JVM et dans le calendrier grégorien (proleptique), votre méthode de conversion devrait être correcte. –