Java/Android - Convert a GMT time string to local time
Asked Answered
S

5

14

Ok, so I have a string, say "Tue May 21 14:32:00 GMT 2012" I want to convert this string to local time in the format May 21, 2012 2:32 pm. I tried SimpleDateFormat("MM dd, yyyy hh:mm a").parse(), but it threw an exception. So what should I do?

The exception is "unreported exception java.text.ParseException; must be caught or declared to be thrown."

in the line Date date = inputFormat.parse(inputText);

The code I ran on TextMate:

public class test{
    public static void main(String arg[]) {
        String inputText = "Tue May 22 14:52:00 GMT 2012";
        SimpleDateFormat inputFormat = new SimpleDateFormat(
            "EEE MMM dd HH:mm:ss 'GMT' yyyy", Locale.US);
        inputFormat.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
        SimpleDateFormat out = new SimpleDateFormat("MMM dd, yyyy h:mm a");
        Date date = inputFormat.parse(inputText);
        String output = out.format(date);
       System.out.println(output);
    }
}
Selfmortification answered 23/5, 2012 at 17:49 Comment(1)
Your example text up top is 21st which is a Monday not a Tuesday. Different from the example code.Boling
D
28

The format string you provided for parsing doesn't correspond with the text format you've actually got. You need to parse first, then format. It looks like you want:

SimpleDateFormat inputFormat = new SimpleDateFormat(
    "EEE MMM dd HH:mm:ss 'GMT' yyyy", Locale.US);
inputFormat.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));

SimpleDateFormat outputFormat = new SimpleDateFormat("MMM dd, yyyy h:mm a");
// Adjust locale and zone appropriately

Date date = inputFormat.parse(inputText);
String outputText = outputFormat.format(date);

EDIT: Here's the same code in the form of a short but complete program, with your sample input:

import java.util.*;
import java.text.*;

public class Test {
    public static void main(String[] args) throws ParseException {
        String inputText = "Tue May 21 14:32:00 GMT 2012";
        SimpleDateFormat inputFormat = new SimpleDateFormat
            ("EEE MMM dd HH:mm:ss 'GMT' yyyy", Locale.US);
        inputFormat.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));

        SimpleDateFormat outputFormat =
            new SimpleDateFormat("MMM dd, yyyy h:mm a");
        // Adjust locale and zone appropriately
        Date date = inputFormat.parse(inputText);
        String outputText = outputFormat.format(date);
        System.out.println(outputText);
    }
}

Can you compile and run that exact code?

