75

In my project, I have get the API response in json format. I get a string value of time in UTC time format like this Jul 16, 2013 12:08:59 AM.
I need to change this into Local time. That is where ever we use this the app needs to show the local time. How to I do this?

Here is some Code I have tried:

String aDate = getValue("dateTime", aEventJson);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MMM dd, yyyy HH:mm:ss z");
simpleDateFormat.setTimeZone(TimeZone.getDefault());
String formattedDate = simpleDateFormat.format(aDate);

Assume aDate contains Jul 16, 2013 12:08:59 AM

JDurstberger
  • 4,127
  • 8
  • 31
  • 68
MadTech
  • 1,458
  • 3
  • 13
  • 32

8 Answers8

136

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

Community
  • 1
  • 1
devconsole
  • 7,875
  • 1
  • 34
  • 42
  • 2
    I am getting the exception `java.text.ParseException: Unparseable date: "Jul 16, 2013 4:23:37 AM" (at offset 21)` – MadTech Jul 16 '13 at 13:34
  • Was this comment intended for this answer? – devconsole Jul 16 '13 at 13:35
  • I have tried this same code earlier i am getting exception in this line `Date date = df.parse(dateStr);` – MadTech Jul 16 '13 at 13:37
  • Please try again, I did test this! – devconsole Jul 16 '13 at 13:37
  • 1
    And don't forget to include the "a" (am/pm marker) instead of the "z" (time zone). – devconsole Jul 16 '13 at 13:38
  • Those who get an exception, use try catch for "Date date = df.parse(dateStr); " – Parinda Rajapaksha Aug 09 '18 at 04:03
  • Thanks, It works! I'm disappointed why can't android have a simple thing for that! I needed a Date object, so I had to convert my date String to Date then to String then to Date again! – Tamim Attafi Feb 23 '20 at 07:05
  • @TamimAttafi This is a standard Java API, not an Android API. If you use the correct date format pattern for your string representation only one conversion should be necessary. – devconsole Feb 26 '20 at 15:39
  • @devconsole before converting date format to date you set the timezone to "UTC", then from date to string you set the timezone to default. If I skip the default time zone action my date is not correctly shown. And I know that it is a standard Java API, I'm talking about android as a framework that is more responsible for presenting data and can't provide a simple solution for that. – Tamim Attafi Feb 27 '20 at 06:08
  • @TamimAttafi In this example one String representation is transformed into another, so a string gets parsed into a Date, then formatted into another string for a different time zone. Only one Date object required! If you need a Date object you only need to parse a String with the correct parameters, no need to format back to String then to Date again. Date basically only stores milliseconds since Jan 1, 1970 GMT(!), i.e. it represents a specific point in time, independent of time zone. – devconsole Feb 28 '20 at 08:36
  • The answer works but there is no need set default timezone df.setTimeZone(TimeZone.getDefault()); if you are specifying "UTC" timezone in simpledateformat then it will give your date back in local timezone only. reference https://stackoverflow.com/a/6049385/1567907 – Rikin Prajapati Jun 04 '20 at 18:19
  • @RikinPrajapati In the example I'm setting the timezone back to the default after having it set to UTC two lines prior. The SimpleDateFormat is then used to format, not to parse! OP's example code asked for a string representation, not just a Date object. – devconsole Jun 05 '20 at 07:38
  • 1
    @devconsole, formate to string is completely fine but setting the default timezone is not required. so the following line can be omitted and the result would remain unchanged df.setTimeZone(TimeZone.getDefault()); – Rikin Prajapati Jun 06 '20 at 08:14
14

I should like to contribute the modern answer. While SimpleDateFormat was the class we had for parsing and formatting date-times in 2013 (apart from Joda-Time), it is now long outdated, and we have so much better in java.time or JSR-310, the modern Java date and time API that came out with Java 8 in 2014.

But most Android devices still don’t run Java 8, I hear you say. Fortunately you can still use the modern Java date and time API on them through the ThreeTenABP, the backport of JSR-310 to Android Java 7. Details are in this question: How to use ThreeTenABP in Android Project.

