Discrepancy when converting ancient dates between java.util.Date and java.time.Instant
I have legacy code that uses java.util.Date creating an ancient date (30 Nov 0002). I'm trying to update what code I can, but that's necessitating converting between Date and LocalDate, etc. I can't completely get rid of the use of Date or the ancient date choice.
I'm finding what appears to be an error when converting back and forth between Date and Instant with this ancient date, and was hoping someone could explain what is going on.
Here's a sample:
Date date = new Date();
Instant instant = date.toInstant();
System.out.println("Current:");
System.out.println("Date: "+date);
System.out.println("Instant: "+instant);
System.out.println("Date epoch: "+date.getTime());
System.out.println("Instant epoch: "+instant.getEpochSecond()*1000);
System.out.println("nAncient from Date:");
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("MST"));
cal.set(2, Calendar.NOVEMBER, 30, 0, 0, 0);
date = cal.getTime();
instant = date.toInstant();
System.out.println("Date: "+date);
System.out.println("Instant: "+instant);
System.out.println("Date epoch: "+date.getTime());
System.out.println("Instant epoch: "+instant.getEpochSecond()*1000);
System.out.println("nAncient from Instant:");
instant = Instant.parse("0002-11-30T00:00:00Z");
date = Date.from(instant);
System.out.println("Date: "+date);
System.out.println("Instant: "+instant);
System.out.println("Date epoch: "+date.getTime());
System.out.println("Instant epoch: "+instant.getEpochSecond()*1000);
Which prints the following:
Current:
Date: Tue Sep 18 12:34:27 MST 2018
Instant: 2018-09-18T19:34:27.177Z
Date epoch: 1537299267177
Instant epoch: 1537299267000
Ancient from Date:
Date: Thu Nov 30 00:00:00 MST 2
Instant: 0002-11-28T07:00:00.247Z
Date epoch: -62075437199753
Instant epoch: -62075437200000
Ancient from Instant:
Date: Fri Dec 01 17:00:00 MST 2
Instant: 0002-11-30T00:00:00Z
Date epoch: -62075289600000
Instant epoch: -62075289600000
So if I create an Instant at 30 Nov 2, then convert to a Date, the Date is 1 Dec 2. If I start with a Date at 30 Nov 2, the Instant is 28 Nov 2. I'm aware that neither Date nor Instant store timezone information, but why are the epochs so different based on whether I started with a Date vs. an Instant? Is there anyway I can work around that? I need to be able to start with either a Date or an Instant, and end up with the same epoch value. It would also be nice to know why the default toString() shows such different dates given the same epoch.
java date java-8
add a comment |
I have legacy code that uses java.util.Date creating an ancient date (30 Nov 0002). I'm trying to update what code I can, but that's necessitating converting between Date and LocalDate, etc. I can't completely get rid of the use of Date or the ancient date choice.
I'm finding what appears to be an error when converting back and forth between Date and Instant with this ancient date, and was hoping someone could explain what is going on.
Here's a sample:
Date date = new Date();
Instant instant = date.toInstant();
System.out.println("Current:");
System.out.println("Date: "+date);
System.out.println("Instant: "+instant);
System.out.println("Date epoch: "+date.getTime());
System.out.println("Instant epoch: "+instant.getEpochSecond()*1000);
System.out.println("nAncient from Date:");
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("MST"));
cal.set(2, Calendar.NOVEMBER, 30, 0, 0, 0);
date = cal.getTime();
instant = date.toInstant();
System.out.println("Date: "+date);
System.out.println("Instant: "+instant);
System.out.println("Date epoch: "+date.getTime());
System.out.println("Instant epoch: "+instant.getEpochSecond()*1000);
System.out.println("nAncient from Instant:");
instant = Instant.parse("0002-11-30T00:00:00Z");
date = Date.from(instant);
System.out.println("Date: "+date);
System.out.println("Instant: "+instant);
System.out.println("Date epoch: "+date.getTime());
System.out.println("Instant epoch: "+instant.getEpochSecond()*1000);
Which prints the following:
Current:
Date: Tue Sep 18 12:34:27 MST 2018
Instant: 2018-09-18T19:34:27.177Z
Date epoch: 1537299267177
Instant epoch: 1537299267000
Ancient from Date:
Date: Thu Nov 30 00:00:00 MST 2
Instant: 0002-11-28T07:00:00.247Z
Date epoch: -62075437199753
Instant epoch: -62075437200000
Ancient from Instant:
Date: Fri Dec 01 17:00:00 MST 2
Instant: 0002-11-30T00:00:00Z
Date epoch: -62075289600000
Instant epoch: -62075289600000
So if I create an Instant at 30 Nov 2, then convert to a Date, the Date is 1 Dec 2. If I start with a Date at 30 Nov 2, the Instant is 28 Nov 2. I'm aware that neither Date nor Instant store timezone information, but why are the epochs so different based on whether I started with a Date vs. an Instant? Is there anyway I can work around that? I need to be able to start with either a Date or an Instant, and end up with the same epoch value. It would also be nice to know why the default toString() shows such different dates given the same epoch.
java date java-8
1
You've got a rounding error. Don't useinstant.getEpochSecond()*1000
, useinstant.toEpochMilli()
.
– teppic
Sep 18 '18 at 20:22
The two frameworks don’t agree 100 % about details as leap years this far back in history. So you will need to make your requirements clear. If you have aDate
a certain large number of days before the epoch, do you require anInstant
the same number of days before the epoch? Or if you got a date of 30 Nov 2, do you require anInstant
on 30 Nov 2? It’s not the same, sorry.
– Ole V.V.
Sep 18 '18 at 20:27
@teppic, thanks, I didn't notice that method there. For the purposes of the question, I didn't think the millisecond value mattered, although I can see how that muddies the example.
– Jeremy
Sep 18 '18 at 20:37
@OleV.V. The code I'm dealing with is using a magic date (let this be a lesson to you, kids), so I would like to have an instant and date go to the same 30 Nov 2 date, although I think I could make either of those options work. The trick is sometimes I'm starting with an Instant, and sometimes I'm starting with a Date. From your comment I take it that it's the leap years that's giving me grief...
– Jeremy
Sep 18 '18 at 20:37
add a comment |
I have legacy code that uses java.util.Date creating an ancient date (30 Nov 0002). I'm trying to update what code I can, but that's necessitating converting between Date and LocalDate, etc. I can't completely get rid of the use of Date or the ancient date choice.
I'm finding what appears to be an error when converting back and forth between Date and Instant with this ancient date, and was hoping someone could explain what is going on.
Here's a sample:
Date date = new Date();
Instant instant = date.toInstant();
System.out.println("Current:");
System.out.println("Date: "+date);
System.out.println("Instant: "+instant);
System.out.println("Date epoch: "+date.getTime());
System.out.println("Instant epoch: "+instant.getEpochSecond()*1000);
System.out.println("nAncient from Date:");
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("MST"));
cal.set(2, Calendar.NOVEMBER, 30, 0, 0, 0);
date = cal.getTime();
instant = date.toInstant();
System.out.println("Date: "+date);
System.out.println("Instant: "+instant);
System.out.println("Date epoch: "+date.getTime());
System.out.println("Instant epoch: "+instant.getEpochSecond()*1000);
System.out.println("nAncient from Instant:");
instant = Instant.parse("0002-11-30T00:00:00Z");
date = Date.from(instant);
System.out.println("Date: "+date);
System.out.println("Instant: "+instant);
System.out.println("Date epoch: "+date.getTime());
System.out.println("Instant epoch: "+instant.getEpochSecond()*1000);
Which prints the following:
Current:
Date: Tue Sep 18 12:34:27 MST 2018
Instant: 2018-09-18T19:34:27.177Z
Date epoch: 1537299267177
Instant epoch: 1537299267000
Ancient from Date:
Date: Thu Nov 30 00:00:00 MST 2
Instant: 0002-11-28T07:00:00.247Z
Date epoch: -62075437199753
Instant epoch: -62075437200000
Ancient from Instant:
Date: Fri Dec 01 17:00:00 MST 2
Instant: 0002-11-30T00:00:00Z
Date epoch: -62075289600000
Instant epoch: -62075289600000
So if I create an Instant at 30 Nov 2, then convert to a Date, the Date is 1 Dec 2. If I start with a Date at 30 Nov 2, the Instant is 28 Nov 2. I'm aware that neither Date nor Instant store timezone information, but why are the epochs so different based on whether I started with a Date vs. an Instant? Is there anyway I can work around that? I need to be able to start with either a Date or an Instant, and end up with the same epoch value. It would also be nice to know why the default toString() shows such different dates given the same epoch.
java date java-8
I have legacy code that uses java.util.Date creating an ancient date (30 Nov 0002). I'm trying to update what code I can, but that's necessitating converting between Date and LocalDate, etc. I can't completely get rid of the use of Date or the ancient date choice.
I'm finding what appears to be an error when converting back and forth between Date and Instant with this ancient date, and was hoping someone could explain what is going on.
Here's a sample:
Date date = new Date();
Instant instant = date.toInstant();
System.out.println("Current:");
System.out.println("Date: "+date);
System.out.println("Instant: "+instant);
System.out.println("Date epoch: "+date.getTime());
System.out.println("Instant epoch: "+instant.getEpochSecond()*1000);
System.out.println("nAncient from Date:");
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("MST"));
cal.set(2, Calendar.NOVEMBER, 30, 0, 0, 0);
date = cal.getTime();
instant = date.toInstant();
System.out.println("Date: "+date);
System.out.println("Instant: "+instant);
System.out.println("Date epoch: "+date.getTime());
System.out.println("Instant epoch: "+instant.getEpochSecond()*1000);
System.out.println("nAncient from Instant:");
instant = Instant.parse("0002-11-30T00:00:00Z");
date = Date.from(instant);
System.out.println("Date: "+date);
System.out.println("Instant: "+instant);
System.out.println("Date epoch: "+date.getTime());
System.out.println("Instant epoch: "+instant.getEpochSecond()*1000);
Which prints the following:
Current:
Date: Tue Sep 18 12:34:27 MST 2018
Instant: 2018-09-18T19:34:27.177Z
Date epoch: 1537299267177
Instant epoch: 1537299267000
Ancient from Date:
Date: Thu Nov 30 00:00:00 MST 2
Instant: 0002-11-28T07:00:00.247Z
Date epoch: -62075437199753
Instant epoch: -62075437200000
Ancient from Instant:
Date: Fri Dec 01 17:00:00 MST 2
Instant: 0002-11-30T00:00:00Z
Date epoch: -62075289600000
Instant epoch: -62075289600000
So if I create an Instant at 30 Nov 2, then convert to a Date, the Date is 1 Dec 2. If I start with a Date at 30 Nov 2, the Instant is 28 Nov 2. I'm aware that neither Date nor Instant store timezone information, but why are the epochs so different based on whether I started with a Date vs. an Instant? Is there anyway I can work around that? I need to be able to start with either a Date or an Instant, and end up with the same epoch value. It would also be nice to know why the default toString() shows such different dates given the same epoch.
java date java-8
java date java-8
edited Sep 18 '18 at 21:32
Stefan Zobel
2,44031828
2,44031828
asked Sep 18 '18 at 19:47
JeremyJeremy
6353818
6353818
1
You've got a rounding error. Don't useinstant.getEpochSecond()*1000
, useinstant.toEpochMilli()
.
– teppic
Sep 18 '18 at 20:22
The two frameworks don’t agree 100 % about details as leap years this far back in history. So you will need to make your requirements clear. If you have aDate
a certain large number of days before the epoch, do you require anInstant
the same number of days before the epoch? Or if you got a date of 30 Nov 2, do you require anInstant
on 30 Nov 2? It’s not the same, sorry.
– Ole V.V.
Sep 18 '18 at 20:27
@teppic, thanks, I didn't notice that method there. For the purposes of the question, I didn't think the millisecond value mattered, although I can see how that muddies the example.
– Jeremy
Sep 18 '18 at 20:37
@OleV.V. The code I'm dealing with is using a magic date (let this be a lesson to you, kids), so I would like to have an instant and date go to the same 30 Nov 2 date, although I think I could make either of those options work. The trick is sometimes I'm starting with an Instant, and sometimes I'm starting with a Date. From your comment I take it that it's the leap years that's giving me grief...
– Jeremy
Sep 18 '18 at 20:37
add a comment |
1
You've got a rounding error. Don't useinstant.getEpochSecond()*1000
, useinstant.toEpochMilli()
.
– teppic
Sep 18 '18 at 20:22
The two frameworks don’t agree 100 % about details as leap years this far back in history. So you will need to make your requirements clear. If you have aDate
a certain large number of days before the epoch, do you require anInstant
the same number of days before the epoch? Or if you got a date of 30 Nov 2, do you require anInstant
on 30 Nov 2? It’s not the same, sorry.
– Ole V.V.
Sep 18 '18 at 20:27
@teppic, thanks, I didn't notice that method there. For the purposes of the question, I didn't think the millisecond value mattered, although I can see how that muddies the example.
– Jeremy
Sep 18 '18 at 20:37
@OleV.V. The code I'm dealing with is using a magic date (let this be a lesson to you, kids), so I would like to have an instant and date go to the same 30 Nov 2 date, although I think I could make either of those options work. The trick is sometimes I'm starting with an Instant, and sometimes I'm starting with a Date. From your comment I take it that it's the leap years that's giving me grief...
– Jeremy
Sep 18 '18 at 20:37
1
1
You've got a rounding error. Don't use
instant.getEpochSecond()*1000
, use instant.toEpochMilli()
.– teppic
Sep 18 '18 at 20:22
You've got a rounding error. Don't use
instant.getEpochSecond()*1000
, use instant.toEpochMilli()
.– teppic
Sep 18 '18 at 20:22
The two frameworks don’t agree 100 % about details as leap years this far back in history. So you will need to make your requirements clear. If you have a
Date
a certain large number of days before the epoch, do you require an Instant
the same number of days before the epoch? Or if you got a date of 30 Nov 2, do you require an Instant
on 30 Nov 2? It’s not the same, sorry.– Ole V.V.
Sep 18 '18 at 20:27
The two frameworks don’t agree 100 % about details as leap years this far back in history. So you will need to make your requirements clear. If you have a
Date
a certain large number of days before the epoch, do you require an Instant
the same number of days before the epoch? Or if you got a date of 30 Nov 2, do you require an Instant
on 30 Nov 2? It’s not the same, sorry.– Ole V.V.
Sep 18 '18 at 20:27
@teppic, thanks, I didn't notice that method there. For the purposes of the question, I didn't think the millisecond value mattered, although I can see how that muddies the example.
– Jeremy
Sep 18 '18 at 20:37
@teppic, thanks, I didn't notice that method there. For the purposes of the question, I didn't think the millisecond value mattered, although I can see how that muddies the example.
– Jeremy
Sep 18 '18 at 20:37
@OleV.V. The code I'm dealing with is using a magic date (let this be a lesson to you, kids), so I would like to have an instant and date go to the same 30 Nov 2 date, although I think I could make either of those options work. The trick is sometimes I'm starting with an Instant, and sometimes I'm starting with a Date. From your comment I take it that it's the leap years that's giving me grief...
– Jeremy
Sep 18 '18 at 20:37
@OleV.V. The code I'm dealing with is using a magic date (let this be a lesson to you, kids), so I would like to have an instant and date go to the same 30 Nov 2 date, although I think I could make either of those options work. The trick is sometimes I'm starting with an Instant, and sometimes I'm starting with a Date. From your comment I take it that it's the leap years that's giving me grief...
– Jeremy
Sep 18 '18 at 20:37
add a comment |
1 Answer
1
active
oldest
votes
The discrepancy resides in how the implementations of Date
and Instant
interact with each other in relation to their implementations, with Date using Gregorian/Julian calendars and Instant using ISO standard for Date, which follow a modified Gregorian calendar prior to the Julian calendar switchover.
The GregorianCalendar
implementation has a special note:
Before the Gregorian cutover, GregorianCalendar implements the Julian calendar. The only difference between the Gregorian and the Julian calendar is the leap year rule. The Julian calendar specifies leap years every four years, whereas the Gregorian calendar omits century years which are not divisible by 400.
Well, yes, technically speaking. But for this issue, we don't quite encounter this.
cal.set(1582, Calendar.OCTOBER, 4, 0, 0, 0);
This yields a date, as expected, of October 4, 1582.
cal.set(1582, Calendar.OCTOBER, 5, 0, 0, 0);
This yields a date, of October 15, 1582.
WHAT MAGIC IS THIS, BATMAN?
Well, this isn't a coding error, it's actually an implementation of GregorianCalendar.
However, this year saw the beginning of the Gregorian Calendar switch, when the Papal bull known as Inter gravissimas introduced the Gregorian calendar, adopted by Spain, Portugal, the Polish–Lithuanian Commonwealth and most of present-day Italy from the start. In these countries, the year continued as normal until Thursday, October 4. However, the next day became Friday, October 15 (like a common year starting on Friday),
From Wikipedia on 1582
When we examine October 4, 1582, the following happens:
Date: 1582-Oct-04 00:00:00
Instant: 1582-10-14T00:00:00Z
There is a 10-day gap here, and the reason the instant exists on a "technically non-existent date" is accounted for by the definition of ISO instant dates.
The standard states that every date must be consecutive, so usage of the Julian calendar would be contrary to the standard (because at the switchover date, the dates would not be consecutive).
SO, whereas October 14, 1582 never existed in reality, it exists in ISO time by definition, but occurs on the real world's October 4, 1582 according to Julian Calendar.
Due to what I assume are additional leap year drifts from the first paragraph, where Julian centuries 1500, 1400, 1300, 1100, 1000, 900, 700, 600, 500, 300, 200, 100 have extra leap days not accounted for in the Gregorian calendar, we slowly shift back from a +10 to a -1 offset. This can be verified by adjusting the year in +100 increments.
If you are displaying historical event dates, you will be better off using a Date
or JulianCalendar
DateFormatter to display the correct correct historical date, as it actually occurred in history. Printing out the ISO time for historical periods may appear nonsensical or inaccurate, but storing the time in this format is still valid.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52393619%2fdiscrepancy-when-converting-ancient-dates-between-java-util-date-and-java-time-i%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
The discrepancy resides in how the implementations of Date
and Instant
interact with each other in relation to their implementations, with Date using Gregorian/Julian calendars and Instant using ISO standard for Date, which follow a modified Gregorian calendar prior to the Julian calendar switchover.
The GregorianCalendar
implementation has a special note:
Before the Gregorian cutover, GregorianCalendar implements the Julian calendar. The only difference between the Gregorian and the Julian calendar is the leap year rule. The Julian calendar specifies leap years every four years, whereas the Gregorian calendar omits century years which are not divisible by 400.
Well, yes, technically speaking. But for this issue, we don't quite encounter this.
cal.set(1582, Calendar.OCTOBER, 4, 0, 0, 0);
This yields a date, as expected, of October 4, 1582.
cal.set(1582, Calendar.OCTOBER, 5, 0, 0, 0);
This yields a date, of October 15, 1582.
WHAT MAGIC IS THIS, BATMAN?
Well, this isn't a coding error, it's actually an implementation of GregorianCalendar.
However, this year saw the beginning of the Gregorian Calendar switch, when the Papal bull known as Inter gravissimas introduced the Gregorian calendar, adopted by Spain, Portugal, the Polish–Lithuanian Commonwealth and most of present-day Italy from the start. In these countries, the year continued as normal until Thursday, October 4. However, the next day became Friday, October 15 (like a common year starting on Friday),
From Wikipedia on 1582
When we examine October 4, 1582, the following happens:
Date: 1582-Oct-04 00:00:00
Instant: 1582-10-14T00:00:00Z
There is a 10-day gap here, and the reason the instant exists on a "technically non-existent date" is accounted for by the definition of ISO instant dates.
The standard states that every date must be consecutive, so usage of the Julian calendar would be contrary to the standard (because at the switchover date, the dates would not be consecutive).
SO, whereas October 14, 1582 never existed in reality, it exists in ISO time by definition, but occurs on the real world's October 4, 1582 according to Julian Calendar.
Due to what I assume are additional leap year drifts from the first paragraph, where Julian centuries 1500, 1400, 1300, 1100, 1000, 900, 700, 600, 500, 300, 200, 100 have extra leap days not accounted for in the Gregorian calendar, we slowly shift back from a +10 to a -1 offset. This can be verified by adjusting the year in +100 increments.
If you are displaying historical event dates, you will be better off using a Date
or JulianCalendar
DateFormatter to display the correct correct historical date, as it actually occurred in history. Printing out the ISO time for historical periods may appear nonsensical or inaccurate, but storing the time in this format is still valid.
add a comment |
The discrepancy resides in how the implementations of Date
and Instant
interact with each other in relation to their implementations, with Date using Gregorian/Julian calendars and Instant using ISO standard for Date, which follow a modified Gregorian calendar prior to the Julian calendar switchover.
The GregorianCalendar
implementation has a special note:
Before the Gregorian cutover, GregorianCalendar implements the Julian calendar. The only difference between the Gregorian and the Julian calendar is the leap year rule. The Julian calendar specifies leap years every four years, whereas the Gregorian calendar omits century years which are not divisible by 400.
Well, yes, technically speaking. But for this issue, we don't quite encounter this.
cal.set(1582, Calendar.OCTOBER, 4, 0, 0, 0);
This yields a date, as expected, of October 4, 1582.
cal.set(1582, Calendar.OCTOBER, 5, 0, 0, 0);
This yields a date, of October 15, 1582.
WHAT MAGIC IS THIS, BATMAN?
Well, this isn't a coding error, it's actually an implementation of GregorianCalendar.
However, this year saw the beginning of the Gregorian Calendar switch, when the Papal bull known as Inter gravissimas introduced the Gregorian calendar, adopted by Spain, Portugal, the Polish–Lithuanian Commonwealth and most of present-day Italy from the start. In these countries, the year continued as normal until Thursday, October 4. However, the next day became Friday, October 15 (like a common year starting on Friday),
From Wikipedia on 1582
When we examine October 4, 1582, the following happens:
Date: 1582-Oct-04 00:00:00
Instant: 1582-10-14T00:00:00Z
There is a 10-day gap here, and the reason the instant exists on a "technically non-existent date" is accounted for by the definition of ISO instant dates.
The standard states that every date must be consecutive, so usage of the Julian calendar would be contrary to the standard (because at the switchover date, the dates would not be consecutive).
SO, whereas October 14, 1582 never existed in reality, it exists in ISO time by definition, but occurs on the real world's October 4, 1582 according to Julian Calendar.
Due to what I assume are additional leap year drifts from the first paragraph, where Julian centuries 1500, 1400, 1300, 1100, 1000, 900, 700, 600, 500, 300, 200, 100 have extra leap days not accounted for in the Gregorian calendar, we slowly shift back from a +10 to a -1 offset. This can be verified by adjusting the year in +100 increments.
If you are displaying historical event dates, you will be better off using a Date
or JulianCalendar
DateFormatter to display the correct correct historical date, as it actually occurred in history. Printing out the ISO time for historical periods may appear nonsensical or inaccurate, but storing the time in this format is still valid.
add a comment |
The discrepancy resides in how the implementations of Date
and Instant
interact with each other in relation to their implementations, with Date using Gregorian/Julian calendars and Instant using ISO standard for Date, which follow a modified Gregorian calendar prior to the Julian calendar switchover.
The GregorianCalendar
implementation has a special note:
Before the Gregorian cutover, GregorianCalendar implements the Julian calendar. The only difference between the Gregorian and the Julian calendar is the leap year rule. The Julian calendar specifies leap years every four years, whereas the Gregorian calendar omits century years which are not divisible by 400.
Well, yes, technically speaking. But for this issue, we don't quite encounter this.
cal.set(1582, Calendar.OCTOBER, 4, 0, 0, 0);
This yields a date, as expected, of October 4, 1582.
cal.set(1582, Calendar.OCTOBER, 5, 0, 0, 0);
This yields a date, of October 15, 1582.
WHAT MAGIC IS THIS, BATMAN?
Well, this isn't a coding error, it's actually an implementation of GregorianCalendar.
However, this year saw the beginning of the Gregorian Calendar switch, when the Papal bull known as Inter gravissimas introduced the Gregorian calendar, adopted by Spain, Portugal, the Polish–Lithuanian Commonwealth and most of present-day Italy from the start. In these countries, the year continued as normal until Thursday, October 4. However, the next day became Friday, October 15 (like a common year starting on Friday),
From Wikipedia on 1582
When we examine October 4, 1582, the following happens:
Date: 1582-Oct-04 00:00:00
Instant: 1582-10-14T00:00:00Z
There is a 10-day gap here, and the reason the instant exists on a "technically non-existent date" is accounted for by the definition of ISO instant dates.
The standard states that every date must be consecutive, so usage of the Julian calendar would be contrary to the standard (because at the switchover date, the dates would not be consecutive).
SO, whereas October 14, 1582 never existed in reality, it exists in ISO time by definition, but occurs on the real world's October 4, 1582 according to Julian Calendar.
Due to what I assume are additional leap year drifts from the first paragraph, where Julian centuries 1500, 1400, 1300, 1100, 1000, 900, 700, 600, 500, 300, 200, 100 have extra leap days not accounted for in the Gregorian calendar, we slowly shift back from a +10 to a -1 offset. This can be verified by adjusting the year in +100 increments.
If you are displaying historical event dates, you will be better off using a Date
or JulianCalendar
DateFormatter to display the correct correct historical date, as it actually occurred in history. Printing out the ISO time for historical periods may appear nonsensical or inaccurate, but storing the time in this format is still valid.
The discrepancy resides in how the implementations of Date
and Instant
interact with each other in relation to their implementations, with Date using Gregorian/Julian calendars and Instant using ISO standard for Date, which follow a modified Gregorian calendar prior to the Julian calendar switchover.
The GregorianCalendar
implementation has a special note:
Before the Gregorian cutover, GregorianCalendar implements the Julian calendar. The only difference between the Gregorian and the Julian calendar is the leap year rule. The Julian calendar specifies leap years every four years, whereas the Gregorian calendar omits century years which are not divisible by 400.
Well, yes, technically speaking. But for this issue, we don't quite encounter this.
cal.set(1582, Calendar.OCTOBER, 4, 0, 0, 0);
This yields a date, as expected, of October 4, 1582.
cal.set(1582, Calendar.OCTOBER, 5, 0, 0, 0);
This yields a date, of October 15, 1582.
WHAT MAGIC IS THIS, BATMAN?
Well, this isn't a coding error, it's actually an implementation of GregorianCalendar.
However, this year saw the beginning of the Gregorian Calendar switch, when the Papal bull known as Inter gravissimas introduced the Gregorian calendar, adopted by Spain, Portugal, the Polish–Lithuanian Commonwealth and most of present-day Italy from the start. In these countries, the year continued as normal until Thursday, October 4. However, the next day became Friday, October 15 (like a common year starting on Friday),
From Wikipedia on 1582
When we examine October 4, 1582, the following happens:
Date: 1582-Oct-04 00:00:00
Instant: 1582-10-14T00:00:00Z
There is a 10-day gap here, and the reason the instant exists on a "technically non-existent date" is accounted for by the definition of ISO instant dates.
The standard states that every date must be consecutive, so usage of the Julian calendar would be contrary to the standard (because at the switchover date, the dates would not be consecutive).
SO, whereas October 14, 1582 never existed in reality, it exists in ISO time by definition, but occurs on the real world's October 4, 1582 according to Julian Calendar.
Due to what I assume are additional leap year drifts from the first paragraph, where Julian centuries 1500, 1400, 1300, 1100, 1000, 900, 700, 600, 500, 300, 200, 100 have extra leap days not accounted for in the Gregorian calendar, we slowly shift back from a +10 to a -1 offset. This can be verified by adjusting the year in +100 increments.
If you are displaying historical event dates, you will be better off using a Date
or JulianCalendar
DateFormatter to display the correct correct historical date, as it actually occurred in history. Printing out the ISO time for historical periods may appear nonsensical or inaccurate, but storing the time in this format is still valid.
edited Nov 20 '18 at 14:32
answered Sep 18 '18 at 21:02
CompassCompass
4,60442338
4,60442338
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52393619%2fdiscrepancy-when-converting-ancient-dates-between-java-util-date-and-java-time-i%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
You've got a rounding error. Don't use
instant.getEpochSecond()*1000
, useinstant.toEpochMilli()
.– teppic
Sep 18 '18 at 20:22
The two frameworks don’t agree 100 % about details as leap years this far back in history. So you will need to make your requirements clear. If you have a
Date
a certain large number of days before the epoch, do you require anInstant
the same number of days before the epoch? Or if you got a date of 30 Nov 2, do you require anInstant
on 30 Nov 2? It’s not the same, sorry.– Ole V.V.
Sep 18 '18 at 20:27
@teppic, thanks, I didn't notice that method there. For the purposes of the question, I didn't think the millisecond value mattered, although I can see how that muddies the example.
– Jeremy
Sep 18 '18 at 20:37
@OleV.V. The code I'm dealing with is using a magic date (let this be a lesson to you, kids), so I would like to have an instant and date go to the same 30 Nov 2 date, although I think I could make either of those options work. The trick is sometimes I'm starting with an Instant, and sometimes I'm starting with a Date. From your comment I take it that it's the leap years that's giving me grief...
– Jeremy
Sep 18 '18 at 20:37