java.time и ThreeTenABP
Я хотел бы внести современный ответ: используйте java.time, современный API даты и времени Java для вашей работы с датами. Если разрабатываете для Android API level 25 и ниже, то через бэкпорт для Android, ThreeTenABP (ссылка внизу).
LocalDate eDate = LocalDate.now(ZoneId.of("Europe/Paris"));
LocalDate sDate = eDate.minusDays(127);
long daysBetween = ChronoUnit.DAYS.between(sDate, eDate);
System.out.println(daysBetween);
Когда я запустил этот код сегодня, результат был ожидаемым:
127
Обратите внимание, что код не только короче, но и всего одна строка для поиска разницы; это также яснее и естественнее для чтения. Классы Date
и Calendar
, которые вы использовали, плохо спроектированы и давно устарели. Я рекомендую вам не использовать их.
Что пошло не так в вашем коде?
У вас int
переполнение при преобразовании 127 дней в миллисекунды. В математике 127 * 24 * 3600 * 1000 равно 10 972 800 000. Поскольку числа, которые вы умножаете, равны int
, Java выполняет умножение в int
, а наибольшее число, которое может содержать int
, равно 2 147 483 647, что далеко не достаточно для ожидаемого результат. В этой ситуации было бы неплохо, если бы Java выдал исключение или каким-то другим образом сообщил нам об ошибке. Это не так. Он неявно отбрасывает старшие биты, что дает нам результат -1 912 101 888. Вычитание этого отрицательного числа из текущего времени эквивалентно добавлению 22 дней и нескольких часов. Это объясняет, почему вы получили 22. Забавно, что было опубликовано 13 ответов, и кажется, что никто этого не заметил…
Однако даже при выполнении умножения с использованием типа long
127 дней по-прежнему вычисляются неправильно. Если 127 дней пересекают переход на летнее время (DST) или обратно, что во Франции имеет место в течение 254 из 365 дней в году, днем перехода будет не 24 часа, а либо 23, либо 25 часов. Что вызывает неправильное количество миллисекунд.
Вы всегда должны оставлять математику дат проверенным библиотечным методам. Никогда не кодируйте его самостоятельно. Это сложнее, чем думает большинство из нас, поэтому высок риск сделать это неправильно.
Вопрос: Разве для java.time не требуется Android API уровня 26?
java.time прекрасно работает как на старых, так и на новых устройствах Android. Просто требуется как минимум Java 6.
- В Java 8 и более поздних версиях, а также на более новых устройствах Android (начиная с уровня API 26) современный API встроен.
- В не-Android Java 6 и 7 получите ThreeTen Backport, бэкпорт современных классов (ThreeTen для JSR 310; см. ссылки внизу).
- На (старом) Android используйте версию ThreeTen Backport для Android. Он называется ThreeTenABP. И убедитесь, что вы импортируете классы даты и времени из
org.threeten.bp
с подпакетами.
Ссылки
person
Ole V.V.
schedule
14.03.2020
dateEvent
? - person keyser   schedule 27.04.2014dateEvent
объявлен сprivate long dateEvent = 0L;
. Я также пытался заменитьDAY_OF_MONTH
наDAY_OF_YEAR
, но это не решило проблему. - person Manitoba   schedule 27.04.2014Calendar
плохо разработан и давно устарел, поэтому не используйте его. С java.time не только намного приятнее работать, в отличие отCalendar
, у него есть прямая поддержка для определения количества дней между двумя датами. - person Ole V.V.   schedule 06.04.2020