Почему getMonth устарел на java. sql .Date и java .util.Date - PullRequest
2 голосов
/ 09 июля 2020

Я должен предварять это тем, что использую Apache Spark, который использует java.sql.Date, на случай, если кто-то предложит мне использовать даты из java.time. Пример ниже находится в Scala.

API, который я использую (который устарел) для получения месяца для даты, выглядит следующим образом:

val date: java.sql.Date = ???
val month = date.getMonth()

Однако, если я посмотрю на как кажется, я должен сделать это на основе устаревания, приведенный выше код будет переписан следующим образом:

val date: java.sql.Date = ???
val cal = Calendar.getInstance()
cal.setTime(date)
cal.get(Calendar.MONTH)

Простота и удобочитаемость кода значительно отличаются, а дата является побочным эффектом в календаре не очень-то хорошо с точки зрения функционального программирования. Может кто-нибудь объяснить, почему они думают, что это изменение было внесено?

Ответы [ 2 ]

5 голосов
/ 09 июля 2020

До JDK 1.1 класс Date имел две дополнительные функции. Это позволило интерпретировать даты как значения года, месяца, дня, часа, минуты и секунды. Это также позволило форматировать и анализировать строки даты. К сожалению, API для этих функций не поддавался интернационализации . Начиная с JDK 1.1, класс Calendar должен использоваться для преобразования между полями даты и времени, а класс DateFormat должен использоваться для форматирования и анализа строк даты. Соответствующие методы в Date устарели.

Объясняет JavaDo c. Интернационализация.

" на случай, если кто-то предложит использовать даты из java.time"

Нет ничего, что могло бы помешать вам как можно скорее преобразовать в классы java.time, выполняя любые вычисления. / модификации, которые вам нужны, и, если вам нужно повторно вставить, преобразование обратно в java.sql.Date снова.

2 голосов
/ 09 июля 2020
    val date: java.sql.Date = ???
    val month = date.toLocalDate().getMonthValue()

Вы сами это сказали, и я все еще думаю: вам следует использовать java .time, современный Java API даты и времени. Когда вы получаете старомодный java.sql.Date из устаревшего API, еще не обновленного до java .time, преобразуйте его в современный LocalDate и наслаждайтесь написанием естественного кода с java .time.

Почему были объявлены устаревшими getMonth () и другие методы getXxx?

Хотя Майкл уже ответил на вопрос относительно java.util.Date, мне есть что добавить, когда дело доходит до java.sql.Date. Для этого класса ситуация несколько хуже, чем то, о чем сообщил Майкл.

Что осталось нерекомендованным (оцененным?) Из java.util.Date после устаревания, так это то, что Date - это момент времени. С другой стороны, java.sql.Date никогда не должен был быть моментом во времени. Один из способов проиллюстрировать этот факт состоит в том, что его метод toInstant, который должен преобразовать его в Instant, момент времени, безоговорочно выдает UnsupportedOperationException. java.sql.Date должен был быть календарной датой, которая будет использоваться с базой данных SQL и ее типом данных date, который в большинстве случаев также является датой, определяемой годом, месяцем и днем ​​месяца. Поскольку Date больше не является годом, месяцем и днем ​​месяца, они практически устарели все, что java.sql.Date должно было быть . И они не дали нам замену, пока с JDB C 4.2 мы не сможем обменивать LocalDate объектов с SQL базами данных.

Наблюдения, которые приводят к устареванию, имеют очень практические последствия. Давайте попробуем это (в Java, потому что это то, что я могу написать):

void foo(java.sql.Date sqlDate) {
    System.out.println(sqlDate);
    TimeZone.setDefault(TimeZone.getTimeZone(ZoneId.of("Pacific/Samoa")));
    System.out.println(sqlDate.getMonth());
}

За один вызов напечатанный метод:

2020-11-02
9

Итак, мы был 2-й день 11-го месяца, а месяц печатался как 9? Происходят две вещи:

  1. Как ни странно, номер месяца, который возвращает getMonth(), отсчитывается от 0, поэтому 9 означает октябрь.
  2. Date внутренне представлено как количество миллисекунд с начала эпохи до начала дня в часовом поясе JVM по умолчанию. 2020-11-02 00:00:00 в моем исходном часовом поясе (для этой демонстрации установлен Тихий океан / Киритимати) - это тот же момент времени, что и 23:00:00 31.10.2020 в Самоа. Таким образом, мы получаем октябрь.

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

  • Часовой пояс JVM по умолчанию можно изменить из любой части вашей программы и из любой другой программы, работающей в той же JVM.
  • date может быть сериализован в программе, запущенной в одной JVM, и десериализован в другой JVM с другой настройкой часового пояса.

Кстати, первый фрагмент, который я представил вверху, часто не помогает против неожиданных результатов в этих ситуациях. Если что-то go сбилось с пути до того, как вы преобразовали из java.sql.Date в LocalDate, преобразование также даст вам неправильную дату. Если вы можете это сделать, конвертируйте в LocalDate , прежде чем кто-нибудь испортит настройку часового пояса JVM, и будьте осторожны.

...