Учитывая, что дата начала по григорианскому календарю - 15 октября 1582 года, рассмотрите следующие тесты и помогите мне понять, что происходит:
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import javax.xml.datatype.DatatypeFactory;
import org.junit.Test;
@Test
public void gregorianToDateConversion() {
GregorianCalendar calendar = null;
Date date = null;
calendar = new GregorianCalendar(1582, 9, 04);
date = calendar.getTime();
System.out.println("new GregorianCalendar(1582, 9, 4) -> calendar[DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("calendar.getTime() -> Date:" + date);
calendar = new GregorianCalendar(1582, 9, 05);
date = calendar.getTime();
System.out.println("\nnew GregorianCalendar(1582, 9, 5) -> calendar[DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("calendar.getTime() -> Date:" + date);
calendar = new GregorianCalendar(1582, 9, 14);
date = calendar.getTime();
System.out.println("\nnew GregorianCalendar(1582, 9, 14) -> calendar[DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("calendar.getTime() -> Date:" + date);
calendar = new GregorianCalendar(1582, 9, 15);
date = calendar.getTime();
System.out.println("\nnew GregorianCalendar(1582, 9, 15) -> calendar[DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("calendar.getTime() -> Date:" + date);
String dateToParse = null;
dateToParse = "1582-10-04";
System.out.println("\nString to parse: " + dateToParse);
calendar = parseDateTime(dateToParse);
if(calendar != null) {
date = calendar.getTime();
System.out.println("datatypeFactory.newXMLGregorianCalendar(s).toGregorianCalendar() -> \n calendar[DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("calendar.getTime() -> Date: " + date);
}
dateToParse = "1582-10-05";
System.out.println("\nString to parse: " + dateToParse);
calendar = parseDateTime(dateToParse);
if(calendar != null) {
date = calendar.getTime();
System.out.println("datatypeFactory.newXMLGregorianCalendar(s).toGregorianCalendar() -> \n calendar[DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("calendar.getTime() -> Date: " + date);
}
dateToParse = "1582-10-14";
System.out.println("\nString to parse: " + dateToParse);
calendar = parseDateTime(dateToParse);
if(calendar != null) {
date = calendar.getTime();
System.out.println("datatypeFactory.newXMLGregorianCalendar(s).toGregorianCalendar() -> \n calendar[DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("calendar.getTime() -> Date: " + date);
}
dateToParse = "1582-10-15";
System.out.println("\nString to parse: " + dateToParse);
calendar = parseDateTime(dateToParse);
if(calendar != null) {
date = calendar.getTime();
System.out.println("datatypeFactory.newXMLGregorianCalendar(s).toGregorianCalendar() -> \n calendar[DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("calendar.getTime() -> Date: " + date);
}
}
private GregorianCalendar parseDateTime(String s) {
DatatypeFactory datatypeFactory = null;
try {
datatypeFactory = DatatypeFactory.newInstance();
return datatypeFactory.newXMLGregorianCalendar(s).toGregorianCalendar();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Результаты следующие:
new GregorianCalendar(1582, 9, 4) -> calendar[DAY_OF_MONTH [4], MONTH [9], YEAR [1582]] **OK**
calendar.getTime() -> Date:Thu Oct 04 00:00:00 CET 1582 **OK**
new GregorianCalendar(1582, 9, 5) -> calendar[DAY_OF_MONTH [15], MONTH [9], YEAR [1582]] **+ 10 days ??**
calendar.getTime() -> Date:Fri Oct 15 00:00:00 CET 1582 **coherent with calendar**
new GregorianCalendar(1582, 9, 14) -> calendar[DAY_OF_MONTH [24], MONTH [9], YEAR [1582]] **+ 10 days ??**
calendar.getTime() -> Date:Sun Oct 24 00:00:00 CET 1582 **coherent with calendar**
new GregorianCalendar(1582, 9, 15) -> calendar[DAY_OF_MONTH [15], MONTH [9], YEAR [1582]] **OK**
calendar.getTime() -> Date:Fri Oct 15 00:00:00 CET 1582 **OK**
String to parse: 1582-10-04
datatypeFactory.newXMLGregorianCalendar(s).toGregorianCalendar() ->
calendar[DAY_OF_MONTH [4], MONTH [9], YEAR [1582]]
calendar.getTime() -> Date: Mon Sep 24 00:00:00 CET 1582 **Not coherent with calendar. Conversion to julian date?**
String to parse: 1582-10-05
datatypeFactory.newXMLGregorianCalendar(s).toGregorianCalendar() ->
calendar[DAY_OF_MONTH [5], MONTH [9], YEAR [1582]]
calendar.getTime() -> Date: Tue Sep 25 00:00:00 CET 1582 **Not coherent with calendar. Conversion to julian date?**
String to parse: 1582-10-14
datatypeFactory.newXMLGregorianCalendar(s).toGregorianCalendar() ->
calendar[DAY_OF_MONTH [14], MONTH [9], YEAR [1582]] **OK**
calendar.getTime() -> Date: Thu Oct 04 00:00:00 CET 1582 **Not coherent with calendar. Conversion to julian date?**
String to parse: 1582-10-15
datatypeFactory.newXMLGregorianCalendar(s).toGregorianCalendar() ->
calendar[DAY_OF_MONTH [15], MONTH [9], YEAR [1582]] **OK**
calendar.getTime() -> Date: Fri Oct 15 00:00:00 CET 1582 **OK**
Не могли бы вы пояснить мне, что происходит? Большое тебе спасибо.
РЕДАКТИРОВАТЬ: Спасибо, я исправил свои ошибки в формате даты для синтаксического анализа: теперь все имеют вид yyyy-MM-gg, и больше не создаются исключения.
Сейчас пытаюсь уточнить свои дубты.
Что определяет, используем ли мы пролептический григорианский календарь?
Подводя итог:
java.util.GregorianCalendar представляет собой юлианский календарь для дат до 15 октября 1582 года и григорианский календарь после этой даты. Это правильно?
Итак, это оправдывает поведение в новом GregorianCalendar (...) ...
Если я это сделаю:
new GregorianCalendar(1582, 9, 4)
у меня есть
calendar[DAY_OF_MONTH [4], MONTH [9], YEAR [1582]]
потому что 4 октября 1582 года существует в юлианском календаре, а созданный мной календарь представляет юлианскую дату.
Преобразуя этот календарь в дату, мы получаем:
Date:Thu Oct 04 00:00:00 CET 1582, consistent with Calendar.
If I do:
new GregorianCalendar(1582, 9, 5)
Я получаю
calendar[DAY_OF_MONTH [15], MONTH [9], YEAR [1582]]
потому что день 5 октября не существует ни в юлианском, ни в григорианском календаре. Таким образом, конструктор GregorianCalendar создает дату ровно через 1 день после 4 октября, то есть в первый день григорианского календаря, 15 октября. Затем новая дата выражается в системе григорианского календаря.
Я буду вести себя так же, создавая новый календарь, передающий даты с (1582, 9, 5) на (1582, 9, 14).
В примере выше преобразованный java.util.Date снова соответствует календарю
Date:Fri Oct 15 00:00:00 CET 1582
If I do:
new GregorianCalendar(1582, 9, 15)
у меня есть
calendar[DAY_OF_MONTH [15], MONTH [9], YEAR [1582]]
потому что 15 октября существует в григорианском календаре, и новая дата выражается в этой системе. Календарь, преобразованный в дату, снова согласован:
Date:Fri Oct 15 00:00:00 CET 1582
Это означает, что конструктор GregorianCalendar предполагает, что я ввожу даты в календарной системе, которая действительна для данной эпохи: другими словами, предполагает, что если я ввожу дату, предшествующую или равную 4 октября, я думаю, что дата соответствует юлианскому календарю. календарь, и дата выражается в этой системе, если я ввожу дату между 05 и 14 октября, она подсчитывает количество дней между датой окончания по юлианскому календарю (04 октября) и датой, которую я ввел, и суммирует эти дни с датой начала григорианского календаря (15 октября) и выражаю новую дату в григорианской системе, и если я ввожу дату после или равную 15 октября, предполагается, что введенная мной дата предназначена для григорианского календаря, а новая дата выражается в этой системе.
Все это правильно?
Это не пролептическое поведение, верно? Если бы календарь был пролептическим григорианским календарем, я бы ожидал, что его инициализация
new GregorianCalendar(1582, 9, 5)
Я бы получил
calendar[DAY_OF_MONTH [5], MONTH [9], YEAR [1582]]
То есть 5 октября устанавливается также, если дата не существует в григорианской системе и, если я не ошибаюсь, за 10 дней до первого дня григорианского календаря она будет равна юлианской дате 25 сентября.
Как я могу решить использовать пролептический григорианский календарь или нет?
Анализируя строку и создавая новый GregorianCalendar, проходящий через XmlGregorianCalendar, поведение кажется мне другим.
Анализируя "1582-10-04", я получаю
calendar[DAY_OF_MONTH [4], MONTH [9], YEAR [1582]]
(как в примере выше ..), но дата
Date: Mon Sep 24 00:00:00 CET 1582
(Здесь у нас есть юлианская дата, верно? Но в приведенном выше примере (где GregorianCalendar был создан его конструктором) Дата была равна Календарю. Почему теперь она другая?
Разбирая строку "1582-10-05", получаем
calendar[DAY_OF_MONTH [5], MONTH [9], YEAR [1582]]
(Теперь у нас есть пролептический григорианский календарь, не так ли?)
Но снова другая Дата
Date: Tue Sep 25 00:00:00 CET 1582 (Julian Date? Why?)
Такое же поведение при синтаксическом анализе "1582-10-14"
calendar[DAY_OF_MONTH [14], MONTH [9], YEAR [1582]]
Date: Thu Oct 04 00:00:00 CET 1582
Если мы наконец проанализируем «1582-10-15», мы вернемся к григорианской эпохе, и все станет последовательным:
calendar[DAY_OF_MONTH [15], MONTH [9], YEAR [1582]]
Date: Fri Oct 15 00:00:00 CET 1582
Можете ли вы помочь мне понять все это поведение?
Большое спасибо.
ИЗМЕНИТЬ 2:
Спасибо за ответы, даже если у меня остались сомнения. Я пробовал следующий код:
GregorianCalendar proleptic = new GregorianCalendar();
proleptic.setGregorianChange(new Date(Long.MIN_VALUE));
proleptic.set(Calendar.DAY_OF_MONTH, 5);
proleptic.set(Calendar.MONTH, 9);
proleptic.set(Calendar.YEAR, 1582);
System.out.println("proleptic [DAY_OF_MONTH ["+proleptic.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+proleptic.get(Calendar.MONTH)+"], YEAR ["+proleptic.get(Calendar.YEAR)+"]");
Date prolepticDate = proleptic.getTime();
System.out.println("prolepticDate ["+prolepticDate+"]");
Результат был:
proleptic [DAY_OF_MONTH [5], MONTH [9], YEAR [1582]
prolepticDate [Tue Sep 25 00:24:07 CET 1582]
Теперь у меня есть календарь с DAY_OF_MONTH, который соответствует тому, что я установил, так что я думаю, что это пролептическое поведение, верно? Но снова я спрашиваю, почему Дата, полученная методом getTime (), представляет не тот же день, а 10 дней назад. Спасибо еще раз.
ИЗМЕНИТЬ 3:
Вопрос для меня немного яснее, но не до конца. Я не понимал подробно, по какой логике выполняется преобразование из GregorianCalendar в Date и почему пролептический григорианский календарь и традиционный календарь, каждый из которых построен с такими же параметрами, как DAY, MONTH и YEAR, не всегда представляют один и тот же момент времени. Я сделал еще несколько тестов.
GregorianCalendar proleptic = null;
GregorianCalendar calendar = null;
Date date = null;
// ---- JULIAN PERIOD ----
proleptic = new GregorianCalendar();
proleptic.clear();
proleptic.setGregorianChange(new Date(Long.MIN_VALUE));
proleptic.set(Calendar.DAY_OF_MONTH, 5);
proleptic.set(Calendar.MONTH, Calendar.FEBRUARY);
proleptic.set(Calendar.YEAR, 1582);
System.out.println("proleptic_calendar_5Feb1582 [DAY_OF_MONTH ["+proleptic.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+proleptic.get(Calendar.MONTH)+"], YEAR ["+proleptic.get(Calendar.YEAR)+"]");
date = proleptic.getTime();
System.out.println("date_5Feb1582 from proleptic ["+date+"]");
calendar = new GregorianCalendar(1582, 1, 5);
date = calendar.getTime();
System.out.println("new GregorianCalendar(1582, 1, 5) -> [DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("new GregorianCalendar(1582, 1, 5) .getTime() -> Date:" + date);
System.out.println("proleptic_calendar_5Feb1582 in millis ["+proleptic.getTimeInMillis()+"], new GregorianCalendar(1582, 1, 5) in millis ["+calendar.getTimeInMillis()+"], millis are equal ["+ (proleptic.getTimeInMillis() == calendar.getTimeInMillis()) +"]");
//--------
System.out.println("\n");
// ---- transition period ----
proleptic = new GregorianCalendar();
proleptic.clear();
proleptic.setGregorianChange(new Date(Long.MIN_VALUE));
proleptic.set(Calendar.DAY_OF_MONTH, 8);
proleptic.set(Calendar.MONTH, Calendar.OCTOBER);
proleptic.set(Calendar.YEAR, 1582);
System.out.println("proleptic_calendar_8Oct1582 [DAY_OF_MONTH ["+proleptic.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+proleptic.get(Calendar.MONTH)+"], YEAR ["+proleptic.get(Calendar.YEAR)+"]");
date = proleptic.getTime();
System.out.println("date_5Oct1582 from proleptic ["+date+"]");
calendar = new GregorianCalendar(1582, 9, 8);
date = calendar.getTime();
System.out.println("new GregorianCalendar(1582, 9, 8) -> [DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("new GregorianCalendar(1582, 9, 8) .getTime() -> Date:" + date);
System.out.println("proleptic_calendar_8Oct1582 in millis ["+proleptic.getTimeInMillis()+"], new GregorianCalendar(1582, 9, 8) in millis ["+calendar.getTimeInMillis()+"], millis are equal ["+ (proleptic.getTimeInMillis() == calendar.getTimeInMillis()) +"]");
//--------
System.out.println("\n");
// ---- GREGORIAN PERIOD ----
proleptic = new GregorianCalendar();
proleptic.clear();
proleptic.setGregorianChange(new Date(Long.MIN_VALUE));
proleptic.set(Calendar.DAY_OF_MONTH, 5);
proleptic.set(Calendar.MONTH, Calendar.DECEMBER);
proleptic.set(Calendar.YEAR, 1582);
System.out.println("proleptic_calendar_5Dec1582 [DAY_OF_MONTH ["+proleptic.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+proleptic.get(Calendar.MONTH)+"], YEAR ["+proleptic.get(Calendar.YEAR)+"]");
date = proleptic.getTime();
System.out.println("date_5Dec1582 from proleptic ["+date+"]");
calendar = new GregorianCalendar(1582, 11, 5);
date = calendar.getTime();
System.out.println("new GregorianCalendar(1582, 11, 5) -> [DAY_OF_MONTH ["+calendar.get(Calendar.DAY_OF_MONTH)+"], MONTH ["+calendar.get(Calendar.MONTH)+"], YEAR ["+calendar.get(Calendar.YEAR)+"]]");
System.out.println("new GregorianCalendar(1582, 11, 5) .getTime() -> Date:" + date);
System.out.println("proleptic_calendar_5Dec1582 in millis ["+proleptic.getTimeInMillis()+"], new GregorianCalendar(1582, 11, 5) in millis ["+calendar.getTimeInMillis()+"], millis are equal ["+ (proleptic.getTimeInMillis() == calendar.getTimeInMillis()) +"]");
//--------
Результат был:
proleptic_calendar_5Feb1582 [DAY_OF_MONTH [5], MONTH [1], YEAR [1582]
date_5Feb1582 from proleptic [Fri Jan 26 00:00:00 CET 1582]
new GregorianCalendar(1582, 1, 5) -> [DAY_OF_MONTH [5], MONTH [1], YEAR [1582]]
new GregorianCalendar(1582, 1, 5) .getTime() -> Date:Mon Feb 05 00:00:00 CET 1582
proleptic_calendar_5Feb1582 in millis [-12241069200000], new GregorianCalendar(1582, 1, 5) in millis [-12240205200000], millis are equal [false]
proleptic_calendar_8Oct1582 [DAY_OF_MONTH [8], MONTH [9], YEAR [1582]
date_5Oct1582 from proleptic [Fri Sep 28 00:00:00 CET 1582]
new GregorianCalendar(1582, 9, 8) -> [DAY_OF_MONTH [18], MONTH [9], YEAR [1582]]
new GregorianCalendar(1582, 9, 8) .getTime() -> Date:Mon Oct 18 00:00:00 CET 1582
proleptic_calendar_8Oct1582 in millis [-12219901200000], new GregorianCalendar(1582, 9, 8) in millis [-12219037200000], millis are equal [false]
proleptic_calendar_5Dec1582 [DAY_OF_MONTH [5], MONTH [11], YEAR [1582]
date_5Dec1582 from proleptic [Sun Dec 05 00:00:00 CET 1582]
new GregorianCalendar(1582, 11, 5) -> [DAY_OF_MONTH [5], MONTH [11], YEAR [1582]]
new GregorianCalendar(1582, 11, 5) .getTime() -> Date:Sun Dec 05 00:00:00 CET 1582
proleptic_calendar_5Dec1582 in millis [-12214890000000], new GregorianCalendar(1582, 11, 5) in millis [-12214890000000], millis are equal [true]
Первый тест (5 февраля 1582 г.) относится к периоду, принадлежащему юлианскому календарю, второй (8 октября 1582 г.) относится к переходному периоду, третий (5 декабря 1582 г.) - к периоду григорианского календаря. Тогда я думаю обратить внимание на следующие вещи:
Юлианский период
- Пролептический григорианский календарь, кажется, представляет желаемую дату
- полученная дата, как объяснил @Meno Hochschild, преобразуется в юлианскую дату (-10 дней)
- традиционный григорианский календарь также, кажется, представляет желаемую дату ...
- но полученная дата отличается от предыдущей
- Фактически, два григорианского календаря представляют два разных момента времени, см. значения миллисекунд
переходный период
- Пролептический григорианский календарь, кажется, представляет желаемую дату
- полученная дата снова конвертируется в юлианскую дату (-10 дней)
- традиционный григорианский календарь, по-видимому, является результатом преобразования в григорианском календаре даты (8 октября), первоначально выраженной в пролептическом юлианском календаре (8 октября = на 4 дня больше, чем по юлианскому календарю МАКСИМАЛЬНАЯ ДАТА (4 октября) = на 3 дня больше, чем МИН ДАТА по григорианскому календарю = 15 + 3 = 18 октября (это предположение)
- на этот раз полученная дата, кажется, представляет ту же дату из вышеупомянутого традиционного григорианского календаря (на этот раз без преобразования в юлианскую дату?)
- два григорианского календаря снова представляют два разных момента времени, см. значения миллисекунд
Григорианский период
- Пролептический григорианский календарь представляет желаемую дату
- полученная дата представляет ту же дату
- традиционный григорианский календарь представляет желаемую дату
- полученная дата представляет ту же дату
- два григорианского календаря представляют один и тот же момент времени, одинаковое количество миллисекунд
Не могли бы вы помочь мне по порядку объяснить все эти результаты?
Спасибо.