2

Using moment.js library on my Node JS server:

moment().utc().format("YYYY-MM-DD HH:mm:ss.SSS")

I got the current time string as:

2017-08-02 11:57:52.616Z

On Android, I used the below code.

Date myDate = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
calendar.setTime(myDate);
Date time = calendar.getTime();
SimpleDateFormat outputFmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
String dateAsString = outputFmt.format(time);

And the output was:

2017-08-02 22:58:46.163Z

How can I fix this? Difference seems to be around 11 hours.

LEE
  • 3,335
  • 8
  • 40
  • 70
  • Do you happen to be in a time zone that is 11 hours off of UTC? – Ben P. Aug 02 '17 at 18:08
  • India. It's +5:30 – LEE Aug 02 '17 at 18:39
  • 1
    I can't really help you here, because I am not familiar with the intricacies of `Calendar` and `Date`. What I _can_ tell you is that the _reason_ I'm not familiar with them is that they are notoriously bad APIs. If you have the ability, I highly recommend using Joda Time (http://www.joda.org/joda-time/), JSR-310 (http://www.threeten.org/), or Java 8's `java.time` package (https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html) – Ben P. Aug 02 '17 at 18:42
  • 1
    As a taste of what's so bad about `Calendar` and `Date`, I can tell you that `calendar.setTimeZone()` has no effect on the `Date` object returned by `calendar.getTime()`. – Ben P. Aug 02 '17 at 18:43
  • What's the result of `myDate.getTime()`? –  Aug 02 '17 at 19:08
  • @BenP. Joda-Time is in maintainance mode and being replaced by the new API's. Even in [joda's website](http://www.joda.org/joda-time) it says: **"Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310)."**. And I'm not sure if `java.time` is already available in Android, so in this case I guess [ThreeTen Backport](http://www.threeten.org/threetenbp) is the best option. –  Aug 02 '17 at 19:12

1 Answers1

1

If you want the current date in UTC, you must set the timezone on the SimpleDateFormat, not on the Calendar. And you don't need to create a Calendar, you can use a Date directly:

SimpleDateFormat outputFmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
outputFmt.setTimeZone(TimeZone.getTimeZone("UTC"));
String dateAsString = outputFmt.format(new Date()); // current date/time

The X pattern above was introduced in JDK 7, so if you are using JDK <= 6, you'll have to put a literal Z:

SimpleDateFormat outputFmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
outputFmt.setTimeZone(TimeZone.getTimeZone("UTC"));
String dateAsString = outputFmt.format(new Date());

Try with X first, as it's preferrable to output the correct timezone instead of a hardcoded Z (because if you change the timezone to another one, the Z will be wrong, because it's used only when the date/time is in UTC).


The old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, and they're being replaced by the new APIs.

For Android, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. You'll also need the ThreeTenABP to make it work (more on how to use it here).

If you want the current date in UTC, you can use the org.threeten.bp.Instant class (which represents an UTC instant):

String dateAsString = Instant.now().toString();

The dateAsString variable will have a value like 2017-08-02T19:21:22.271Z.


If you are working just with UTC values, the Instant class is enough. But if you want to work with another timezones, you must use a org.threeten.bp.ZonedDateTime:

// current time in UTC
dateAsString = ZonedDateTime.now(ZoneOffset.UTC).toString();

// current time in another timezone
dateAsString = ZonedDateTime.now(ZoneId.of("Asia/Kolkata")).toString();

The second case will produce a different output (such as 2017-08-03T01:05:06.631+05:30[Asia/Kolkata]) because it's using a timezone that's not UTC. You can change it, though, by using a org.threeten.bp.format.DateTimeFormatter:

DateTimeFormatter fmt = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
dateAsString = ZonedDateTime.now(ZoneId.of("Asia/Kolkata")).format(fmt);

This will result in 2017-08-03T01:06:19.131+05:30. You can also create another formats with DateTimeFormatter.ofPattern("pattern"), replacing pattern by the corresponding pattern letters (check the javadoc for more details).

Note that he API uses IANA timezones names (always in the format Region/City, like Asia/Kolkata or Europe/Berlin). Avoid using the 3-letter abbreviations (like CST or IST) because they are ambiguous and not standard.

You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds().

You can also use the system's default timezone with ZoneId.systemDefault(), but this can be changed without notice, even at runtime, so it's better to explicity use a specific one.