问题描述
大家好。我有一个关于天气的项目。而且我面临转换问题,我将日出和日落转换为 Long(秒),我需要转换为 HH:mm。当我运行应用程序时,我得到无效数据,日出:23:30 和日落:14:42。虽然实际上我们在 5:30 日出,20:42 日落。自从我们住在 UTC +6 时区以来,我可以看到 6 小时的差异,这可能相关吗?如何正确转换?我的变换函数 :
fun Long?.format(pattern: String? = "dd/MM/yyyy"): String{
this?.let {
val sdf = SimpleDateFormat(pattern,Locale.getDefault())
return sdf.format(Date(this * 1000))
}
return ""
}
主要活动代码
private fun setValuesToViews(it: ForeCast) {
val tvTemperature = findViewById<TextView>(R.id.tv_temperature)
val tvDate = findViewById<TextView>(R.id.tv_date)
val tvTempMax = findViewById<TextView>(R.id.tv_temp_max)
val tvTempMin = findViewById<TextView>(R.id.tv_temp_min)
val tvFeelsLike = findViewById<TextView>(R.id.tv_feels_like)
val tvWeather = findViewById<TextView>(R.id.tv_weather)
val tvSunrise = findViewById<TextView>(R.id.tv_sunrise)
val tvSunset = findViewById<TextView>(R.id.tv_sunset)
val tvHumidity = findViewById<TextView>(R.id.tv_humidity)
tvTemperature.text = it.current?.temp?.toString()
tvDate.text = it.current?.date.format()
tvTempMax.text = it.daily?.get(0)?.temp?.max?.roundToInt()?.toString()
tvTempMin.text = it.daily?.get(0)?.temp?.min?.roundToInt()?.toString()
tvFeelsLike.text = it.current?.feels_like?.roundToInt()?.toString()
tvWeather.text = it.current?.weather?.get(0)?.description
tvSunrise.text = it.current?.sunrise.format("hh:mm")
tvSunset.text = it.current?.sunset.format("hh:mm")
tvHumidity.text = "${it.current?.humidity?.toString()} %"
}
解决方法
java.time
考虑使用 java.time(现代 Java 日期和时间 API)来处理您的时间工作。很抱歉我只能写Java。我首先为您想要的时间格式定义一个格式化程序:
private static final DateTimeFormatter TIME_FORMATTER
= DateTimeFormatter.ofPattern("HH:mm");
格式包括转换为您的时区。如果不是亚洲/乌鲁木齐,请替换正确的时区 ID。
// Example time zone at offset +06:00
ZoneId zone = ZoneId.of("Asia/Urumqi");
long sunriseLong = 1_625_700_600;
long sunsetLong = 1_625_755_320;
Instant sunrise = Instant.ofEpochSecond(sunriseLong);
System.out.println(sunrise);
String sunriseText = sunrise.atZone(zone).format(TIME_FORMATTER);
System.out.println(sunriseText);
Instant sunset = Instant.ofEpochSecond(sunsetLong);
System.out.println(sunset);
String sunsetText = sunset.atZone(zone).format(TIME_FORMATTER);
System.out.println(sunsetText);
输出为:
2021-07-07T23:30:00Z
05:30
2021-07-08T14:42:00Z
20:42
我还打印了我使用的 Instant
对象。这些以 UTC 打印,您可以识别 23:30 和 14:42 的无效时间。转换为您的时区后,时间是正确的。
您的天气数据还可能包含有关 UTC 偏移量的信息,您可以使用这些信息来代替自己定义时区。你可以检查一下。一个例子:
int timezone = 21600;
ZoneOffset offset = ZoneOffset.ofTotalSeconds(timezone);
System.out.println(offset);
String sunriseText = sunrise.atOffset(offset).format(TIME_FORMATTER);
System.out.println(sunriseText);
+06:00
05:30
我只打印偏移量以确认我已正确解释了数字 21600。再次打印预期的日出时间 05:30。日落也是如此,你可能已经猜到了。
问题:java.time 不需要 Android API 级别 26 吗?
java.time 在较旧和较新的 Android 设备上都能很好地工作。它只需要至少 Java 6。
- 在 Java 8 及更高版本以及更新的 Android 设备(从 API 级别 26 开始)中,内置了现代 API。
- 在非 Android Java 6 和 7 中获得 ThreeTen Backport,现代类的向后移植(ThreeTen for JSR 310;请参阅底部的链接)。
- 在较旧的 Android 上,使用脱糖或 ThreeTen Backport 的 Android 版本。它被称为 ThreeTenABP。在后一种情况下,请确保使用子包从
org.threeten.bp
导入日期和时间类。
链接
- Oracle tutorial: Date Time 解释如何使用 java.time。
-
Java Specification Request (JSR) 310,其中首次描述了
java.time
。 -
ThreeTen Backport project,将
java.time
向后移植到 Java 6 和 7(JSR-310 的 ThreeTen)。 - Java 8+ APIs available through desugaring
- ThreeTenABP,ThreeTen Backport 的 Android 版
- Question: How to use ThreeTenABP in Android Project,非常详尽的解释。