Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
532 views
in Technique[技术] by (71.8m points)

Cannot Convert Date '0001-01-01' from Java to C# correctly

I try to provide a tool to convert datetime from Java to C#. But there is a serious problem.

In Java, I read '0001-01-01' from the SQL Server database via java.sql.Date, and get the millisecond -62135798400000.

I also consider the timezone offset.

private static long getMilliSecondWithoutTimeZone(long origin) {
    return origin + (ZonedDateTime.now().getOffset().getLong(OFFSET_SECONDS) * 1000);
}

And the final millisecond is -62135769600000.

In C#, I use this millisecond to new Datetime

var ticks = new DateTime(1970, 1, 1).Ticks + (-62135769600000 * 10000);
var date = new DateTime(ticks);

When the code runs, it will throw the exception:

System.ArgumentOutOfRangeException: 'Ticks must be between DateTime.MinValue.Ticks and DateTime.MaxValue.Ticks. (Parameter 'ticks')'

However, the conversion is correct after '1600-01-01' according to my test.
Before '1600-01-01', there always is a few days of error.

It makes me very confused.


I find the remarks in https://docs.microsoft.com/en-us/dotnet/api/system.globalization.juliancalendar?view=net-5.0#remarks

The Gregorian calendar was developed as a replacement for the Julian calendar (which is represented by the JulianCalendar class) and was first introduced in a small number of cultures on October 15, 1582. When working with historic dates that precede a culture's adoption of the Gregorian calendar, you should use the original calendar if it is available in the .NET Framework. For example, Denmark changed from the Julian calendar to the Gregorian calendar on February 19 (in the Julian calendar) or March 1 (in the Gregorian calendar) of 1700. In this case, for dates before the adoption of the Gregorian calendar, you should use the Julian calendar. However, note that no culture offers intrinsic support for the JulianCalendar class. You must use the JulianCalendar class as a standalone calendar. For more information, see Working with calendars.

The actual reason is:

  • C# uses the Gregorian calendar all the time.
  • Java uses the Gregorian calendar after October 15, 1582, and uses the Julian calendar before.

The solution:

import java.sql.Date;
import java.time.chrono.IsoChronology;
import java.time.*;

public class Test {
    public static Long getMilliSeconds(Date date) {
        if (null == date) {
            return null;
        }
        IsoChronology ISO = IsoChronology.INSTANCE;
        LocalDate ld = date.toLocalDate();
        return ISO.localDateTime(LocalDateTime.of(ld.getYear(), ld.getMonth(), ld.getDayOfMonth(), 0, 0, 0)).toInstant(ZoneOffset.UTC).toEpochMilli();
    }
}
question from:https://stackoverflow.com/questions/65930964/cannot-convert-date-0001-01-01-from-java-to-c-sharp-correctly

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

It seems like the millisecond value that you mention, -62_135_798_400_000, comes out of an old-fashioned java.sql.Date object created in a timezone that is assumed to be at UTC offset +08:00 back then, perhaps just Etc/GMT-8. With this assumption, the value is historically correct since it was the Julian calendar that was used back then, and Date does use that.

I don’t know the .NET classes that C# uses, but I consider it a likely that a few days error are caused by them using the proleptic Gregorian calendar, that is, pretending that the Gregorian calendar was used in all past even though it didn’t come into existence before 1582. The modern Java date and time API does this and therefore gives you millisecond values that usually differ by a few days.

    long milliseconds = LocalDate.of(1, 1, 1)
            .atStartOfDay(ZoneOffset.ofHours(8))
            .toInstant()
            .toEpochMilli();
    System.out.format(Locale.ENGLISH, "%,d%n", milliseconds);

Output:

-62,135,625,600,000

It is 48 hours — or 2 days — later than the time you mentioned. See if it solves your issue.

Link

Oracle tutorial: Date Time explaining how to use java.time.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...