Странное поведение при ручном преобразовании java. sql .Timestamp в LocalDate - PullRequest
1 голос
/ 27 февраля 2020

Я создал небольшую функцию для преобразования TimeStamp в LocalDate и наткнулся на странное поведение. Вот код:

import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Test {

  private static void convert(long seconds) {
    System.out.printf("At %d seconds%n", seconds);
    Timestamp t = new Timestamp(seconds * 1000L);
    System.out.format("Timestamp: %s%n", t);
    Instant i = t.toInstant();
    System.out.format("Instant:   %s%n", i);
    ZonedDateTime atZone = i.atZone(ZoneId.systemDefault());
    System.out.format("at Zone:   %s%n", atZone);
    LocalDate localDate = atZone.toLocalDate();
    System.out.format("LocalDate: %s%n", localDate);
  }
}

Мой местный часовой пояс - Европа / Берлин. Теперь, вызывая это для Timestamp 0, я получаю правильный результат:

At 0 seconds
Timestamp: 1970-01-01 01:00:00.0
Instant:   1970-01-01T00:00:00Z
at Zone:   1970-01-01T01:00+01:00[Europe/Berlin]
LocalDate: 1970-01-01

Все как и ожидалось. Но когда я называю его датой 1-го года, мои ожидания не оправдываются:

At -62135769600 seconds
Timestamp: 0001-01-01 01:00:00.0
Instant:   0000-12-30T00:00:00Z
at Zone:   0000-12-30T00:53:28+00:53:28[Europe/Berlin]
LocalDate: 0000-12-30

Вопросы:

  1. Недостающий день после преобразование в Instant, так что кажется, что часовые пояса UT C и Европа / Берлин находились в один день с интервалом в один час в это время?
  2. При преобразовании Instant в мой часовой пояс, 6 минут и 32 секунды потерял где-то! Почему это так?
  3. Полученный LocalDate неверен. Какой надежный способ сделать преобразование?

Ответы [ 2 ]

1 голос
/ 01 марта 2020

Я столкнулся с этой проблемой, пытаясь переключиться с XMLGregorianCalendar на java .time.ZonedDateTime, и наша система зависела от 1-го года для представления «минимальной» даты. Ситуация становится очень странной, когда вы начинаете конвертировать даты до юлиано-григорианского перехода. например, Year 201 Year 200

Вот фрагмент кода Javado c, который намекает на то, что в первые годы дела идут немного смешно

GregorianCalendar реализует prolepti c Григорианский и юлианский календари. То есть даты вычисляются путем экстраполяции текущих правил на неопределенное время назад и вперед во времени. В результате GregorianCalendar может использоваться на все годы для получения значимых и последовательных результатов. Однако даты, полученные с использованием GregorianCalendar, исторически точны только с 1 марта 4 года нашей эры, когда были приняты современные правила юлианского календаря. До этой даты правила високосного года применялись нерегулярно, а до 45 B C юлианский календарь даже не существовал.

https://docs.oracle.com/javase/8/docs/api/java/util/GregorianCalendar.html

Если вы откроете источник GregorianCalendar, вы обнаружите еще одну прекрасную «заметку о реализации», которая предлагает еще больше сумасшествия в игре:

 * Likewise, with the Julian calendar, we assume a consistent
 * 4-year leap year rule, even though the historical pattern of
 * leap years is irregular, being every 3 years from 45 BCE
 * through 9 BCE, then every 4 years from 8 CE onwards, with no
 * leap years in-between.  Thus date computations and functions
 * such as isLeapYear() are not intended to be historically
 * accurate.

Я написал библиотеку преобразования дат, которая, как мне кажется, реализует преобразование между типами дат «ожидаемым» способом: https://github.com/beirtipol/date-converters. Я надеялся, что смогу обеспечить согласованное преобразование между java .util и java .time датами до 1582 года (юлианский-> григорианский сдвиг), но оно не завершено.

Чтобы ответить на часть вашего вопрос, я не уверен, что есть надежный способ сделать это без тестирования каждой даты и часового пояса до 1582 года. Я пытаюсь сделать это и отправлю ответ, если выясню, но впереди долгий путь испытаний!

Вот еще немного информации о радости римско-юлиано-григорианских сдвигов: https://www.timeanddate.com/calendar/julian-calendar.html

0 голосов
/ 27 февраля 2020

Кажется, проблема связана с тем, что ваш входной параметр преобразовывает функцию. «At -62135769600 секунд» показывает, что ваше входное значение превышает заданные длинные пределы. Ниже приведен тестовый вывод для входного значения, представляющего метку времени первого года (370 * 24 * 60 * 60).

At 31968000 seconds
Timestamp: 1971-01-06 01:00:00.0
Instant:   1971-01-06T00:00:00Z
at Zone:   1971-01-06T01:00+01:00[Europe/Berlin]
LocalDate: 1971-01-06
...