繁体   English   中英

Java/Android - 将 GMT 时间字符串转换为本地时间

[英]Java/Android - Convert a GMT time string to local time

好的,所以我有一个字符串,比如“2012 年 5 月 21 日星期二 14:32:00 GMT”我想将这个字符串转换为当地时间,格式为 2012 年 5 月 21 日下午 2:32。 我尝试了 SimpleDateFormat("MM dd, yyyy hh:mm a").parse(),但它引发了异常。 所以我该怎么做?

异常是“未报告的异常 java.text.ParseException;必须被捕获或声明为抛出。”

在行Date date = inputFormat.parse(inputText);

我在 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);
    }
}

您提供的用于解析的格式字符串与您实际获得的文本格式不符。 您需要先解析,然后格式化。 它看起来像你想要的:

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);

编辑:这是一个简短但完整的程序形式的相同代码,您的示例输入:

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);
    }
}

你能编译并运行那些确切的代码吗?

您用于解析的格式化程序必须定义为您期望的格式。 下面是一个适用于您提供的值的示例,但您可能需要根据某些边缘情况对输入的作用进行更改:

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));

SimpleDateFormat.parse方法抛出一个解析异常。

你得到的例外是告诉你这个......

例外情况是“未报告的异常java.text.ParseException; 必须被捕获或声明被抛出”。

使用try-catch包装进行解析的行,你应该是金色的..

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

[R

您正在使用现在由java.time类取代的麻烦的旧日期时间类。

输入数据错误

您的第一个示例字符串不正确,因为21日是星期一而不是星期二。 带有22nd的第二个示例字符串是正确的,并在下面的示例代码中使用。

使用java.time

避免将此类格式用于日期时间值的文本表示。 特别是,永远不要使用这种格式中看到的3-4字母缩写,例如ESTIST ,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。 指定正确的时区名称 在这种特殊情况下,java.time能够将其转换为GMT作为UTC ,但其他值可能会失败。

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 );

转储到控制台。 toString方法生成标准ISO 8601格式的String,通过在括号中附加区域名称进行扩展。 当您需要将日期时间值序列化为文本时,这些标准格式是更好的选择。

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

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

生成字符串

您可以生成一个String,以您希望的任何格式表示此值。 通常最好让java.time使用LocaleDateTimeFormatter自动进行本地化。

您所需的格式使用中等长度样式作为日期部分,但使用短长度样式作为时间部分。 幸运的是, DateTimeFormatter允许您分别本地化每个部分,如此处所示,我们传递一对FormatStyle对象。

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 );

转储到控制台。

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

zdt:2012-05-22T14:52Z [GMT] | 输出:2012年5月22日下午2:52

关于java.time

java.time框架内置于Java 8及更高版本中。 这些类取代了旧的麻烦的日期时间类,如java.util.Date.Calendarjava.text.SimpleDateFormat

现在处于维护模式Joda-Time项目建议迁移到java.time。

要了解更多信息,请参阅Oracle教程 并搜索Stack Overflow以获取许多示例和解释。

大部分的java.time功能后移植到Java 6和7 ThreeTen,反向移植 ,并进一步适应的AndroidThreeTenABP (见如何使用...... )。

ThreeTen-Extra项目使用其他类扩展了java.time。 该项目是未来可能添加到java.time的试验场。 您可以在这里找到一些有用的课程,如IntervalYearWeekYearQuarter等。

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

我创建了 3 个重载方法,即带有以下参数的changeFormat(...)

  1. 日期时间(字符串 -> 日期或时间或日期时间)
  2. fromFormat (String/Int -> Current format of dateTime) - 可选(即,如果未提供,将使用默认值)
  3. toFormat (String/Int -> New format for dateTime) - 可选(即,如果未提供,将使用默认值)
  4. convertInTimeZone (枚举 -> 在指定时区转换)
  5. needOnlyTime (Boolean -> 如果为true则仅返回转换后的时间,否则转换后的日期时间

希望这可以帮助将来的人。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM