39

I am downloading some JSON data from a webservice. In this JSON I've got some Date/Time values. Everything in UTC. How can I parse this date string so the result Date object is in the current locale?

For example: the Server returned "2011-05-18 16:35:01" and my device should now display "2011-05-18 18:35:01" (GMT +2)

My current code:

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date myDate = simpleDateFormat.parse(rawQuestion.getString("AskDateTime"));
LongFlick
  • 1,129
  • 1
  • 12
  • 21
  • 3
    FYI: Locale has nothing to do with time zone. A `Locale` is used when generating a String to represent your date-time in two ways: (a) determine the human language used to localize name of month etc., and (b) determine the cultural norms used in deciding issues such as abbreviation, capitalization, punctuation, etc. Meanwhile the time zone is a completely separate matter. You could have a Canadian user in India, so you would use `Locale.CANADA_FRENCH` with an India time zone, `ZoneId.of( "Asia/Kolkata" )`. – Basil Bourque Nov 16 '17 at 17:46

7 Answers7

90

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!

Affe
  • 47,174
  • 11
  • 83
  • 83
  • 8
    Can you please explain what is "rawQuestion" and "AskDateTime" ?? – Bhavin Patel Dec 17 '16 at 04:48
  • FYI, this Answer uses troublesome old date-time classes that are now supplanted by the java.time classes. See the [modern Answer](https://stackoverflow.com/a/47328630/642706). – Basil Bourque Nov 16 '17 at 17:49
20

So you want to inform SimpleDateFormat of UTC time zone:

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

To display:

simpleDateFormat.setTimeZone(TimeZone.getDefault());
String formattedDate = simpleDateFormat.format(myDate);
Paweł Dyda
  • 18,366
  • 7
  • 57
  • 79
  • 1
    Add Locale i.e SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); – Raj Karekar Sep 08 '16 at 04:58
3
public static String toLocalDateString(String utcTimeStamp) {
    Date utcDate = new Date(utcTimeStamp);
    DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
    df.setTimeZone(TimeZone.getTimeZone("PST"));
    return df.format(utcDate);
}

Cheers!

SolArabehety
  • 8,467
  • 5
  • 38
  • 42
Mohan
  • 4,755
  • 2
  • 27
  • 20
2

java.time

I should like to contribute the modern answer. Most of the other answers are correct and were fine answers in 2011. Today SimpleDateFormat is long outdated, and it always came with some surprises. And today we have so much better: java.time also known as JSR-310, the modern Java date and time API. This answer is for anyone who either accepts an external dependency (just until java.time comes to your Android device) or is already using Java 8 or later.

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
    String dateTimeFromServer = "2011-05-18 16:35:01";
    String localTimeToDisplay = LocalDateTime.parse(dateTimeFromServer, formatter)
            .atOffset(ZoneOffset.UTC)
            .atZoneSameInstant(ZoneId.of("Europe/Zurich"))
            .format(formatter);

The result of this code snippet is what was asked for:

2011-05-18 18:35:01

Give explicit time zone if you can

I have given an explicit time zone of Europe/Zurich. Please substitute your desired local time zone. To rely on your device’s time zone setting, use ZoneId.systemDefault(). However, be aware that this is fragile because it takes the time zone setting from the JVM, and that setting could be changed under our feet by other parts of your program or other programs running in the same JVM.

Using java.time on Android

I promised you an external dependency. To use the above on Android you need the ThreeTenABP, the Android edition of ThreeTen Backport, the backport of JSR-310 to Java 6 and 7. How to go about it is nicely and thoroughly explained in this question: How to use ThreeTenABP in Android Project.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • Can't use this. Call requires api 26 – Zeeshan Nov 23 '17 at 09:57
  • 1
    this should be the accepted answer! @ShanXeeshi To use in Android you need `ThreeTenABP` (backport of JSR-310) as @Ole V.V. says. Add this dependency `implementation 'com.jakewharton.threetenabp:threetenabp:1.2.1'` and you can use it! – Ryan Amaral Nov 14 '19 at 18:45
  • 1
    It's been 2 years now ;) I don't remember how I fixed conversion to local time at that time. But your comment will help others. – Zeeshan Nov 18 '19 at 01:22
1

Your String myUTC = "2016-02-03T06:41:33.000Z"

SimpleDateFormat existingUTCFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
SimpleDateFormat requiredFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

try{
Date getDate = existingFormat.parse(myUTC);
String mydate = requiredFormat.format(getDate)
}
catch(ParseException){
}
Raja Jawahar
  • 6,742
  • 9
  • 45
  • 56
0

If you had a timestamp (Long) as input instead (for the UTC time), since this is on Android, you can do something as such:

fun DateFormat.formatUtcEpochSecond(epochSecond: Long): String = format(CalendarEx.getFromEpochSecond(epochSecond).time)

fun DateFormat.formatUtcEpochMs(epochMilli: Long): String = format(CalendarEx.getFromEpochMilli(epochMilli).time)

CalendarEx.kt

object CalendarEx {

    @JvmStatic
    fun getFromEpochMilli(epochMilli: Long): Calendar {
        val cal = Calendar.getInstance()
        cal.timeInMillis = epochMilli
        return cal
    }

    @JvmStatic
    fun getFromEpochSecond(epochSecond: Long): Calendar {
        val cal = Calendar.getInstance()
        cal.timeInMillis = epochSecond * 1000L
        return cal
    }
}

DateHelper.kt

/**
 * gets the default date formatter of the device
 */
@JvmStatic
fun getFormatDateUsingDeviceSettings(context: Context): java.text.DateFormat {
    return DateFormat.getDateFormat(context) ?: SimpleDateFormat("yyyy/MM/dd", Locale.getDefault())
}

/**
 * gets the default time formatter of the device
 */
@JvmStatic
fun getFormatTimeUsingDeviceSettings(context: Context): java.text.DateFormat {
    return DateFormat.getTimeFormat(context) ?: SimpleDateFormat("HH:mm", Locale.getDefault())
}

Example usage:

    val dateFormat = DateHelper.getFormatDateUsingDeviceSettings(this)
    val timeFormat = DateHelper.getFormatTimeUsingDeviceSettings(this)
    val timeStampSecondsInUtc = 1516797000L
    val localDateTime = Instant.ofEpochSecond(timeStampSecondsInUtc).atZone(ZoneId.ofOffset("UTC", ZoneOffset.ofHours(0))).toLocalDateTime()
    Log.d("AppLog", "input time in UTC:" + localDateTime)
    Log.d("AppLog", "formatted date and time in current config:${dateFormat.formatUtcEpochSecond(timeStampSecondsInUtc)} ${timeFormat.formatUtcEpochSecond(timeStampSecondsInUtc)}")
android developer
  • 114,585
  • 152
  • 739
  • 1,270
0

A Date object is always a wrapper around milliseconds since epoch 0 in UTC. It does never represent local time.

That means that you need to create a second SimpleDateFormatter that creates a display string that is in local time.

Edit: @Op. Note that the preffered class for date/time-formatting on Android is java.text.DateFormat

Kaj
  • 10,862
  • 2
  • 33
  • 27
  • Yes but the zone context in which you parse the input string determines how many milliseconds are represented by that particular "clock on the wall" time. – Affe May 18 '11 at 18:34
  • 1
    Yes, my bad, I didn't see that he hadn't set the timezone for the first formatter. – Kaj May 18 '11 at 18:35