Java-календарь 'getTimeInMillis ()' заставляет все поля 'isSet' быть истинными - PullRequest
0 голосов
/ 02 января 2019

Меня очень смущает следующее неожиданное поведение Java Calendar

Calendar calendar = Calendar.getInstance();
calendar.clear();
//System.out(calendar.getTimeInMillis());
calendar.setLenient(false);
calendar.set(Calendar.YEAR, year);

Если я вызываю getTimeInMillis () после 'clear ()', все поля isSet (), которые были ложными после очистки() стать реальностью.Что я делаю неправильно?Если это правильное поведение (которое кажется очень странным), есть ли способ остановить его?

Ответы [ 4 ]

0 голосов
/ 31 марта 2019

Поскольку я не мог использовать пакет java.time (он не поддерживается в версиях Android, которые мне нужно поддерживать) и сторонние пакеты, мне пришлось создать свой собственный класс на основе календаря, где я должен был самостоятельно отслеживатьчто установлено, а что нет.Мне нужно было сохранить эту информацию, чтобы выразить метки времени в ресурсах HL7 FHIR с правильной точностью времени.Раздражение и боль, но она делает то, что мне нужно.

0 голосов
/ 02 января 2019

Обычно не следует использовать Calendar или Date, так как они изменчивы, а некоторые методы API непредсказуемы (например, снисходительны по умолчанию).java.time - лучший выбор в современной кодовой базе.

Согласно Calendar.isSet() javadoc

Определяет, имеет ли заданное поле календаря значение, включая случаи, когда значение былоустанавливаемые внутренними полями вычисления, инициируемые вызовом метода get.

Calendar.getTimeInMillis() может устанавливать позицию календаря на текущее время, однако это может зависеть от версии Java.При использовании OpenJDK 11.0.1 ниже код печатает только false, поэтому поля getTmeInMillis() не устанавливаются:

Calendar cal = Calendar.getInstance();
cal.clear();
IntStream.range(0, 17).mapToObj(cal::isSet).forEach(System.out::println);
cal.getTimeInMillis();
IntStream.range(0, 17).mapToObj(cal::isSet).forEach(System.out::println);

Однако замена cal.getTimeInMillis() на cal.get(Calendar.YEAR) приведет к печати всех true во второмIntStream.

0 голосов
/ 02 января 2019

tl; dr

Никогда не используйте ужасный Calendar класс.

Используйте современные java.time классы.Эти неизменяемые объекты полностью исключают проблемы, которые вы обнаружили.

ZonedDateTime                   // Represent a moment using the wall-clock time used by the people of a particular region (a time zone).
.now(                           // Capture the current moment.
    ZoneId.systemDefault()      // Get the JVM’s current default time zone. Beware: This can change at any moment during runtime. If crucial, confirm with user.
)                               // Returns a `ZonedDateTime` object.
.withYear(                      // Per the immutable objects pattern, produce another object based on the original’s values but with a change.
    2001                        // Change the year, but copy the month, day-of-month, hour, minute, second, fractional second, and time zone all the same. If the time-of-day is not valid on that date in the other year, auto-adjust per algorithm documented in the JavaDoc.
)                               // Returns another `ZonedDateTime` object.

java.time

Ужасный класс Calendar устарел, его давно вытеснили современные java.time классы.

Чтобы зафиксировать текущий момент в UTC, используйте Instant.

Instant instant = Instant.now();

С этого Instant вы можете получить количество миллисекунд с той же привязки эпохи, что и Calendar:первый момент 1970 года в UTC, 1970-01-01T00: 00: 00Z.Остерегайтесь потери данных, поскольку разрешение Instant составляет наносекунды, намного меньше, чем миллисекунды, используемые в устаревших классах даты и времени, таких как Calendar.

long millisecondsSinceEpoch = instant.toEpochMilli() ;

Вы можете создать Instant из этого числа.

Instant instant = Instant.ofEpochMilli( millisecondsSinceEpoch) ;

Чтобы увидеть этот момент через часы настенного времени, используемые людьми определенного региона, применитечасовой пояс (ZoneId) для получения объекта ZonedDateTime.

ZoneId z = ZoneId.of( "America/Montreal" ) // Or your JVM’s current default, ZoneId.systemDefault().
ZonedDateTime zdt = instant.atZone( z ) ;

Чтобы изменить год, как вы делали это в вопросе, позвоните по номеру withYear.

ZonedDateTime zdtOtherYear = zdt.withYear( 2001 ) ;

О 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 SE 11 и более поздние версии - часть стандартного Java API с связанной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и JavaSE 7
    • Большая часть функций java.time перенесена в Java 6 & 7 в ThreeTen-Backport .
  • Android
    • Более поздние версии пакетов Android для реализации java.time классы.
    • Для более ранних версий Android (<26) проект <a href="https://github.com/JakeWharton/ThreeTenABP" rel="nofollow noreferrer"> ThreeTenABP адаптируется ThreeTen-Backport (упомянуто выше).См. Как использовать ThreeTenABP… .

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

0 голосов
/ 02 января 2019

In относится к Calendar javadoc :

Получение и настройка значений полей календаря

Значения полей календаря можно установить, вызвав методы set.Любые значения полей, установленные в Календаре, не будут интерпретироваться до тех пор, пока ему не понадобится рассчитать значение времени (в миллисекундах с начала эпохи) или значения полей календаря.Вызов get, getTimeInMillis, getTime, add и roll включает такие вычисления.

При вызове calendar.getTimeInMillis() устанавливаются значения.Это правильное поведение, и вы не можете его остановить.Как упоминал Джо, вам следует переключиться на пакет java.time, если это возможно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...