Java Android设备系统时间在将服务器日期字符串转换为日期时更改其时区

Java Android设备系统时间在将服务器日期字符串转换为日期时更改其时区,java,android,timezone,simpledateformat,Java,Android,Timezone,Simpledateformat,我必须检查服务器和Android设备系统的时间差是否超过1小时。 现在,我从服务器上获得了以下字符串: 2020-08-24T11:50:18.613+0300 这些是我用于SimpleDataFormat的常量: private static final String SYSTEM_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" 问题是,当我尝试将字符串日期转换为日期类时,我得到以下结果: Mon Aug 24 13:50:18 GMT+05

我必须检查服务器和Android设备系统的时间差是否超过1小时。 现在,我从服务器上获得了以下字符串:

2020-08-24T11:50:18.613+0300
这些是我用于SimpleDataFormat的常量:

private static final String SYSTEM_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
问题是,当我尝试将字符串日期转换为日期类时,我得到以下结果:

Mon Aug 24 13:50:18 GMT+05:00 2020
据我所知+05:00是因为它是在Android设备上设置为默认时区。我就是这样得到这个日期的:

Locale locale =  new Locale("ru","RU");
DateFormat df = new SimpleDateFormat(SYSTEM_FORMAT, locale);
df.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));
Date date = df.parse(serverDate);

正如你们所看到的,即使将时区设置为+3莫斯科时间,也不会产生我所期望的日期。我知道我可以用字符串来比较它,但要求比较日期,你没有真正的时区,而是偏移量

要正确转换从服务器获取的字符串,应使用java.time而不是过时的java.util.Date或java.util.Calendar

下面是一个使用适合您的情况的类的示例java.time.OffsetDateTime:

此文件的输出是OffsetDateTime,其格式与您发布的模式相似

2020年8月24日星期一11:50:18+03:00 您也可以使用ZonedDateTime,但随后必须添加ZoneId,ZoneId.ofEurope/Moscow,很可能。。。 可以使用已创建的OffsetDateTime TimeFinder服务器执行以下操作:

和System.outing,如果不使用特殊格式,您将获得以下信息:

2020-08-24T11:50:18.613+03:00[欧洲/莫斯科] 2020-08-24T10:50:18.613+02:00[欧洲/柏林] 请注意:
因为有一种方法,您可以在Android 26以下的API级别使用Java 8+功能。

您实际上没有时区,而是有一个偏移量

要正确转换从服务器获取的字符串,应使用java.time而不是过时的java.util.Date或java.util.Calendar

下面是一个使用适合您的情况的类的示例java.time.OffsetDateTime:

此文件的输出是OffsetDateTime,其格式与您发布的模式相似

2020年8月24日星期一11:50:18+03:00 您也可以使用ZonedDateTime,但随后必须添加ZoneId,ZoneId.ofEurope/Moscow,很可能。。。 可以使用已创建的OffsetDateTime TimeFinder服务器执行以下操作:

和System.outing,如果不使用特殊格式,您将获得以下信息:

2020-08-24T11:50:18.613+03:00[欧洲/莫斯科] 2020-08-24T10:50:18.613+02:00[欧洲/柏林] 请注意:
由于Android 26以下的API级别中存在Java 8+功能,因此在理解日期-时间字符串中的区域偏移量方面似乎存在一些差距。日期时间字符串2020-08-24T11:50:18.613+0300表示它是+0300小时区域偏移处的日期时间,即UTC上相应的日期时间字符串为2020-08-24T8:50:18.613+0000

请注意,java.util.Date缺少时区和区域偏移量信息。它只有自1970年1月1日00:00:00 UTC以来的毫秒数。当您使用SimpleDataFormat实例打印java.util.Date时,您会将表示时区中的日期时间的字符串打印到SimpleDataFormat实例中。您可以从以下示例中理解它:

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

