日期时区转换

Date TimeZone conversion

我已经完成了从 UTC 字符串到本地时区日期的转换方法,但它只是 returns 与字符串中的日期相同。这里有什么问题?

 public static Date getUTCToDate(String utc){
    // String exampleOfUTCTime = "2016-09-27T19:35:32.717";

    try{
        Log.d("asd-timeBefore", "getUTCToDate: " + utc);
        DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
        formatter.setTimeZone(TimeZone.getDefault());
        Date d = formatter.parse(utc);
        Log.d("asd-timeAfter", "getUTCToDate: " + d);
        return d;
    } catch (ParseException e){
        e.printStackTrace();
    }
    return null;
}

尝试像这样更改您的代码。它将UTC时区转换为本地时区:

public static Date getUTCToDate(String utc){
    // String exampleOfUTCTime = "2016-09-27T19:35:32.717";

    try{
        Log.d("asd-timeBefore", "getUTCToDate: " + utc);
        DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
        formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
        Date d = formatter.parse(utc);
        Log.d("asd-timeAfter", "getUTCToDate: " + d);
        return d;
    } catch (ParseException e){
        e.printStackTrace();
    }
    return null;
}

如果你想获得 UTC 格式的格式化日期和时间,那么你应该这样做

formatter.setTimeZone(TimeZone.getTimeZone("UTC"));

带有 setTimeZone 的答案是正确的,但作为替代方案,您可以尝试在字符串本身中指定 UTC 并表明您使用的是 SimpleDateFormat [=16] 中的时区=],例如:

public static Date getUTCToDate(String utc){
    // String exampleOfUTCTime = "2016-09-27T19:35:32.717 UTC";

    try{
        System.out.println("getUTCToDate: " + utc);
        DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS z");
        Date d = formatter.parse(utc);
        System.out.println("getUTCToDate: " + d);
        return d;
    } catch (ParseException e){
        e.printStackTrace();
    }
    return null;
}

I need to use local timezone since app will be used in various countries.

如果你想在服务器端使用客户端的时区格式化日期,那么你必须从客户端传递以分钟为单位的 GMT 时间偏移量。使用此 Java脚本代码:

var offset = new Date().getTimezoneOffset();

然后将此偏移量作为参数传递给您的方法:

public static Date getUTCToDate(String utc, int offsetInMinutes) {
    // String exampleOfUTCTime = "2016-09-27T19:35:32.717";

    try {
        Log.d("asd-timeBefore", "getUTCToDate: " + utc);
        DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS Z");
        long offset = -1L*60*1000*offsetInMinutes;
        String[] timezones = TimeZone.getAvailableIDs(offset);
        formatter.setTimeZone(timezones[0]);
        Date d = formatter.parse(utc);
        Log.d("asd-timeAfter", "getUTCToDate: " + d);
        return d;
    } catch (ParseException e){
        e.printStackTrace();
    }
    return null;
}

评论:

您会注意到我在 SimpleDateFormat 中包含了 Z 作为日期格式参数。这将包括显示为与 GMT 时间的小时偏移量的时区。

A Java Date 只是一个时间点,不考虑偏移量。如果你想从客户端获取时区信息,你必须自己带进来。

tl;博士

LocalDateTime.parse( "2016-09-27T19:35:32.717" ).atZone( ZoneOffset.UTC )

详情

您输入的字符串是不是一个UTC value: 2016-09-27T19:35:32.717. That String lacks any information about offset-from-UTC or time zone

您正在使用麻烦的旧日期时间 类,现在是遗留的,被 java.time 类.

取代

LocalDateTime

将该字符串解析为缺少任何偏移量或时区的 LocalDateTime 对象。

该输入字符串恰好符合日期时间字符串的 ISO 8601 标准。当 parsing/generating 字符串时,java.time 类 默认使用 ISO 8601 格式。因此无需指定格式模式。

LocalDateTime ldt = LocalDateTime.parse( "2016-09-27T19:35:32.717" );

OffsetDateTime

如果根据上下文您确定该字符串表示 UTC 中的时刻,则应用偏移量以获得 OffsetDateTime. Use the predefined constant ZoneOffset.UTC.

OffsetDateTime odt = ldt.atZone( ZoneOffset.UTC );

如果需要,您可以从那里使用 DateTimeFormatter 生成各种格式的字符串。

ZonedDateTime

如果您想通过某个特定地区时区的镜头查看同一时刻,请应用 ZoneId to get a ZonedDateTime

时区是与 UTC 的偏移量加上 一组用于处理夏令时 (DST) 等异常的规则。

continent/region的格式指定一个proper time zone name。切勿使用 3-4 个字母的缩写,例如 ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = odt.atZoneSameInstant( z );

如果需要,您可以获取用户当前的默认时区。但请注意,此默认设置随时可能更改,甚至 在运行时。因此,如果重要,您应该向用户询问 intended/desired 时区而不是假设。

ZoneId z = ZoneId.systemDefault();

关于java.time

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

Joda-Time project, now in maintenance mode,建议迁移到java.time。

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

在哪里获取java.time类?

  • Java SE 8 and SE 9 及更高版本
    • 内置。
    • 标准 Java API 的一部分,带有捆绑实施。
    • Java 9 添加了一些小功能和修复。
  • Java SE 6 and SE 7
  • Android
    • ThreeTenABP项目专门为Android改编了ThreeTen-Backport(上面提到的)。

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.