How to Convert Utc Timestamp to Device Local Time in Android

Convert UTC into Local Time on Android

Here's my attempt:

String dateStr = "Jul 16, 2013 12:08:59 AM";
SimpleDateFormat df = new SimpleDateFormat("MMM dd, yyyy HH:mm:ss a", Locale.ENGLISH);
df.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = df.parse(dateStr);
df.setTimeZone(TimeZone.getDefault());
String formattedDate = df.format(date);

Also notice the "a" for the am/pm marker...

How to convert UTC timestamp to device local time in android

The code in your example looks fine at first glance. BTW, if the server timestamp is in UTC (i.e. it's an epoch timestamp) then you should not have to apply the current timezone offset. In other words if the server timestamp is in UTC then you can simply get the difference between the server timestamp and the system time (System.currentTimeMillis()) as the system time is in UTC (epoch).

I would check that the timestamp coming from your server is what you expect. If the timestamp from the server does not convert into the date you expect (in the local timezone) then the difference between the timestamp and the current system time will not be what you expect.

Use Calendar to get the current timezone. Initialize a SimpleDateFormatter with the current timezone; then log the server timestamp and verify if it's the date you expect:

Calendar cal = Calendar.getInstance();
TimeZone tz = cal.getTimeZone();

/* debug: is it local time? */
Log.d("Time zone: ", tz.getDisplayName());

/* date formatter in local timezone */
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
sdf.setTimeZone(tz);

/* print your timestamp and double check it's the date you expect */
long timestamp = cursor.getLong(columnIndex);
String localTime = sdf.format(new Date(timestamp * 1000)); // I assume your timestamp is in seconds and you're converting to milliseconds?
Log.d("Time: ", localTime);

If the server time that is printed is not what you expect then your server time is not in UTC.

If the server time that is printed is the date that you expect then you should not have to apply the rawoffset to it. So your code would be simpler (minus all the debug logging):

long timestamp = cursor.getLong(columnIndex);
Log.d("Server time: ", timestamp);

/* log the device timezone */
Calendar cal = Calendar.getInstance();
TimeZone tz = cal.getTimeZone();
Log.d("Time zone: ", tz.getDisplayName());

/* log the system time */
Log.d("System time: ", System.currentTimeMillis());

CharSequence relTime = DateUtils.getRelativeTimeSpanString(
timestamp * 1000,
System.currentTimeMillis(),
DateUtils.MINUTE_IN_MILLIS);

((TextView) view).setText(relTime);

Convert UTC date to Local Time in Android?

Good you found a solution with SimpleDateFormat. I'd just like to add more insights about it (basically because the old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, and they're being replaced by the new APIs).

The input String (2017-09-16T05:06:18.157) contains only the date (year/month/day) and time (hour/minute/second/millisecond), but no timezone information. So, when calling parseDateTime, Joda-Time just assumes that it's in the JVM default timezone.

If you know that the input is in UTC, but the input itself has no information about it, you must tell it. One way is to set in the formatter:

// set the formatter to UTC
DateTimeFormatter inputFormatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS")
.withZone(DateTimeZone.UTC);

// DateTime will be in UTC
DateTime parsed = inputFormatter.parseDateTime("2017-09-16T05:06:18.157");

Another alternative is to first parse the input to a org.joda.time.LocalDateTime (a class that represents a date and time without a timezone), and then convert it to a DateTime in UTC:

// parse to LocalDateTime
DateTime = parsed = LocalDateTime.parse("2017-09-16T05:06:18.157")
// convert to a DateTime in UTC
.toDateTime(DateTimeZone.UTC);

Both produces the same DateTime, corresponding to UTC 2017-09-16T05:06:18.157Z.

To format it to "IST timezone" (which is actually not a timezone - more on that below), you can also set the timezone in the formatter:

// convert to Asia/Kolkata
DateTimeFormatter outputFormatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")
.withZone(DateTimeZone.forID("Asia/Kolkata"));
System.out.println(outputFormatter.print(parsed));

Or you can convert the DateTime to another timezone, using the withZone() method:

DateTimeFormatter outputFormatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
// convert to Asia/Kolkata
System.out.println(outputFormatter.print(parsed.withZone(DateTimeZone.forID("Asia/Kolkata"))));

Both will print:

2017-09-16 10:36:18

In your code you're using DateTimeZone.getDefault(), that gets the JVM default timezone (with some tricky details). But the default timezone can be changed without notice, even at runtime, so it's always better to specify which one you want to use.

Also, keep in mind that short names like IST are not real timezones. Always prefer to use IANA timezones names (always in the format Region/City, like Asia/Kolkata or Europe/Berlin).

Avoid using the 3-letter abbreviations (like IST or PST) because they are ambiguous and not standard. Just check in this list that IST can be "India Standard Time", "Israel Standard Time" and "Irish Standard Time".

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


Java new Date/Time API

Joda-Time is in maintainance mode and is being replaced by the new APIs, so I don't recommend start a new project with it. Even in joda's website 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).".

If you can't (or don't want to) migrate from Joda-Time to the new API, you can ignore this section.

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

This new API has lots of different date/time types for each situation.

First, you can parse the input to a org.threeten.bp.LocalDateTime, then I use a org.threeten.bp.ZoneOffset to convert it to UTC, resulting in a org.threeten.bp.OffsetDateTime.

Then, I use a org.threeten.bp.ZoneId to convert this to another timezone, and use a org.threeten.bp.format.DateTimeFormatter to format it (this is basically what's suggested by @Ole V.V's comment - just to show how straightforward it is, as there aren't anything much different to do):

// parse to LocalDateTime
OffsetDateTime parsed = LocalDateTime.parse("2017-09-16T05:06:18.157")
// convert to UTC
.atOffset(ZoneOffset.UTC);

// convert to Asia/Kolkata
ZoneId zone = ZoneId.of("Asia/Kolkata");
DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println(outputFormatter.format(parsed.atZoneSameInstant(zone)));

The output is:

2017-09-16 10:36:18

Java convert UTC timestamp to local DateTime

Try this is working with me

public  String getDateCurrentTimeZone(long timestamp) {
try{
Calendar calendar = Calendar.getInstance();
TimeZone tz = TimeZone.getDefault();
calendar.setTimeInMillis(timestamp * 1000);
calendar.add(Calendar.MILLISECOND, tz.getOffset(calendar.getTimeInMillis()));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date currenTimeZone = (Date) calendar.getTime();
return sdf.format(currenTimeZone);
}catch (Exception e) {
}
return "";
}

Convert UTC to current locale time

It has a set timezone method:

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date myDate = simpleDateFormat.parse(rawQuestion.getString("AskDateTime"));

all done!

Kotlin - convert UTC to local time

Try using Extension Functions

fun String.toDate(dateFormat: String = "yyyy-MM-dd HH:mm:ss", timeZone: TimeZone = TimeZone.getTimeZone("UTC")): Date {
val parser = SimpleDateFormat(dateFormat, Locale.getDefault())
parser.timeZone = timeZone
return parser.parse(this)
}

fun Date.formatTo(dateFormat: String, timeZone: TimeZone = TimeZone.getDefault()): String {
val formatter = SimpleDateFormat(dateFormat, Locale.getDefault())
formatter.timeZone = timeZone
return formatter.format(this)
}

Usage:

"2018-09-10 22:01:00".toDate().formatTo("dd MMM yyyy")

Output: "11 Sep 2018"



Related Topics



Leave a reply



Submit