来自 REST API 的服务器响应格式日期无效

Format Date on Server Response from REST API not working

我有一个从 REST 服务器获取数据的方法。方法 returns 格式为“2017-08-14T17:45:16.24Z”的日期。我还写了一个方法,按照 "dd/MM/yyyy" 的顺序格式化日期。这非常有效,但是当我尝试从服务器格式化日期并将其设置为 Edittext 时,它不起作用。这表明我在服务器响应中格式化日期的方法不起作用。我格式化日期的方法如下:

private String formatDate(String dateString) {
    try {
        SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS" );
        Date d = sd.parse(dateString);
        sd = new SimpleDateFormat("dd/MM/yyyy");
        return sd.format(d);
    } catch (ParseException e) {
    }
    return "";
}

下面的这个方法从服务器获取日期并格式化日期并将日期设置为编辑文本。

public void getProfile() {

    Retrofit retrofit = RetrofitClient.getClient(authUser.getToken());
    APIService mAPIService = retrofit.create(APIService.class);

    mAPIService.getProfile("Bearer " + authUser.getToken()).enqueue(new Callback<Profile>() {
        @Override
        public void onResponse(Response<Profile> response, Retrofit retrofit) {
            if(response.isSuccess()) {
                try {
                    String loginSuccess = response.body().getSuccess();
                    if (loginSuccess.equals("true")) {
                        id_name.setText(response.body().getData().getName());
                        id_email.setText(response.body().getData().getEmail());
                        phone_input_layout.setText(response.body().getData().getPhoneNumber());
                        id_gender.setText(response.body().getData().getGender());
                        String dateOfBirth = response.body().getData().getDateOfBirth();
                        id_date_of_birth.setText(formatDate(dateOfBirth));
                        //updateLabel(dateOfBirth);
                        id_residential_address.setText(response.body().getData().getResidentialAddress());
                        if (response.body().getData().getEmploymentStatus().equals("Student")) {
                            id_nss_number.setVisibility(View.VISIBLE);
                            maximum_layout.setVisibility(View.INVISIBLE);
                            extended_layout.setVisibility(View.INVISIBLE);
                        } else if (response.body().getData().getEmploymentStatus().equals("Employed")) {
                            maximum_layout.setVisibility(View.VISIBLE);
                            extended_layout.setVisibility(View.INVISIBLE);
                            id_nss_number.setVisibility(View.INVISIBLE);
                            id_type.setText(response.body().getData().getIdType());
                            id_number.setText(response.body().getData().getIdNumber());
                            id_expiry_date.setText(response.body().getData().getIdExpiryDate());
                        }


                    } else {
                        String message = response.body().getMessage();
                        Log.e("getProfileError", message);
                        Toast.makeText(UserProfileActivity.this, message, Toast.LENGTH_LONG).show();
                    }
                }catch (Exception e){
                    Toast.makeText(getApplicationContext(), "Some fields are empty", Toast.LENGTH_SHORT).show();
                    e.printStackTrace();
                }

            }


        }

        @Override
        public void onFailure(Throwable throwable) {
            Log.e("getProfileError", throwable.getMessage());
            Toast.makeText(UserProfileActivity.this, "Unable to Login, Please Try Again", Toast.LENGTH_LONG).show();
        }
    });
}

这是我从日期格式中得到的异常

I/dateError:: Unparseable date: "1988-11-09T00:00:00Z"

您想要的格式是

yyyy-MM-dd'T'HH:mm:ss.SSS'Z' 

最后一个 Z 代表 "zero hour offset" 也称为 "Zulu time" (UTC)。

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("UTC"));

使用这个 UTC 时区,转换后的小时将为 20H

如果您不添加时区,您将获得预期的时间 ​​17H

this is the error i get from my formatDate I/dateError:: Unparseable date: "1988-11-09T00:00:00Z" (at offset 19)

该日期时间字符串在秒上没有小数(也没有小数点)。偏移量 19 是 Z 所在的位置,也是格式模式字符串中小数点所在的位置。这会导致您的异常。

java.time,现代 Java 日期和时间 API,将轻松解决您的问题:

private static final DateTimeFormatter dateFormatter
        = DateTimeFormatter.ofPattern("dd/MM/yyyy");

private static String formatDate(String dateString) {
    return Instant.parse(dateString)
            .atZone(ZoneId.of("Australia/Queensland"))
            .format(dateFormatter);
}

这将在秒上使用和不使用小数:

    System.out.println(formatDate("2017-08-14T17:45:16.24Z"));
    System.out.println(formatDate("1988-11-09T00:00:00Z"));

这会打印

15/08/2017
09/11/1988

当字符串中的day-of-month 为14 时,第一行说的是该月的15 日,您可能会感到惊讶。这是因为在UTC 中为17:45 时,它已经是第二天在澳大利亚。我想你想在你的用户的时区中的一天。因此,如果不是 Australia/Queensland,请替换为您想要的时区。如果您确实想要 UTC 日期,请使用此行而不是 atZone 调用:

            .atOffset(ZoneOffset.UTC) 

这将确保您获得与字符串中相同的日期。

作为一个细节,上面的代码也正确地解析了你的 0.24 秒。 SimpleDateFormat 将 24 理解为 24 毫秒,所以你得到的是 0.024 秒,有点不准确。还有一个细节,我声明了你的方法static,没必要,但我们也可以。

问题:我可以在 Android 上使用 java.time 吗?

是的,您可以在 Android 上使用 java.time。它只需要至少 Java 6.

  • 在 Java 8 及更高版本和较新的 Android 设备上,现代 API 是内置的。
  • 在 Java 6 和 7 中获取 ThreeTen Backport,新 类 的 backport(ThreeTen 用于 JSR 310;请参阅底部的链接)。
  • 在较旧的 Android 上使用 ThreeTen Backport 的 Android 版本。它叫做 ThreeTenABP。并确保使用子包从 org.threeten.bp 导入日期和时间 类。

链接