Подтвердить что ты не робот

Преобразование java.sql.Timestamp в java.util.Calendar без потери точности

Я пытаюсь получить значения timestamp из базы данных, конвертировать их в Календарь и преобразовывать их обратно в Timestamp, но они теряют свою точность.

Здесь код для воспроизведения проблемы

import java.sql.Timestamp;
import java.util.Calendar;

public class Test {
    public static void main(String[] args)
    {
        Timestamp timestamp = new Timestamp(112, 10, 5, 15, 39, 11, 801000000);
        System.out.println("BEFORE "+timestamp.toString());
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(timestamp.getTime());
        timestamp = new Timestamp(calendar.getTimeInMillis());
        System.out.println("AFTER "+timestamp.toString());
    }
}

Вот пример результата преобразования

BEFORE 2012-10-18 14:30:13.362001
AFTER 2012-10-18 14:30:13.362

Он теряет свою точность. Что я делаю, чтобы сохранить десятичное значение?

4b9b3361

Ответ 1

Вы устанавливаете время в миллисекундах, но ваша точность ввода находится в микросекундах, поэтому, конечно, вы потеряете любую точность мельче, чем миллисекунды.

Календарь не поддерживает более тонкую детализацию, чем миллисекунды. Нет работы.

Ответ 2

java.time

В Java 8 и более поздних версиях теперь есть решение: встроена новая инфраструктура java.time. Определяется JSR 310, вдохновленный Joda-Time, расширенный ThreeTen-Extra.

Эта новая структура имеет nanosecond разрешение. Этого достаточно, чтобы обрабатывать старые значения java.util.Date, значения Joda-Time, оба из которых миллисекунды. И этого достаточно для обработки микросекунд, используемых некоторыми базами данных, такими как Postgres. Некоторые базы данных, такие как H2, используют наносекунды. Таким образом, java.time может обрабатывать все это, или, по крайней мере, все основные ситуации. Единственными исключениями были бы нишевые научные или инженерные ситуации.

Image

С Java 8 старые классы получили новые методы для преобразования в/из java.time. На java.sql.Timestamp используйте новые методы toInstant и fromInstant. Класс Instant содержит количество наносекунд с эпохи, первый момент 1970 UTC (в основном, см. Документ класса для деталей).

Из Instant вы можете получить объект ZonedDateTime.

java.sql.Timestamp ts = myResultSet.getTimestamp( 1 );
Instant instant = ts.toInstant();
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( zoneId );