1

I'm working with YouTube Live Streaming API. And I had a problem, every time I create live broadcast and set its scheduledStartTime, the timezone I set is ignored. In requests response I receive DateTime with 0 timezone.

And again when I requesting list of upcoming broadcasts I receive broadcasts with timezone -0700. No matter which timezone was on this broadcast, no matter from where request was executed - from Android/iOS mobile client, or via YouTube API explorer.

That is how I format my date:

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

Maybe, problem is with my DateTime format pattern. But that is pattern of ISO 8601 date format representation. And I'm confused, why my timezone is ignored?

yanni
  • 56
  • 6

1 Answers1

0

The old API (with Calendar and SimpleDateFormat classes) is outdated and has lots of problems.

You should consider using the newer API's. If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.

If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it here).

The code below works for both. The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.

If you're working with dates/times that contains an offset, the best choice is to use the OffsetDateTime class, which represents a date and time with an offset. And it already has a method to parse a 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

The output will be:

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

Note that by default, the toString() method didn't show the fraction-of-seconds, because they're zero. If you want to always show these 3 digits, you can use a 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

In this case, the output will be:

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

Testing with different offsets:

// 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

If you still have to use the old API (java.util.Calendar), you can easily convert it to and from the new classes.

If the java.time package is available, you can do:

// 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));

If you're using ThreeTenABP, the method c.toInstant() won't be available. But you can use org.threeten.bp.DateTimeUtils class to convert it. So, instead of c.toInstant() you can use 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));

Update: Youtube API

I checked at Youtube API documentation (not sure if that's what you're using) and in the examples it sets the scheduledStartTime to a date/time in UTC:

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

According to the docs, this field has the following format:

The date and time that the broadcast is scheduled to start. The value is specified in ISO 8601 (YYYY-MM-DDThh:mm:ss.sZ) format.

So, we just need to create a formatter to get the String in this format:

// 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

The output will be in the same format used in youtube's example:

2017-06-20T00:50:51.000Z

Community
  • 1
  • 1
  • thank you for the answer, but you're telling me how to parse date, as result I'll get string of formatted date and sent in to YouTube server. But this string looks ok, the problem is why YouTube ignore my date? And, of course, I can edit date I receive from YouTube and set my timezone on it, but is it a good practice? – yanni Jun 13 '17 at 13:32
  • 1
    You must check what format youtube accepts (is there a documentation explaining this? I don't know). If you could provide more details about it, just edit your question to add them (and I'll update my answer accordingly, if necessary). –  Jun 13 '17 at 13:38
  • @stiletto I've updated the answer, see if it helps. But I'm not sure if that's what you need, so if you could please provide more details about what you're using in Youtube API, then I'd be happy to update my answer. –  Jun 13 '17 at 13:48
  • 1
    A good and recommended practice is to always work **internally** with UTC, and convert to another timezone just when a visualization is needed (like when it's displayed to an user, so you show the date/time in the user's timezone, for example). But internally you're working with UTC, so you don't mess your code doing unnecessary conversions all the time. That's a general rule, but of course it depends on each case (though in Youtube's API, it seems to work with UTC as well). –  Jun 13 '17 at 13:56