Dispatch answered 23/5, 2012 at 17:54 Comment(7)
I tried it but the line Date date = inputFormat.parse(inputText); still throw the exception I mentioned above :(Selfmortification
@user1066956: Please post the exact string involved then - because I used the string you gave me in the question, and it was fine.Dispatch
"Tue May 21 14:32:00 GMT 2012" is the exact string I used. I ran the following code in TextMate and got the error I mentioned above.Selfmortification
@user1066956: I've edited a short but complete program into the answer. Can you run that exact code on your desktop? When it was failing, was that running it in Android or in Java?Dispatch
BTW, if we don't know the timezone (e.g. sometime the string come with America/Los_Angeles), what should we put to replace 'GMT'? Should we put zzzz?Selfmortification
@user1066956: "America/Los_Angeles" is the time zone ID. That's a much better time zone ID than "GMT". You could certainly try "zzzz" - I can't remember under which versions that will work.Dispatch
Your answer worked miraculously. Thank you so much. Upvoted.Saccharo
C
3

The formatter you use to parse must be defined to the format you expect. Here is an example that works for the values you provided however you may need to change it depending on how some edge cases act for the input:

String date = "Tue May 21 14:32:00 GMT 2012";
DateFormat inputFormat = new SimpleDateFormat("EE MMM dd HH:mm:ss zz yyy");
Date d = inputFormat.parse(date);
DateFormat outputFormat = new SimpleDateFormat("MMM dd, yyy h:mm a zz");
System.out.println(outputFormat.format(d));
Caitiff answered 23/5, 2012 at 18:5 Comment(0)
P
1

The method SimpleDateFormat.parse throws a parse exception.

The exception you're getting is telling you this...

The exception is "unreported exception java.text.ParseException; must be caught or declared to be thrown."

Wrap the line that does the parsing with try-catch and you should be golden..

Date d=null;
try{
    d = inputFormat.parse(date);
catch(ParseException e){
   // handle the error here....
}

R

Pallor answered 23/5, 2012 at 19:54 Comment(0)
B
1

You are using troublesome old date-time classes now supplanted by the java.time classes.

Wrong input data

Your first example string is incorrect, as the 21st is a Monday not a Tuesday. The second example string with 22nd is correct, and used in my example code below.

Using java.time

Avoid using this kind of format for textual representations of date-time values. In particular, never use the 3-4 letter abbreviation such as EST or IST seen in this kind of format, as they are not true time zones, not standardized, and not even unique(!). Specify a proper time zone name. In this particular case, java.time is able to translate that as GMT as UTC, but other values may fail.

String input = "Tue May 22 14:52:00 GMT 2012";
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "EEE MMM dd HH:mm:ss z uuuu" ).withLocale ( Locale.US );
ZonedDateTime zdt = ZonedDateTime.parse ( input , f );

System.out.println ( "zdt: " + zdt );

Dump to console. The toString method generates a String in standard ISO 8601 format, extended by appending the name of the zone in brackets. These standard formats are a much better choice for when you need to serialize date-time values to text.

System.out.println ( "zdt: " + zdt );

zdt: 2012-05-22T14:52Z[GMT]

Generate String

You can generate a String to represent this value in any format you desire. Generally best to let java.time localize automatically using a Locale and DateTimeFormatter.

Your desired format uses a medium-length style for the date portion but a short-length style for the time-of-day portion. Fortunately the DateTimeFormatter allows you to localize each portion separately, as seen here where we pass a pair of FormatStyle objects.

Locale l = Locale.US;  // Or Locale.CANADA_FRENCH, or Locale.ITALY, etc.
DateTimeFormatter fOutput = DateTimeFormatter.ofLocalizedDateTime ( FormatStyle.MEDIUM , FormatStyle.SHORT ).withLocale ( l );
String output = zdt.format ( fOutput );

Dump to console.

System.out.println ( "zdt: " + zdt + " | output: " + output );

zdt: 2012-05-22T14:52Z[GMT] | output: May 22, 2012 2:52 PM

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the old troublesome date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to java.time.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.

Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP (see How to use…).

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Boling answered 23/8, 2016 at 21:21 Comment(0)
T
0
const val DATE_HYPHEN_FORMAT = "yyyy-MM-dd"
const val DATE_MMM_DD_YYYY_FORMAT = "MMM dd, yyyy"
const val DATE_MMMM_DD_YYYY_FORMAT = "MMMM dd, yyyy"

const val FULL_DAY_NAME_FORMAT = "EEEE"
const val DATE_EEE_DD_MMMM_YYYY_FORMAT = "EEE dd, MMMM yyyy"
const val DATE_EEEE_DD_MMMM_YYYY_FORMAT = "EEEE dd, MMMM yyyy"

const val DATETIME_24_FORMAT = "dd-MM-yyyy'T'HH:mm:ss"

const val DATETIME_24_YMD_FORMAT = "yyyy-MM-dd'T'HH:mm:ss"
const val DATE_WITH_MONTH_NAME_MMM_DY_FORMAT = DateFormat.MEDIUM
const val DATE_WITH_MONTH_FULL_NAME_MMMM_DY_FORMAT = DateFormat.LONG

const val TIME_24H_FORMAT = "HH:mm:ss"
const val TIME_FORMAT_AM_PM = "hh:mm aa"
const val TIME_24H_FORMATWithoutSS = "HH:mm"

enum class TimeZoneTo {
    NONE, UTC, LOCAL
}


fun changeFormat(
    dateTime: String,
    fromFormat: Int = DATE_WITH_MONTH_NAME_MMM_DY_FORMAT,
    toFormat: String = DATETIME_24_FORMAT,
    convertIn: TimeZoneTo = TimeZoneTo.NONE,
    needOnlyTime: Boolean = false
): String {
    try {
        val parser = DateFormat.getDateInstance(fromFormat)
        val finalDateTime = trimDateTime(dateTime)

        val date = parser.parse(finalDateTime)
        val sdf = SimpleDateFormat(toFormat)

        return format(
            date = date!!, formatter = sdf, convertIn = convertIn, needOnlyTime = needOnlyTime
        )
    } catch (e: AssertionError) {
        e.printStackTrace()
    } catch (e: Exception) {
        e.printStackTrace()
    }

    return dateTime // Return Same DateTime - only iff unable to change format
}



fun changeFormat(
    dateTime: String,
    fromFormat: String = DATETIME_24_FORMAT,
    toFormat: Int = DATE_WITH_MONTH_NAME_MMM_DY_FORMAT,
    convertIn: TimeZoneTo = TimeZoneTo.NONE,
    needOnlyTime: Boolean = false
): String {
    try {
        val sfdInput = SimpleDateFormat(fromFormat, Locale.ROOT)
        val finalDateTime = trimDateTime(dateTime)

        val date: Date = sfdInput.parse(finalDateTime)!!
        val outputFormatter = DateFormat.getDateInstance(toFormat)

        return format(
            date = date,
            formatter = outputFormatter,
            convertIn = convertIn,
            needOnlyTime = needOnlyTime
        )
    } catch (e: AssertionError) {
        e.printStackTrace()
    } catch (e: Exception) {
        e.printStackTrace()
    }

    return dateTime // Return Same DateTime - only iff unable to change format
}

fun changeFormat(
    dateTime: String,
    fromFormat: String = DATETIME_24_FORMAT,
    toFormat: String = DATE_HYPHEN_FORMAT,
    convertInTimeZone: TimeZoneTo = TimeZoneTo.NONE,
    needOnlyTime: Boolean = false
): String {
    try {
        val sfdInput = SimpleDateFormat(fromFormat, Locale.ROOT)

        val finalDateTime = trimDateTime(dateTime)

        val date: Date = sfdInput.parse(finalDateTime)!!
        val sdfOutput = SimpleDateFormat(toFormat)

        return format(
            date = date,
            formatter = sdfOutput,
            convertIn = convertInTimeZone,
            needOnlyTime = needOnlyTime
        )
    } catch (e: AssertionError) {
        e.printStackTrace()
    } catch (e: Exception) {
        e.printStackTrace()
    }

    return dateTime // Return Same DateTime - only iff unable to change format
}


// Format Given Date as per specified timeZone
private fun format(
    date: Date,
    formatter: DateFormat,
    convertIn: TimeZoneTo,
    needOnlyTime: Boolean
): String {
    return when (convertIn) {
        TimeZoneTo.LOCAL -> {
            val zone = TimeZone.getTimeZone(Calendar.getInstance().timeZone.id)
            val newDate = Date(date.time + zone.getOffset(date.time))
            formatter.timeZone = zone

            val result = formatter.format(newDate)
            if (needOnlyTime) return result.substringAfter('T')
            else result
        }
        TimeZoneTo.UTC -> {
            formatter.timeZone = TimeZone.getTimeZone("UTC")
            val result = formatter.format(date)

            if (needOnlyTime) return result.substringAfter('T')
            else result
        }
        else -> {
            val result = formatter.format(date)
            if (needOnlyTime) return result.substringAfter('T')
            else result
        }
    }
}

I've created 3 overloaded methods namely changeFormat(...) with following params;

  1. dateTime (String -> date or time or dateTime)
  2. fromFormat (String/Int -> Current format of dateTime) - optional (i.e. if not provided default will be used)
  3. toFormat (String/Int -> New format for dateTime) - optional (i.e. if not provided default will be used)
  4. convertInTimeZone (Enum -> Convert in specified TimeZone)
  5. needOnlyTime (Boolean -> Will return only converted Time if true else converted dateTime

Hopefully, this may help someone in future.

Tight answered 12/12, 2022 at 11:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.