public class Main {
    public static void main(String[] args) throws ParseException {
        // Parse the date-time string to java.util.Date
        String serverDate = "2020-08-24T11:50:18.613+0300";
        final String SYSTEM_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
        DateFormat dfSource = new SimpleDateFormat(SYSTEM_FORMAT);
        Date date = dfSource.parse(serverDate);
        System.out.println(date);

        // Get the date-time string for the time-zone of Europe/Moscow from
        // java.util.Date
        Locale locale = new Locale("ru", "RU");
        DateFormat dfTarget = new SimpleDateFormat(SYSTEM_FORMAT, locale);
        dfTarget.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));
        System.out.println(dfTarget.format(date));
    }
}
我建议您停止使用过时且容易出错的java.util日期时间API和SimpleDataFormat。切换到java.time日期时间API和相应的格式化API java.time.format。从了解有关现代日期时间API的更多信息。如果您的android版本与Java-8不兼容,您可以使用。检查

使用现代日期时间API: 输出:


请注意,现代日期-时间API有一个名为ZonedDateTime的类,该类包含时区信息以及日期和时间信息。

您对日期-时间字符串中的区域偏移的理解似乎存在一些差距。日期时间字符串2020-08-24T11:50:18.613+0300表示它是+0300小时区域偏移处的日期时间,即UTC上相应的日期时间字符串为2020-08-24T8:50:18.613+0000

请注意,java.util.Date缺少时区和区域偏移量信息。它只有自1970年1月1日00:00:00 UTC以来的毫秒数。当您使用SimpleDataFormat实例打印java.util.Date时,您会将表示时区中的日期时间的字符串打印到SimpleDataFormat实例中。您可以从以下示例中理解它:

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

public class Main {
    public static void main(String[] args) throws ParseException {
        // Parse the date-time string to java.util.Date
        String serverDate = "2020-08-24T11:50:18.613+0300";
        final String SYSTEM_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
        DateFormat dfSource = new SimpleDateFormat(SYSTEM_FORMAT);
        Date date = dfSource.parse(serverDate);
        System.out.println(date);

        // Get the date-time string for the time-zone of Europe/Moscow from
        // java.util.Date
        Locale locale = new Locale("ru", "RU");
        DateFormat dfTarget = new SimpleDateFormat(SYSTEM_FORMAT, locale);
        dfTarget.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));
        System.out.println(dfTarget.format(date));
    }
}
我建议您停止使用过时且容易出错的java.util日期时间API和SimpleDataFormat。切换到java.time日期时间API和相应的格式化API java.time.format。从了解有关现代日期时间API的更多信息。如果您的android版本与Java-8不兼容,您可以使用。检查

使用现代日期时间API: 输出:


请注意,现代日期时间API有一个名为ZonedDateTime的类,该类包含时区信息以及日期和时间信息。

无需担心abo 比较时间时ut与UTC或时区的偏移量。跨偏移量的比较进展顺利

java.time 我正在使用java.time,这是现代的java日期和时间API。让我们首先定义两个有用的常量:

private static final Duration TOLERANCE = Duration.ofHours(1);

private static final DateTimeFormatter serverFormatter = new DateTimeFormatterBuilder()
        .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
        .appendPattern("XX")
        .toFormatter();
现在我们可以做:

    String serverDateTimeString = "2020-08-24T11:50:18.613+0300";
    OffsetDateTime serverTime = OffsetDateTime.parse(serverDateTimeString, serverFormatter);
    System.out.println("Server time: " + serverTime);
    
    ZoneId deviceTimeZone = ZoneId.of("Asia/Yekaterinburg");
    OffsetDateTime deviceTime = OffsetDateTime.now(deviceTimeZone);
    System.out.println("Device time: " + deviceTime);
    
    if (deviceTime.isBefore(serverTime.minus(TOLERANCE)) || deviceTime.isAfter(serverTime.plus(TOLERANCE))) {
        System.out.println("Difference between time on server and Android device system time more than 1 hour");
    } else {
        System.out.println("Difference between time on server and Android device system time 1 hour or less");
    }
我已经使用了问题中的字符串,因此当我现在运行它时,代码片段告诉我们这两次之间有很大的差异时,我们不应该感到惊讶:

为了进行实验,我们还可以尝试将设备时间设置为您提问的时间:

    OffsetDateTime deviceTime = OffsetDateTime.of(2020, 8, 24, 13, 50, 18, 0, ZoneOffset.ofHours(5));
问:java.time不需要Android API级别26吗? time在较旧和较新的Android设备上都能很好地工作。它至少需要Java6

