Зачем использовать Date с осторожностью

Java Android
Зачем использовать Date с осторожностью

предисловие

Как программист Java, особенно программист Android, который использует программирование Java7 круглый год, если в разработке участвуют дата, время и другие требования, большинство мелких партнеров должны учитыватьjava.util.Dateэтот класс. Например, чтобы напечатать текущее время -

Date date = new Date();// Date date = new Date(System.currentTimeMillis()); // 与上等价System.out.println(date);скопировать код

Это не кажется проблемой, поскольку, вероятно, большинство потребностей должно быть только здесь. Если текущим требованием является получение текущего года, месяца и дня, с2018-08-04(星期六)Пример -

Date date = new Date(System.currentTimeMillis());System.out.println(date.getYear() + "-" + date.getMonth() + "-" + date.getDay());скопировать код

Результат печати:

118-7-6скопировать код

Как программист, вы должны остро осознавать недружественность этого выходного значения.Нетрудно найти ответ из исходного кода или комментариев к дате - значение года представляет собой числовую разницу между текущим годом и 1900 (для эта точка Java относится к C ), месяц рассчитывается от 0 (это также относится к C), а значение текущего дня, которое я использую, равноgetDay(), его значение — день недели, на самом деле Date также обеспечиваетgetDate(), значением которого является день месяца. Такой запутанный дизайн API — это очень плохо!

Мало того, первым впечатлением от класса Date у разработчика должна быть дата, которая должна зафиксироватьгод месяц деньКласс , но упоминается в комментариях

The class Date represents a specific instant in time, with millisecond precision.

Это означает, что Date используется для записи «мгновения», а не просто для записи года, месяца и дня, и даже имеет точность на уровне миллисекунд, но в то же время класс Date не является окончательным, а это значит, что разработчики также могут проходятsetTime()Чтобы изменить «момент». В дополнение к этому разработчики могут даже создавать такие даты, как 32 января —new Date(2018, 0, 32), в распечатке будет указано, что сегодня 1 февраля --Fri Feb 01 00:00:00 CST 3918, Ява «Умный», чтобы помочь разработчикам исправить ошибки. Кроме того, даже если Дата используется как класс для записи "момент", он все равно безоговорочный.Согласно здравому смыслу, помимо записи года, месяца, дня, часа, минуты и секунды, измерение мгновения должно также записывать часовой пояс, но в объект Date не входит ключевой атрибут часового пояса, а только вtoString()Объект часового пояса новый в методе и распечатывается, что явно неразумно, например -

Разработчик в Пекине отправлял еженедельный отчет начальнику в Вашингтон. В этом еженедельном отчете использовался объект Date для записи даты создания еженедельного отчета. Начальник в Вашингтоне открыл недельный отчет рано утром, не почистив зубы, и, наконец, нашел дату внизу для Сб Авг 04 17:35:24PDT2018, поэтому он яростно спрашивал разработчиков в Пекине, почему ваш еженедельный отчет был создан в 17:35 (часовой пояс PDT) 4 августа, когда текущее время в США составляет 5:35 4 августа! Разработчики из далекого Китая посмотрели на дату еженедельной газеты и решительно написали внизу Sat Aug 04 17:35:24.CSTВ 2018 году это, очевидно, 17:35 4 августа по пекинскому времени (часовой пояс CST), почему он становится 17:35 4 августа по американскому времени, когда он прибывает в Соединенные Штаты? Ответ заключается вtoString()Часовой пояс в методе предназначен для получения часового пояса по умолчанию для текущей системы.В Пекине он должен быть в 17:35 4 августа по пекинскому времени, а в Вашингтоне он должен быть в 17:35 4 августа, Время США. Итак, проблема в том, что атрибут часового пояса не назначается при создании объекта и не может быть изменен позже.toString()Когда время для динамического создания, что вызвало вышеуказанное недоразумение.

Приведенный выше запутанный дизайн отстой!

Конечно, проницательные читатели, возможно, уже давно поняли, что в комментарии Date это уже упоминалось — использование класса java.util.Calendar для замены некоторых устаревших методов в Date. Да, еще в JDK 1.1 разработчики языка знали об этой проблеме и создали класс Calendar, чтобы компенсировать недостатки многих методов класса Date, но действительно ли Calendar решает проблему?

Календарь представляет собой календарь, но в нем есть метод получения часов, минут и секунд текущего года... Я думаю, этого достаточно, чтобы как можно скорее сделать Календарь @Deprecated, кроме того, месяцы Календаря также отсчитываются от 0 ; кроме этого Если разработчик хочет напечатать дату в соответствующем формате, он обнаружит, что JDK не предоставляет такого класса и может только преобразовать Calendar в Date, а затем использовать DateFormat для создания даты в указанном формате.