Now the code is:

    DateTimeFormatter formatter 
            = DateTimeFormatter.ofPattern("MMM dd, uuuu hh:mm:ss a", Locale.ENGLISH);
    String aDate = "Jul 16, 2013 12:08:59 AM";
    String formattedDate = LocalDateTime.parse(aDate, formatter)
            .atOffset(ZoneOffset.UTC)
            .atZoneSameInstant(ZoneId.systemDefault())
            .format(formatter);
    System.out.println(formattedDate);

Since my computer is running Europe/Copenhagen time zone, which in July is 2 hours ahead of UTC, this prints

Jul 16, 2013 02:08:59 AM

Further points:

  • Since you have AM in your string, I assumed your hours are within AM, from 1 through 12. To parse and format them correctly you need lowercase h in the format pattern string. Uppercase H is for hour-of-day from 0 through 23.
  • Prefer to give an explcit locale to the formatter (whether SimpleDateFormat or DateTimeFormatter). If no locale is given, the formatter will use the device’s default locale. “Jul” and “AM” are in English, and your code may run nicely on many devices until one day it runs on a device with non-English locale and crashes, and you have a hard time figuring out why.
  • If you can, give the desired time zone explictly, for example as ZoneId.of("Asia/Kolkata"). The JVM’s default time zone may be changed by other parts of your program or other programs running in the same JVM, so is not reliable.
Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • 1
    This is Android api level 26 minimum – Boy May 30 '18 at 13:59
  • 1
    Not necessarily, @Boy. The ThreeTenABP I mention in the answer is for API level lower than 26. – Ole V.V. May 30 '18 at 14:44
  • ah ok! Well, I went with this answer: https://stackoverflow.com/a/15666678/969016 – Boy May 30 '18 at 14:49
  • Sorry, @Boy, that answer is not correct. Milliseconds since the epoch are always since the epoch. Adjusting them for time zone and/or summer time (DST) does not make sense. If you code ends up giving you the correct result, it has still gone the wrong way there and will be sure to confuse future readers. Your choice, of course. – Ole V.V. May 31 '18 at 07:27
  • ah sorry, my use case is different I guess. I have a number, let's say 7, which is the local time (hours). Then I need to add/subtract the hours unitl UTC to get the UTC time. that should be, right? – Boy May 31 '18 at 11:25
  • 1
    Well, err, @Boy, it doesn’t sound too wrong. To be sure to have it correct, you should know on which day it is 07:00 local time, since offsets have changed historically and may do again, not only with summer time. There is an enlightening discussion in [this question](https://stackoverflow.com/questions/50601391/what-is-the-right-way-to-format-time-between-different-timezones), for example. – Ole V.V. May 31 '18 at 11:32
8

1.Local to UTC Converter

public static String localToUTC(String dateFormat, String datesToConvert) {


        String dateToReturn = datesToConvert;

        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
        sdf.setTimeZone(TimeZone.getDefault());
        Date gmt = null;

        SimpleDateFormat sdfOutPutToSend = new SimpleDateFormat(dateFormat);
        sdfOutPutToSend.setTimeZone(TimeZone.getTimeZone("UTC"));

        try {

            gmt = sdf.parse(datesToConvert);
            dateToReturn = sdfOutPutToSend.format(gmt);

        } catch (ParseException e) {
            e.printStackTrace();
        }
        return dateToReturn;
    }

2. UTC to Local Converter

public static String uTCToLocal(String dateFormatInPut, String dateFomratOutPut, String datesToConvert) {


    String dateToReturn = datesToConvert;

    SimpleDateFormat sdf = new SimpleDateFormat(dateFormatInPut);
    sdf.setTimeZone(TimeZone.getTimeZone("UTC"));

    Date gmt = null;

    SimpleDateFormat sdfOutPutToSend = new SimpleDateFormat(dateFomratOutPut);
    sdfOutPutToSend.setTimeZone(TimeZone.getDefault());

    try {

        gmt = sdf.parse(datesToConvert);
        dateToReturn = sdfOutPutToSend.format(gmt);

    } catch (ParseException e) {
        e.printStackTrace();
    }
    return dateToReturn; }
Ronak Gadhia
  • 524
  • 5
  • 12
  • 3
    I can’t see what you are contributing towards the question asked that wasn’t already in more than one of the existing 4 answers? Also in 2018 please don’t teach the young ones to use the long outdated and notoriously troublesome `SimpleDateFormat` class. At least not as the first option. And not without any reservation. Today we have so much better in [`java.time`, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/) – Ole V.V. Jul 12 '18 at 08:47
  • 1
    I agree with Ole V.V., don't use SimpleDateFormat – joehinkle11 Apr 24 '20 at 16:21
7
//your UTC time var
long time = UTCtime;

//convert it
Time timeFormat = new Time();
timeFormat.set(time+TimeZone.getDefault().getOffset(time));

//use the value
long localTime = timeFormat.toMillis(true);
Tom Bevelander
  • 1,686
  • 1
  • 22
  • 31
3

Use the following code.

TimeZone defaultTimeZone = TimeZone.getDefault();
String strDefaultTimeZone = defaultTimeZone.getDisplayName(false, TimeZone.SHORT);

//The code you use
String aDate = getValue("dateTime", aEventJson);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MMM dd, yyyy HH:mm:ss z");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone(strDefaultTimeZone));
String formattedDate = simpleDateFormat.format(aDate);

This should work.

Omid.N
  • 824
  • 9
  • 19
Salman Khakwani
  • 6,684
  • 7
  • 33
  • 58
  • I am getting the exception `java.text.ParseException: Unparseable date: "Jul 16, 2013 4:23:37 AM" (at offset 21)` – MadTech Jul 16 '13 at 13:33
  • I get `java.lang.IllegalArgumentException: Cannot format given Object as a Date`. – Ole V.V. Jul 12 '18 at 08:46
  • Please share your date value that you are trying to format, as this error only occurs when a non-proper date is provided as an input. – Salman Khakwani Jul 16 '18 at 08:27
1

This is how i do it on android Build.VERSION.SDK_INT < 26

int offset = TimeZone.getDefault().getRawOffset();
String str_date='20:30 12-01-2021';
DateFormat formatter = new SimpleDateFormat("HH:mm dd-MM-yyy",Locale.US);
Date date = formatter.parse(str_date);
long utcTime = date.getTime() + (3600000*3);
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm dd/MM/yyyy", Locale.US);
String dateStr = sdf.format(utcTime + offset);
System.out.println(dateStr);

As my server sends the time with -3 timezone i have to add (3600*3) to getTime and i save it into utcTime, this way utcTime is in UTC. And then i add to utcTime the offset of the phone current timezone. In my case as my timezone is -3 its prints:

20:30 12/01/2021

But if i change my time zone the date also changes.

user3486626
  • 139
  • 1
  • 6
0

Use this code:

public static String stringDateWithTimezone(Date date, String pattern, TimeZone timeZone) {
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern, Locale.US);
            if (timeZone != null) {
                simpleDateFormat.setTimeZone(timeZone);
            }
            return simpleDateFormat.format(date);
        } catch (Exception e) {
            Timber.e(e);
            return null;
        }
    }

call in another class:

String dateUtc = DateUtil.stringDateWithTimezone(new Date(), "yyyy-MM-dd hh:mm:ss", TimeZone.getTimeZone("UTC"));
Hoàng Vũ Anh
  • 647
  • 1
  • 8
  • 24
0

I wanted to convert UTC Timestamp to Local Timestamp for some calculations. this is what i did

  val refreshed = Prefs.getLong(requireContext(), "refreshed_time")
  val calendar = Calendar.getInstance()
  calendar.timeInMillis = refreshed
  calendar.timeZone = TimeZone.getDefault()

  val localTimestamp = calendar.timeInMillis
Nasib
  • 1,173
  • 1
  • 13
  • 23