Расхождение во времени сохранения 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
- Более поздние версии Android связывают реализации классов java.time.
- Для более ранних версий Android (<26) проект ThreeTenABP адаптирует ThreeTen-Backport (упомянутый выше). Смотрите Как использовать ThreeTenABP….
Проект 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");
^^^^