Расхождение во времени сохранения Java в миллисекундах

Я пытаюсь использовать mongodb для извлечения некоторых записей с полями даты, примеры записей показаны ниже, и хочу преобразовать поле даты, которое было проанализировано с помощью jayway jsonpath, в java.util.Date long integer. длинное целое число не соответствует исходному. Пожалуйста помоги.

Образцы записей в коллекции тестеров:

{
    "_id" : ObjectId("5b3fe6f91e618afb473dc644"),
    "dateField" : ISODate("2018-07-06T15:46:55.819Z")
}

Код Java для получения записей с использованием jongo выглядит следующим образом:

List<Tester> list=  jongo.runCommand("{aggregate : 'tester',pipeline:[],cursor : {batchSize :10}}")
          .field("cursor")
          .as(Tester.class);

for(Tester t : list)
{
    System.out.println("dateField test: : : : "+t.getDateField()+" : : : : "+t.getDateField().getTime());

    // Output is perfectly fine : dateField test: : : : Fri Jul 06 21:16:55 IST 2018 : : : : 1530892015819


    Gson gson = new Gson();
    String str = gson.toJson(t);
    DocumentContext docCtx = JsonPath.parse(str);
    JsonPath jsonPath = JsonPath.compile("$.dateField");
    Object obj = docCtx.read(jsonPath);

    System.out.println(obj);
    //After parsing with jsonPath the date is retained - Jul 6, 2018 9:16:55 PM
    SimpleDateFormat format = new SimpleDateFormat("MMM dd, yyyy hh:mm:ss aaa");
    Date d = format.parse(obj.toString());
    System.out.println(d + " : : : " + d.getTime());
    //Fri Jul 06 21:16:55 IST 2018 : : : 1530892015000 - Time is not retained       
}

Ожидается: t.getDateField(). GetTime() ==== d.getTime()

Пожалуйста помоги

С уважением

Kris

2 ответа

ТЛ; др

  • В вашем шаблоне форматирования пропущены доли секунды, поэтому в выводе не отображаются миллисекунды.
  • Вы используете устаревшие классы даты и времени. Вместо этого используйте java.time.

Пример:

Instant                                 // Represent a moment in UTC, with a resolution as fine as nanoseconds.
.parse( "2018-07-06T15:46:55.819Z" )    // Parse a string in standard ISO 8601 format. The `Z` on the end means UTC, pronounced “Zulu”.
.atZone( ZoneId.of( "Asia/Kolkata" ) )  // Adjust from UTC to a desired time zone. Same moment, same point on the timeline, different wall-clock time. Returns a `ZonedDateTime` object.
.toString()                             // Generate a String in standard ISO 8601 format. Represents the moment in our `ZonedDateTime` object.

Преобразовать из наследия java.util.Date класс к современному java.time.Instant и обратно. Пример бессмысленного кода:

java.util.Date.from(            // Convert from modern `Instant` to legacy `Date`. 
    myJavaUtilDate.toInstant()  // Convert from legacy `Date` to modern `Instant`.
)

java.time

Вы используете ужасно хлопотные старые классы даты и времени: Date & SimpleDateFormat, Они были вытеснены несколько лет назад современными классами java.time.

Ваш вклад 2018-07-06T15:46:55.819Z в стандартном формате ISO 8601. Классы java.time по умолчанию используют форматы ISO 8601 при разборе или генерации строк. Поэтому нет необходимости указывать шаблон форматирования.

Z на конце произносится Zulu и означает UTC. Instant класс представляет момент в UTC.

Instant instant = Instant.parse( "2018-07-06T15:46:55.819Z" ) ; 

Сгенерируйте выходную строку в формате ISO 8601.

String output = instant.toString() ;

2018-07-06T15: 46: 55.819Z

Ваш код игнорирует критическую проблему часового пояса. Вместо того, чтобы неявно полагаться на текущий часовой пояс JVM по умолчанию, укажите явно ZoneId даже если это ZoneId.systemDefault(),

Укажите правильное название часового пояса в формате continent/region, такие как America/Montreal, Africa/Casablanca, или же Pacific/Auckland, Никогда не используйте 3-4 буквенное сокращение, такое как EST или же IST поскольку они не являются истинными часовыми поясами, не стандартизированы и даже не уникальны (!). Например, ваш IST может означать ирландское стандартное время, стандартное время Индии, стандартное время Ирана или что-то еще.

После перехода от UTC к определенному часовому поясу у нас остается тот же момент, та же точка на временной шкале. Только время настенных часов отличается.

ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;  // Or `ZoneId.systemDefault()`.
ZonedDateTime zdt = instant.atZone( z ) ; // Adjust from UTC to a specific time zone. 

Сгенерируйте выходную строку в формате ISO 8601, расширенном для добавления имени часового пояса в квадратных скобках.

String output = zdt.toString() ;

2018-07-06T21: 16: 55,819+05:30[Азия / Калькутта]

Обратите внимание, что ваша дробная секунда (миллисекунды) все еще не повреждена.

преобразование

Возможно, вы должны взаимодействовать с java.util.Date (ваш вопрос не ясен), поскольку старый код еще не обновлен для поддержки java.time.

Вы найдете удобные методы преобразования, новые методы добавлены к старым классам.

Исходя из java.util.Date в java.time.Instant,

Instant myInstant = myJavaUtilDate.toInstant() ;

Действуйте, как показано выше. Настройте нужный часовой пояс и сгенерируйте String,

Идя в другом направлении, от современного Instant класс в унаследованный класс Date,

java.util.Date myDate = java.util.Date.from( myInstant ) ;

Неизменные предметы

Классы java.time разрабатываются так, чтобы быть потокобезопасными и использовать шаблон неизменяемых объектов. Обратите внимание, как приведенный выше код создает свежие объекты на основе значений оригинала, а не изменяет ("мутирует") оригинал.


О java.time

Инфраструктура java.time встроена в Java 8 и более поздние версии. Эти классы вытесняют проблемные старые классы даты и времени, такие как java.util.Date, Calendar & SimpleDateFormat,

Проект Joda-Time, находящийся сейчас в режиме обслуживания, рекомендует перейти на классы java.time.

Чтобы узнать больше, смотрите Oracle Tutorial. И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310.

Вы можете обмениваться объектами java.time напрямую с вашей базой данных. Используйте драйвер JDBC, соответствующий JDBC 4.2 или более поздней версии. Нет необходимости в строках, нет необходимости в java.sql.* классы.

Где взять классы java.time?

  • Java SE 8, Java SE 9, Java SE 10 и более поздние версии
    • Встроенный.
    • Часть стандартного Java API со встроенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и Java SE 7
    • Большая часть функциональности java.time перенесена на Java 6 и 7 в ThreeTen-Backport.
  • Android

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Вы можете найти некоторые полезные классы здесь, такие как Interval, YearWeek, YearQuarter и многое другое.

new SimpleDateFormat("MMM dd, yyyy hh:mm:ss aaa");

Вы отбрасываете часть ввода в миллисекундах, что приводит именно к той разнице, которую вы видите. Используйте это вместо:

new SimpleDateFormat("MMM dd, yyyy hh:mm:ss.SSS aaa");
                                           ^^^^
Другие вопросы по тегам