当前位置: 首页 > 知识库问答 >
问题:

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

管弘
2023-03-14

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

2020-08-24T11:50:18.613+0300

这些是我用于SimpleDateFormat的常量:

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(莫斯科时间)也不会使我期望的日期。我知道我可以用字符串比较它,但要求是比较日期

共有3个答案

佴英奕
2023-03-14

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

我正在使用java。时间,现代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");
    }

我已经使用了问题中的字符串,所以当我现在运行它时,代码片段告诉我们这两次之间有很大的差异时,我们不应该感到惊讶:

Server time: 2020-08-24T11:50:18.613+03:00
Device time: 2020-08-24T23:08:57.939565+05:00
Difference between time on server and Android device system time more than 1 hour

为了便于实验,我们还可以试着将设备时间设置为问题的时间:

    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

JAVA时间在旧的和新的Android设备上都能很好地工作。它至少需要Java6。

  • 在Java8和更高版本以及更新的Android设备上(从API级别26),现代API内置。
  • 在非AndroidJava6和7获取Threeten Backport,现代类的Backport(JSR 310的Threeten;请参阅底部的链接)。
  • 在较旧的Android上,要么使用脱脂或Android版的Threeten Backport。它叫做ThreeTenABP。在后一种情况下,请确保从带有子包的org.threeten.bp导入日期和时间类。
  • Oracle教程:解释如何使用java.time.日期时间
  • Java规范请求(JSR)310,其中首次描述了java.time
  • Threeten Backport项目,是java.time到Java6和7的Backport(用于JSR-310的Threeten)。
  • Java8个API可通过脱毛
  • ThreeTenABP, Android版的Threeten Backport
  • 问题:如何在Android项目中使用ThreeTenABP,有一个非常彻底的解释。
祖浩淼
2023-03-14

你没有真正的时区,而是一个偏移量。

要正确转换从服务器获取的String,您应该使用java.time而不是过时的java.util.Datejava.util.日历

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

public static void main(String[] args) {
    String stringFromServer = "2020-08-24T11:50:18.613+0300";
    OffsetDateTime timeFromServer = OffsetDateTime.parse(
                        stringFromServer,
                        DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSZ")
    );
    
    System.out.println(timeFromServer.format(
            DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss XXX uuuu", Locale.ENGLISH))
    );
}

该文件的输出(使用模仿您发布的模式格式化的OffsetDateTime)如下所示:

Mon Aug 24 11:50:18 +03:00 2020

您也可以使用ZoneDateTime,但随后必须添加ZoneIdZoneId。关于(“欧洲/莫斯科”),很可能
可以使用已经创建的OffsetDateTime timeFromServer这样做:

ZonedDateTime moscowTime = timeFromServer.atZoneSameInstant(ZoneId.of("Europe/Moscow"));
ZonedDateTime berlinTime = timeFromServer.atZoneSameInstant(ZoneId.of("Europe/Berlin"));

系统。在没有特殊格式的情况下删除它们,可以得到以下几行:

2020-08-24T11:50:18.613+03:00[Europe/Moscow]
2020-08-24T10:50:18.613+02:00[Europe/Berlin]

请注意:由于有Android的API反脱脂,您可以在Android 26以下的API级别中使用Java8()功能。

高正初
2023-03-14

看起来你对日期时间字符串中区域偏移的理解有一些差距。日期时间字符串2020-08-24T11:50:18.613 0300表示它是0300小时的区域偏移处的日期时间,即UTC上相应的日期时间字符串将是2020-08-24T8:50:18.613 0000

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

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。utildate-time API和SimpleDataFormat。切换到现代的java。时间date-time API和相应的格式化API(java.time.format)。从Trail:date-time了解更多关于现代日期时间API的信息。如果您的android版本不符合Java-8,您可以使用Three Ten BackportCheck进行backport。查看如何在Android项目中使用ThreeTenABP。

import java.text.ParseException;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) throws ParseException {
        // Given date-time string
        String serverDate = "2020-08-24T11:50:18.613+0300";

        // Date-time formatter
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");

        ZonedDateTime zdtServer = ZonedDateTime.parse(serverDate, formatter);
        System.out.println("Given date-time: " + zdtServer);
        System.out.println("Zone Offset of the given date-time: " + zdtServer.getOffset());

        // Convert it to some other time-zone e.g Etc/UTC
        ZonedDateTime zdtatUTC = zdtServer.withZoneSameInstant(ZoneId.of("Etc/UTC"));
        System.out.println("Equivalent date-time at UTC: " + zdtatUTC);

        // Convert it to some other time-zone e.g Europe/London
        ZonedDateTime zdtInLondon = zdtServer.withZoneSameInstant(ZoneId.of("Europe/London"));
        System.out.println("Equivalent date-time in London: " + zdtInLondon);
    }
}

输出:

Given date-time: 2020-08-24T11:50:18.613+03:00
Zone Offset of the given date-time: +03:00
Equivalent date-time at UTC: 2020-08-24T08:50:18.613Z[Etc/UTC]
Equivalent date-time in London: 2020-08-24T09:50:18.613+01:00[Europe/London]

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

 类似资料:
  • 问题内容: 将日期转换为JSON时,javascript会以以下格式保存日期: 但是,我不确定如何将其放入python datetime对象。我已经尝试过这些: 我相信javascript会将字符串保存为官方ISO格式,因此似乎应该有一种方法可以让python 读取它? 问题答案: 请尝试以下格式: 例如: 该的日期只是手段,它应该被解释为UTC时间,所以忽略它不会造成任何信息丢失。您可以在这里找

  • 问题内容: 我从来没有不得不将时间与UTC转换。最近有人要求我的应用注意时区,并且我一直在圈子里奔波。我发现很多有关将本地时间转换为UTC的信息,这很基本(也许我也做错了),但是我找不到任何有关将UTC时间轻松转换为最终用户时区的信息。 简而言之,android应用程序向我发送了(appengine应用程序)数据,该数据中包含时间戳。要将时间戳存储为UTC时间,我正在使用: 那似乎行得通。当我的应

  • 问题内容: 我在mysql中使用NOW()获取当前日期和时间。我想将日期值转换为varchar并将其与另一个字符串连接。我该怎么做? 问题答案: 使用DATE_FORMAT()

  • 问题内容: 例如字符串: 我将把它们推回到数据库中正确的日期时间字段中,因此我需要将它们魔术化为实际的日期时间对象。 这是通过Django的ORM进行的,因此我无法使用SQL进行插入时的转换。 问题答案: 是将字符串解析为日期时间的主要例程。它可以处理各种格式,格式由你为其指定的格式字符串确定: 生成的对象是时区未使用的。 链接: 适用于strptime:Python 2和Python 3的 Py

  • 问题内容: 我试图将字符串转换为日期时间对象。我从新闻提要中获取的字符串格式如下:“星期四,2014年10月16日美国东部时间01:16:17” 我尝试使用datetime.strptime()进行转换。即 并得到以下错误: 追溯(最近一次通话最近): 文件“”,第1行,位于datetime.strptime(’Thu,16 Oct 2014 01:16:17 EDT’,’%a,%d%b%Y%H:

  • 我有以下字符串: 我尝试用以下代码将此字符串转换为: Java . time . format . datetimeparseexception:无法解析文本“18/07/2019 04:30:00”:无法从TemporalAccessor获取LocalDateTime 我错过了什么?