Часовой пояс игнорируется, когда я пытаюсь создать новую трансляцию

Я работаю с YouTube Live Streaming API. И у меня была проблема, каждый раз, когда я создаю прямую трансляцию и устанавливаю ее scheduledStartTime, установленный мной часовой пояс игнорируется. В ответ на запросы я получаю DateTime с часовым поясом 0.

И снова, когда я запрашиваю список предстоящих трансляций, я получаю трансляции с часовым поясом -0700. Неважно, в каком часовом поясе была эта трансляция, откуда был выполнен запрос — из мобильного клиента Android/iOS или через YouTube API explorer.

Вот как я форматирую дату:

String datePattern = "yyyy-MM-dd'T'HH:mm:ssZZZZZ";
DateFormat dateFormat = new SimpleDateFormat(datePattern);
dateFormat.setTimeZone(calendar.getTimeZone());

String dateFormatted = dateFormat.format(date); //2017-06-19T17:50:51+03:00

String iso8601Date = DateTime.parseRfc3339(dateFormatted);//2017-06-19T17:50:51.000+03:00

Возможно, проблема в моем шаблоне формата DateTime. Но это шаблон представления формата даты ISO 8601. И я запутался, почему мой часовой пояс игнорируется?


person yanni    schedule 12.06.2017    source источник


Ответы (1)


Старый API (с классами Calendar и SimpleDateFormat) устарел и имеет множество проблем< /а>.

Вам следует рассмотреть возможность использования более новых API. Если вы используете Java 8, рассмотрите возможность использования нового java. API времени. Это проще, меньше ошибок и менее подвержено ошибкам, чем старые API .

Если вы используете Java ‹= 7, вы можете использовать ThreeTen Backport, отличный бэкпорт для новых классов даты/времени Java 8. А для Android есть ThreeTenABP (подробнее о том, как его использовать здесь).

Код ниже работает для обоих. Единственная разница заключается в именах пакетов (в Java 8 — java.time, а в ThreeTen Backport (или ThreeTenABP для Android) — org.threeten.bp), но имена классов и методов одинаковы.

Если вы работаете с датами/временем, содержащими смещение, лучше всего использовать класс OffsetDateTime, который представляет дату и время со смещением. И у него уже есть метод парсинга String:

// parse a date string with offset -07:00
String strDate = "2017-06-19T17:50:51.000-07:00";
OffsetDateTime dt = OffsetDateTime.parse(strDate);
System.out.println(dt.toString()); // 2017-06-19T17:50:51-07:00

Вывод будет:

2017-06-19T17:50:51-07:00

Обратите внимание, что по умолчанию метод toString() не показывает доли секунд, потому что они равны нулю. Если вы хотите всегда показывать эти 3 цифры, вы можете использовать DateTimeFormatter:

// use a formatter to always print fraction-of-second with 3 digits
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ");
System.out.println(fmt.format(dt)); // 2017-06-19T17:50:51.000-07:00

В этом случае на выходе будет:

2017-06-19T17:50:51.000-07:00

Тестирование с разными смещениями:

// offset +03:00
dt = OffsetDateTime.parse("2017-06-19T17:50:51.000+03:00");
System.out.println(fmt.format(dt)); // 2017-06-19T17:50:51.000+03:00
// UTC: "Z" == offset zero (or "+00:00")
dt = OffsetDateTime.parse("2017-06-19T17:50:51.000Z");
System.out.println(fmt.format(dt)); // 2017-06-19T17:50:51.000Z
dt = OffsetDateTime.parse("2017-06-19T17:50:51.000+00:00");
System.out.println(fmt.format(dt)); // 2017-06-19T17:50:51.000Z

Если вам по-прежнему приходится использовать старый API (java.util.Calendar), вы можете легко преобразовать его в новые классы и обратно.

Если пакет java.time доступен, вы можете сделать:

