В большинстве случаев не следует преобразовывать точку во времени из одного строкового формата в одном часовом поясе в другой строковый формат в другом часовом поясе.В вашей программе храните дату и время в надлежащих объектах даты и времени, а не в строках (точно так же, как вы не будете хранить целочисленные значения или значения с плавающей точкой в строке).Если вам просто нужен момент времени (а не исходное смещение по Гринвичу, +05: 30), класс Instant
является правильным для использования.Когда ваша программа принимает строковый ввод, сначала проанализируйте и преобразуйте его в Instant
и сохраните как таковой.Только когда вам нужно передать строковый вывод, отформатируйте время обратно в строку и передайте его.
java.time и ThreeTenABP
Разбор и преобразование ввода
ZoneId originalZone = ZoneId.of("Asia/Kolkata");
Instant time = LocalDateTime.parse("2019-07-11T21:28:02.8469576")
.atZone(originalZone)
.toInstant();
System.out.println(time);
Преобразованное время печатается как:
2019-07-11T15: 58: 02.846957600Z
Для большинства целей не выделяйте времязона как голое смещение по Гринвичу.Именованный часовой пояс лучше объясняет читателю, почему эта зона была выбрана, и является более перспективной в случае изменения смещения (что происходит чаще, чем вы думаете).Я использую тот факт, что ваша строка в формате ISO 8601.В этом случае нам не нужно указывать явный форматер.Кстати, ваша строка примера имеет 7 десятичных знаков в секундах, а ваш oldDateFormat
, кажется, хочет 6. Здесь не имеет значения, поскольку LocalDateTime.parse
принимает все от 0 до 9 десятичных знаков.
Формат вывода
Требуемый вывод - это другой вариант ISO 8601. Приведенный выше вывод очень похож, потому что это тоже ISO 8601, только слишком много десятичных знаков.Итак, давайте применим явное форматирование на этот раз:
ZoneOffset newOffset = ZoneOffset.UTC;
DateTimeFormatter newFormatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral('T')
.appendPattern("HH:mm:ss.SSSX")
.toFormatter();
String formattedUtcDateTime = time.atOffset(newOffset).format(newFormatter);
System.out.println(formattedUtcDateTime);
2019-07-11T15: 58: 02.846Z
Мы видим, что java.time, современная JavaAPI даты и времени вынуждает нас указывать смещение часового пояса, поэтому забыть сделать это (как вы, похоже, сделали в коде вопроса, вызывая неожиданный вывод) просто невозможно.
Я рекомендую против SimpleDateFormat и TimeZone
Классы даты и времени, которые вы пытались использовать, SimpleDateFormat
и TimeZone
, плохо спроектированы и давно устарели, первые, в частности, печально известны своими проблемами.Также не может , чтобы SimpleDateFormat
мог правильно анализировать 6 или 7 десятичных знаков по секундам;он поддерживает только миллисекунды, ровно три знака после запятой.Вместо этого я использую java.time, современный Java-интерфейс даты и времени.Мне гораздо приятнее работать.
Вопрос: Могу ли я использовать 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
с подпакетами.
Ссылки