java.time или Joda-Time
Классы Date
и SimpleDateFormat
имеют проблемы с дизайном, поэтому не используйте их.Первая версия вашего вопроса была помечена jodatime, и если вы используете Joda-Time в своем проекте, это уже значительное улучшение.Joda-Time предоставляет вам всю необходимую функциональность, поэтому ваш метод, вероятно, должен возвращать тип запроса от Joda-Time, а не старомодный Date
.
Joda-Time также находится на пути к выходу на пенсию.Однако его преемником является java.time, современный Java-интерфейс даты и времени.Таким образом, последний вариант вы можете рассмотреть независимо от того, используете ли вы Joda-Time или нет.Поскольку ваша строка содержит смещение UTC, один из вариантов - вернуть OffsetDateTime
.Чтобы проверить метод, который делает это:
assertEquals(OffsetDateTime.of(1980, 3, 26, 0, 0, 0, 0, ZoneOffset.ofHours(2)),
DateUtils.getOffsetDateTimeFromString("1980-03-26T00:00:00.000+0200"));
Ваш пример и ваш код могут создать впечатление, что вы только после даты из строки и не заботитесь ни о времени дня, ни о смещении.Если это правильно, ваш метод может вернуть LocalDate
и быть протестирован следующим образом:
assertEquals(LocalDate.of(1980, Month.MARCH, 26),
DateUtils.getLocalDateFromString("1980-03-26T00:00:00.000+0200"));
Последний также освободит вас от всех соображений, связанных с часовым поясом.В обоих случаях обратите внимание, что я передаю объекты даты и времени в assertEquals
, а не в строки.
Ваш модульный тест правильный: ваш метод возвращает неправильное время
Ошибка, о которой вы сообщилив вашем вопросе было то, что хотя ожидаемый Date
от вашего метода был Wed Mar 26 00:00:00 PST 1980
, фактическое значение было Wed Mar 26 00:00:00 SGT 1980
.Это правильно, что они отличаются.Полночь в Нижней Калифорнии, Юконе, Вашингтоне, Неваде, Калифорнии и других местах, где наблюдается тихоокеанское время, отличается от полуночи в Китае.
Можно ли использовать java.time на Android?
Да, java.time прекрасно работает на старых и новых устройствах Android.Для этого требуется как минимум Java 6 .
- В Java 8 и более поздних версиях и на более новых устройствах Android (от уровня API 26) современный API поставляется встроенным.
- В Java 6 и 7 получают ThreeTen Backport, бэкпорт новых классов (ThreeTen для JSR 310; см. Ссылки внизу).
- На (более старых) Android используется версия ThreeTen для AndroidBackport.Это называется ThreeTenABP.И убедитесь, что вы импортируете классы даты и времени из
org.threeten.bp
с подпакетами.
Если вы не хотите, чтобы ваш код Android зависел от сторонней библиотеки, вы все равно можете использовать java.time в вашем модульном тесте.Чтобы протестировать метод, который возвращает старомодный Date
:
Instant expectedInstant = LocalDate.of(1980, Month.MARCH, 26)
.atStartOfDay(ZoneId.systemDefault())
.toInstant();
Date expectedDate = Date.from(expectedInstant);
Date actualDate = DateUtils.getDateFromString("1980-03-26T00:00:00.000+0200");
assertEquals(expectedDate, actualDate);
При использовании обратного порта (ThreeTen Backport и / или ThreeTenABP) преобразование из Instant
ot Date
происходит немного по-другому:
Date expectedDate = DateTimeUtil.toDate(expectedInstant);
Снова обратите внимание, что я сравниваю Date
объекты, а не строки.
Как установить часовой пояс для SimpleDateFormat?
Чтобы ответить на вопрос вВаш заголовок: используйте метод setTimeZone
:
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXX");
df.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); // Pacific Time
System.out.println(df.parseObject("1980-03-26T00:00:00.000+0200"));
В этом конкретном случае это не будет иметь никакого значения, поскольку смещение в строке анализируется и имеет приоритет над часовым поясомformatter.
Можно ли установить часовой пояс по умолчанию только для модульного тестирования?
Есть несколько вариантов.
TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
Поместить это в beforeClass
или before
метод вашего модульного теста установит часовой пояс вашей JVM в Pacific Time.Это не пуленепробиваемое, так как другой код может установить его на что-то другое до завершения теста, но вы можете контролировать, что этого не происходит.Обычно я бы не рекомендовал использовать устаревший класс TimeZone
.У него тоже есть проблемы с дизайном, но это естественный устаревший выбор, если тестируемые вами методы используют устаревший SimpleDateFormat
.Одна из проблем заключается в том, что она не сообщает, является ли переданная строка недействительной.Чтобы получить правильную проверку, просто пройдите современный класс:
TimeZone.setDefault(TimeZone.getTimeZone(ZoneId.of("America/Los_Angeles")));
Или используйте backport:
TimeZone.setDefault(DateTimeUtils.toTimeZone(ZoneId.of("America/Los_Angeles")));
Ссылки