Этот дизайн тоже ужасен!

Тьяго Фернандес однажды организовал опрос на самый плохой Java API —

Вы можете видеть, что API даты занимает второе место...

Альтернативы в Java

before Java8

До Java 8 рекомендуется использовать ThreeTen-Backport или Joda Time, чтобы компенсировать недостатки обработки времени Java. Конечно, из-за популярности текущей версии JDK и новой обработки данных в Java8 версия Joda Time переписана в соответствии со спецификацией JSR-310, поэтому эти две библиотеки здесь не представлены.

after Java8

В ответ на вышеупомянутые дефекты Java8 предлагает рядjava.timeНовые классы в пакете используются для обработки операций, связанных с датами, таких как: LocalDate, LocalTime, LocalDateTime, ZonedDateTime и т. д. Важно отметить, что эти занятияimmutable and thread-safe, и назначьте обработку точек даты и времени каждому конкретному классу, чтобы он выполнял свою собственную роль, и больше не путайте разработчиков, потому что имя класса не соответствует фактической роли.

Например, класс LocalDate, который, как следует из названия, предоставляет только краткуюИнформация о годе, месяце, дне, без информации о часах, минутах и ​​секундах. Вы можете создавать экземпляры с LocalDate.of(год, месяц, день)/LocalDate.now() -

LocalDate date = LocalDate.of(2018, 08, 04);LocalDate date = LocalDate.now();скопировать код

Кроме того, LocalDate также предоставляет ряд известных API-интерфейсов:

LocalDate часто используемый API

запись, соответствующая этомуМинуты и секундыЭто класс LocalTime, который используется так же, как LocalDate. Конечно, чтобы облегчить разработку разработчикам, есть еще LocalDateTime, который на самом деле является комбинацией LocalDate и LocalTime, так что здесь нет никакого дополнительного расширения.

Как видно из комментариев к исходному коду, LocalDate/LocalTime/LocalDateTime не имеют отношения к часовому поясу, а значит не содержат никакой информации о часовом поясе.Если вы хотите, чтобы текущий класс был привязан к часовому поясу , следует использовать ZonedDateTime, реализация которого опирается на внутреннее хранилище объекта LocalDateTime и объекта часового пояса ZoneId.

Итак, по сравнению с исходным Date, какие оптимизации были сделаны в этих классах, чтобы разработчики были более склонны их использовать? Возьмите LocalDate в качестве примера:

1. final: Это означает, что класс не может быть унаследован, а неизменность объекта может быть гарантирована только путем управления выставленным API в этом классе.

2. Читабельность возвращаемого значения:

LocalDate date = LocalDate.now();System.out.println(date.getYear() + "-" + date.getMonth() + "-" + date.getDayOfMonth());скопировать код

2018-AUGUST-5

3. Четкие обязанности: LocalDate отвечает за год, месяц и день, LocalTime отвечает за часы, минуты и секунды, а ZonedDateTime хранит LocalDateTime, связанный с часовым поясом. разработчики не запутались.

4. Перестаньте быть самоуверенными, чтобы помочь разработчикам быть отказоустойчивыми:

LocalDate localDate = LocalDate.of(2018, 1, 32);System.out.println(localDate);скопировать код

Он выдаст исключение java.time.DateTimeException, сообщая разработчику, что значение должно находиться в диапазоне от 1 до 28/31.

В дополнение к классам, описанным выше,java.timeВ пакете также есть классы Duration, Period, Instant и другие, чтобы помочь разработчикам лучше обрабатывать информацию о дате.Например, Instant — это класс, созданный для «мгновенного», описанного выше, но автор меньше знакомится с этими классами в повседневной разработке. , поэтому здесь не делается никаких дополнительных уточнений.

Альтернативы в андроиде

Для Android-программистов операции после Java 8 такие же, как и описанные выше альтернативы в Java, но Java 8 не полностью соответствует вышеизложенному, потому что Threetenbp/Joda-Time использует пакеты jar для загрузки информации о часовом поясе.Эта эффективность в Android на самом деле не высок, поэтому JakeWharton создал библиотеку ThreeTenABP для адаптации к приложению Threetenbp / Joda-Time на Android, Принцип на самом деле очень прост, больше не используйте пакет jar для загрузки информации о часовом поясе, а поместив его в активы Файл TZDB.dat в папке, чтобы получить информацию о часовом поясе, чтобы было эффективнее работать на Android.

Примечание:Все даты, специально не упомянутые в этой статье, относятся к java.util.Date.