// converting the OffsetDateTime to a Calendar
dt = OffsetDateTime.parse("2017-06-19T17:50:51.000Z");
Calendar c = Calendar.getInstance();
// setting the epoch milli to calendar
c.setTimeInMillis(dt.toInstant().toEpochMilli());

// converting Calendar back to OffsetDateTime (using UTC offset)
dt = OffsetDateTime.ofInstant(c.toInstant(), ZoneOffset.UTC);
// converting Calendar back to OffsetDateTime (using +03:00 offset)
dt = OffsetDateTime.ofInstant(c.toInstant(), ZoneOffset.ofHours(3));

Если вы используете ThreeTenABP, метод c.toInstant() будет недоступен. Но вы можете использовать класс org.threeten.bp.DateTimeUtils для его преобразования. Итак, вместо c.toInstant() можно использовать DateTimeUtils.toInstant(c):

// conversion for ThreeTenABP
// converting Calendar back to OffsetDateTime (using UTC offset)
dt = OffsetDateTime.ofInstant(DateTimeUtils.toInstant(c), ZoneOffset.UTC);
// converting Calendar back to OffsetDateTime (using +03:00 offset)
dt = OffsetDateTime.ofInstant(DateTimeUtils.toInstant(c), ZoneOffset.ofHours(3));

Обновление: API YouTube

Я проверил документацию по API YouTube (не уверен, что это то, что вы используете), и в примерах он устанавливает scheduledStartTime в дату/время в формате UTC:

broadcastSnippet.setScheduledStartTime(new DateTime("2024-01-30T00:00:00.000Z"));

Согласно документам, это поле имеет следующий формат:

Дата и время начала трансляции. Значение указывается в формате ISO 8601 (YYYY-MM-DDThh:mm:ss.sZ).

Итак, нам просто нужно создать средство форматирования, чтобы получить String в таком формате:

// your date/time, in -07:00 offset
String strDate = "2017-06-19T17:50:51.000-07:00";
OffsetDateTime odt = OffsetDateTime.parse(strDate);

// formatter
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX");
// convert to UTC
String utc = formatter.format(odt.withOffsetSameInstant(ZoneOffset.UTC));
System.out.println(utc); // 2017-06-20T00:50:51.000Z

Вывод будет в том же формате, что и в примере с YouTube:

2017-06-20T00:50:51.000Z

person Community    schedule 12.06.2017
comment
спасибо за ответ, но вы говорите мне, как анализировать дату, в результате я получу строку отформатированной даты и отправлю ее на сервер YouTube. Но эта строка выглядит нормально, проблема в том, почему YouTube игнорирует мою дату? И, конечно же, я могу отредактировать дату, полученную с YouTube, и установить для нее свой часовой пояс, но является ли это хорошей практикой? - person yanni; 13.06.2017
comment
Вы должны проверить, какой формат принимает YouTube (есть ли документация, объясняющая это? Я не знаю). Если бы вы могли предоставить более подробную информацию об этом, просто отредактируйте свой вопрос, чтобы добавить их (и я соответствующим образом обновлю свой ответ, если это необходимо). - person ; 13.06.2017
comment
@stiletto Я обновил ответ, посмотрим, поможет ли. Но я не уверен, что это то, что вам нужно, поэтому, если бы вы могли предоставить более подробную информацию о том, что вы используете в API Youtube, я был бы рад обновить свой ответ. - person ; 13.06.2017
comment
Хорошей и рекомендуемой практикой является всегда работать внутренне с UTC и преобразовывать в другой часовой пояс только тогда, когда требуется визуализация (например, когда она отображается пользователю, поэтому вы показываете дату/время в пользовательском часовой пояс, например). Но внутренне вы работаете с UTC, поэтому вы не портите свой код, постоянно выполняя ненужные преобразования. Это общее правило, но, конечно, оно зависит от каждого случая (хотя в API Youtube, кажется, он работает и с UTC). - person ; 13.06.2017