Android long to time
Я хочу вывести изменение текста timer
countDownTimer = object : CountDownTimer(premiumInfo.overTime.time - System.currentTimeMillis(), 1000) {
override fun onTick(p0: Long) {
Log.d("Timer", p0.toString())
val format = SimpleDateFormat("HH:mm:ss")
val timeString = format.format(Date(p0).time)
Log.d("Timer String", timeString)
switch_premium.text = "Премиум [$timeString]"
}
override fun onFinish() {
Log.d("Finish", "true")
switch_premium.text = "Премиум"
context?.let {
Toast.makeText(context, "Обновление данных", Toast.LENGTH_SHORT).show()
}
getProfile()
}
}.start()
Но полученное время на 3 часа больше (думаю это часовой пояс). Мне же нужно без timeZone. Как поправить?
Log
2020-05-13 19:06:19.651 18783-18783/com.app.peshkariki D/Timer: 53349
2020-05-13 19:06:19.656 18783-18783/com.app.peshkariki D/Timer String: 03:00:53
2020-05-13 19:06:20.654 18783-18783/com.app.peshkariki D/Timer: 52346
2020-05-13 19:06:20.659 18783-18783/com.app.peshkariki D/Timer String: 03:00:52
2020-05-13 19:06:21.059 19322-19336/? I/cebook.service: ProcessProfilingInfo new_methods=0 is saved saved_to_disk=0 resolve_classes_delay=8000
2020-05-13 19:06:21.656 18783-18783/com.app.peshkariki D/Timer: 51344
2020-05-13 19:06:21.663 18783-18783/com.app.peshkariki D/Timer String: 03:00:51
2020-05-13 19:06:22.658 18783-18783/com.app.peshkariki D/Timer: 50342
2020-05-13 19:06:22.662 18783-18783/com.app.peshkariki D/Timer String: 03:00:50
Ладно, давайте начнем сначала, может я не туда пошел и все осложнил.
С сервера приходит дата в формате
yyyy-MM-dd HH:mm:ss
Так как Gson не знает как разбираться (а в будущем Room как хранить), приходится писать TypeConverter
class GsonUTCDateAdapter : JsonSerializer<Date?>, JsonDeserializer<Date?> {
private val dateFormat: DateFormat
@Synchronized
override fun serialize(date: Date?, type: Type?, context: JsonSerializationContext?): JsonElement {
return JsonPrimitive(dateFormat.format(date))
}
@Synchronized
override fun deserialize(jsonElement: JsonElement, type: Type?, jsonDeserializationContext: JsonDeserializationContext?): Date {
return try {
dateFormat.parse(jsonElement.asString)
} catch (e: ParseException) {
throw JsonParseException(e)
}
}
init {
dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()) //This is the key line which converts the date to UTC which cannot be accessed with the default serializer
}
}
Таким образом мы приводим к типу Date
data class PremiumInfo(
@SerializedName("is_active") var isActive: Int,
@SerializedName("premium_description") var description: String,
@SerializedName("premium_over_time") var overTime: Date,
@SerializedName("premium_over_timeleft_text") var overTimeLeftText: String
)
Так как CountDownTimer принимает на вход 2 параметра Long (от какого времени, и с какой периодичностью)
Что такое длительность времени? Это разница 2 дат, поэтому я использую пришедшую Date и текущее системное время (так как непонятно в какой timeZone пришло с сервера), произвожу разницу и это время начала (длительность премиум аккаунта) собственно в формате Long.
Каждый Tick время уменьшается на 2 параметр. Теперь осталось Long превратить в Date и получить Time, но при переводе из Long в Date откуда - то взялась разница в 3 часа. Откуда он взялся, ну наверно в SimpleDateFormat. Я посмотрел, там есть есть метод setZone, но зачем мне для продолжительности зона, так ведь? а setZone установить в null нельзя.
Поэтому я и спросил решение. Возможно можно где - то проще сделать, например Joda - Time (там и Period и Duration) использовать, но эта библиотека избытачна , а вес приложения увеличит, поэтому я и спросил, можно как-то по другому сделать стандартными пакетами Java и Kotlin такую простейшую операцию
Ответы (1 шт):
Это не ответ, а скорее разъяснение где в подобных задачах с датами кроются подводные камни.
Компьютерам по сути плевать на часовые пояса, их придумали люди, чтобы с одной стороны себе жизнь облегчить, с другой стороны усложнить, занимаясь расчетами.
С точки зрения ОС Линукс, абсолютное время это System.currentTimeMillis()
the difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.
Т.е. у компьютеров свои боги и это просто сколько миллисекунд прошло с полуночи 1-го января 1970 по Гринвичу.
Вот тут и кроется подводный камень, в последнем слове по Гринвичу. В полночь по Гринвичу в Берлине уже 2:00, а в Москве и того 3:00.
Поэтому когда получаете откуда-то дату и время в "человеческом" формате (текстовом), необходимо всегда при переводе в "компьютерный" формат (бинарный) учитывать "человеческий" часовой пояс.
Иначе всегда (кроме, конечно случаев что вы в зоне UTC+0) будут возникать расхождения, пытаясь их "как-то" решить, будете по факту просто костылить свой код. Костыли как правило перестают работать, когда к простому "сдвигу" во времени еще добавится переход в другую дату.
Поверьте, все это уже решили до вас. Просто пользуйтесь, выставляйте часовой пояс у даты корректно и все будет работать как надо.
Уточнение. Понятие по Гринвичу устарело :) Правильно
UTC – Всемирное координированное время