Как исправить потерянное время на дату после преобразования?

Я хочу протестировать мой класс DateUtil и у меня появилась ошибка – после преобразования моей Date в String и возврата к дате я потерял около 900 секунд.

Это мой код:

  fun convertStringToDate() { // here I get current Date val currentDate = Date() // 1514285741928 // see apiDateFormatter declaration below this code val dateStr = apiDateFormatter.format(currentDate) // Tue, 26 Dec 2017 12:55:41 GMT+02:00 // see convertStringToDate() method declaration below this code val convertedDate = DateUtil.convertStringToDate(dateStr) // 1514285741000 assertEquals(currentDate == convertedDate, true) } 

apiDateFormatter

 val DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz" val apiDateFormatter = SimpleDateFormat(DATE_FORMAT, Locale.ENGLISH) 

DateUtil. convertStringToDate (dateStr)

 fun convertStringToDate(dateStr: String): Date { return apiDateFormatter.parse(dateStr) } 

Разница между currentDate и currentDate составляет около 900 секунд.

Почему и как это исправить ?

Две временные метки эпохи UNIX у вас на самом деле в миллисекундах , а не в секундах. Вот два значения:

 1514285741928 - before 1514285741000 - after 

Разница между двумя метками времени в 928 миллисекунд. Все, что произошло, это то, что миллисекундный компонент был усечен. Усечение произошло, когда вы применили маску точности даты на уровне секунд в этой строке:

 val dateStr = apiDateFormatter.format(currentDate) 

Чтобы обойти эту проблему, вы можете попробовать изменить маску SimpleDateFormat на миллисекунды:

 val DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss.SSS zzz" // ^^^ add this val apiDateFormatter = SimpleDateFormat(DATE_FORMAT, Locale.ENGLISH) 

Date() вернет текущее время в миллисекундах. Но когда вы конвертируете эти миллисекунды в dateString вы dateString миллисекундную часть. Таким образом, dateString не будет содержать миллисекундную часть. По этой причине, когда вы dateString в объект Date вы теряете часть миллисекунды или дробную часть секунд.

Предположим, что текущее время, возвращаемое Date() равно 1514287787103 . После преобразования в строку dateString будет храниться Tue, 26 Dec 2017 17:29:47 которая равна equivent 1514287787000 . Здесь вы потеряли несколько миллисекунд, что приводит к разнице.

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

val DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss.SSS"

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

(Синтаксис Java, а не Котлин)

ТЛ; др

 Instant.ofEpochMilli( 1_514_285_741_928L ) .atZone( ZoneId.of( "Pacific/Auckland" ) ) 

java.time

Как говорили другие, ваш счет с датой даты эпохи составляет миллисекунды, а не целые секунды.

Вы используете неприятные старые классы, которые теперь устарели современными классами java.time. Для старых Android см. Проекты ThreeTen- Backport и ThreeTenABP .

Классы java.time используют разрешение наносекунд, поэтому никаких проблем с вашими миллисекундами.

 Instant instant = Instant.ofEpochMilli( 1_514_285_741_928L ) ; 

Или захватите текущий момент в UTC.

 Instant instant = Instant.now() ; 

Чтобы увидеть этот момент в часовом поясе, а не в формате UTC, примените ZoneId для получения объекта ZonedDateTime . В тот же момент, та же точка в шкале времени, разное время настенных часов.

 ZoneId z = ZoneId.of( "America/Montreal" ) ; ZonedDateTime zdt = instant.atZone( z ) ; 

Совет. Вы используете ужасный формат в своем Вопросе. Для обмена значениями даты и времени в качестве текста используйте только стандартные форматы ISO 8601.