Retrofit2.3.0中如何解析响应头未知格式的UTC日期
解析响应头中格式不固定的UTC日期字符串为Date对象
问题描述
我正在处理OkHttp的响应回调,需要从PHP服务器返回的响应头
date字段获取UTC日期,但这个日期字符串的格式不固定,不确定该用哪种格式解析。以下是我的代码片段,需要补全日期解析的部分:
@Override public void onResponse(@NonNull Call<ConfigurationData> call, @NonNull Response<ConfigurationData> response) { CacheDb db = new CacheDb(this); int statusCode = response.code(); ConfigurationData configData = response.body(); String dateString = response.headers().get("date");//date String Date date = ..............//***我需要这部分代码*** switch (statusCode){ case 200: db.setClass("config", configData); startActivity(new Intent(SplashActivity.this, HomePage.class)); handler.removeCallbacks(null); handler.removeCallbacksAndMessages(null); SplashActivity.this.finish(); finish(); break; default: setDialog(); break; } } @Override public void onFailure(@NonNull Call<ConfigurationData> call, @NonNull Throwable t) { setDialog(); }
解决方案
其实HTTP协议的Date响应头是有明确规范的,主要支持三种格式:RFC 1123、RFC 850和ANSI C的asctime格式。我们可以通过依次尝试这些格式来解析,不管服务器返回哪种标准格式都能处理。下面给你两种适配不同Java/Android版本的方案:
方案1:Java 8+ / Android API 26+ (推荐)
使用Java 8引入的java.time包,这是更现代、线程安全的日期处理方式:
import java.time.Instant; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.util.Date; import java.util.Locale; // 替换你代码中需要补全的部分 String dateString = response.headers().get("date");//date String Date date = null; if (dateString != null) { // 定义所有HTTP标准支持的日期格式,额外兼容ISO8601格式以防万一 DateTimeFormatter[] formatters = { DateTimeFormatter.RFC_1123_DATE_TIME, DateTimeFormatter.RFC_1036_DATE_TIME, // 对应RFC 850 DateTimeFormatter.ISO_INSTANT }; for (DateTimeFormatter formatter : formatters) { try { // 强制使用US locale,避免系统本地化影响英文日期解析 Instant instant = formatter.withLocale(Locale.US).parse(dateString, Instant::from); date = Date.from(instant); break; // 解析成功就跳出循环 } catch (DateTimeParseException e) { // 格式不匹配,尝试下一种 continue; } } } // 容错处理:如果所有格式都解析失败,date会是null,这里可以根据需求处理 if (date == null) { // 比如设置默认日期,或者记录日志 }
方案2:兼容Java 7 / Android API <26
如果需要兼容旧版本,可以用SimpleDateFormat来实现,注意它是非线程安全的,所以要在循环里每次创建实例:
import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; // 替换你代码中需要补全的部分 String dateString = response.headers().get("date");//date String Date date = null; if (dateString != null) { // 定义HTTP标准支持的三种日期格式 String[] dateFormats = { "EEE, dd MMM yyyy HH:mm:ss zzz", // RFC 1123 "EEEE, dd-MMM-yy HH:mm:ss zzz", // RFC 850 "EEE MMM d HH:mm:ss yyyy" // ANSI C asctime }; for (String format : dateFormats) { try { SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.US); sdf.setLenient(false); // 严格解析,避免错误格式被强制兼容 date = sdf.parse(dateString); break; // 解析成功跳出循环 } catch (ParseException e) { // 尝试下一种格式 continue; } } } // 容错处理 if (date == null) { // 处理解析失败的情况 }
说明
- 强制使用
Locale.US是因为日期字符串里的星期、月份都是英文缩写/全称,避免系统用其他语言的本地化规则导致解析失败。 - 设置
setLenient(false)(针对SimpleDateFormat)可以避免一些不符合规范的日期被错误解析,保证解析的准确性。
内容的提问来源于stack exchange,提问作者stanly1904
相关产品推荐
相关产品推荐