在Java8和更高版本以及API级别为26的较新Android设备上,内置了现代API。 在非Android Java 6和7中,获得了Three Ten Backport,即JSR 310的现代类Three Ten的Backport;请参阅底部的链接。 在较旧的Android上,可以使用desugaring或Android版本的ThreeTen Backport。它叫ThreeTenABP。在后一种情况下,请确保使用子包从org.threeten.bp导入日期和时间类。 链接 解释如何使用java.time。 ,其中首次描述了java.time。 ,java.time的后端口到JSR-310的Java6和Java7。 ,Android版Three Ten Backport ,解释得非常透彻。
在比较时间时,无需担心UTC或时区的偏移量。跨偏移量的比较进展顺利

java.time 我正在使用java.time,这是现代的java日期和时间API。让我们首先定义两个有用的常量:

private static final Duration TOLERANCE = Duration.ofHours(1);

private static final DateTimeFormatter serverFormatter = new DateTimeFormatterBuilder()
        .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
        .appendPattern("XX")
        .toFormatter();
现在我们可以做:

    String serverDateTimeString = "2020-08-24T11:50:18.613+0300";
    OffsetDateTime serverTime = OffsetDateTime.parse(serverDateTimeString, serverFormatter);
    System.out.println("Server time: " + serverTime);
    
    ZoneId deviceTimeZone = ZoneId.of("Asia/Yekaterinburg");
    OffsetDateTime deviceTime = OffsetDateTime.now(deviceTimeZone);
    System.out.println("Device time: " + deviceTime);
    
    if (deviceTime.isBefore(serverTime.minus(TOLERANCE)) || deviceTime.isAfter(serverTime.plus(TOLERANCE))) {
        System.out.println("Difference between time on server and Android device system time more than 1 hour");
    } else {
        System.out.println("Difference between time on server and Android device system time 1 hour or less");
    }
我已经使用了问题中的字符串,因此当我现在运行它时,代码片段告诉我们这两次之间有很大的差异时,我们不应该感到惊讶:

为了进行实验,我们还可以尝试将设备时间设置为您提问的时间:

    OffsetDateTime deviceTime = OffsetDateTime.of(2020, 8, 24, 13, 50, 18, 0, ZoneOffset.ofHours(5));
问:java.time不需要Android API级别26吗? time在较旧和较新的Android设备上都能很好地工作。它至少需要Java6

在Java8和更高版本以及API级别为26的较新Android设备上,内置了现代API。 在非Android Java 6和7中,获得了Three Ten Backport,即JSR 310的现代类Three Ten的Backport;请参阅底部的链接。 在较旧的Android上,可以使用desugaring或Android版本的ThreeTen Backport。它叫ThreeTenABP。在后一种情况下,请确保使用子包从org.threeten.bp导入日期和时间类。 链接 解释如何使用java.time。 ,其中首次描述了java.time。 ,java.time的后端口到JSR-310的Java6和Java7。 ,Android版Three Ten Backport ,解释得非常透彻。
另一方面,考虑扔掉那些陈旧的、臭名昭著的简单的格式和朋友。看看是否可以使用或添加到Android项目中,以便使用java.time,即现代java日期和时间API。显然,与之相关的是:1。2,作为一个旁观者,考虑扔掉那些陈旧的、臭名昭著的简单的格式和朋友。看看是否可以使用或添加到Android项目中,以便使用java.time,即现代java日期和时间API。与你一起工作真是太好了。显然相关:12非常感谢你的回答。在我对日期-时间字符串中的区域偏移的理解上确实存在一些差距,但我在这里尝试了很多次来寻找答案,只有在您的回答之后,我才知道该怎么做。非常感谢您的回答。在我对日期-时间字符串中的区域偏移量的理解上确实存在一些差距,但我在这里尝试了很多次来寻找答案,只有在得到你的答案后,我才知道该怎么做。
    OffsetDateTime deviceTime = OffsetDateTime.of(2020, 8, 24, 13, 50, 18, 0, ZoneOffset.ofHours(5));
Server time: 2020-08-24T11:50:18.613+03:00
Device time: 2020-08-24T13:50:18+05:00
Difference between time on server and Android device system time 1 hour or less