Датум и време у мобилном развоју — једна од кључних тема у мобилном инжењерству. iOS користи DateFormatter и ISO8601DateFormatter, Android користи DateTimeFormatter и LocalDate из java.time. Према Android Developer Docs, правилан избор мобилног API-ја за форматирање датума и времена директно утиче на перформансе и исправност приказа у различитим временским зонама.
Главне тачке
На iOS-у се датум и време традиционално форматирају путем DateFormatter-а из Foundation-а. Ова класа конвертује Date у низ и назад користећи одређени образац, локал и временску зону. Главни проблем DateFormatter-а — није нитно безбедан и споро се креира, зато се у мобилном коду инстанце обавезно кеширају. Датум у мобилном развоју на iOS-у захтева прави форматирач.
Креирање DateFormatter-а траје око 1 милисекунде због парсирања обрасца dateFormat, учитавања локала и одређивања временске зоне. При форматирању листе од стотина датума, вишеструко креирање доводи до приметних застоја у UI-ју. Решење — креирајте форматирач једном за цео екран и поново га користите. За више нитни приступ користите синхронизацију преко DispatchQueue-а.
import Foundation
// Кеширан DateFormatter — креира се једном
private let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "dd.MM.yyyy HH:mm"
formatter.locale = Locale(identifier: "ru_RU")
formatter.timeZone = TimeZone(identifier: "Europe/Moscow")
return formatter
}()
// ISO8601DateFormatter — лака алтернатива
private let isoFormatter: ISO8601DateFormatter = {
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
return formatter
}()
let now = Date()
let formattedDate = dateFormatter.string(from: now)
// "01.07.2026 14:30"
let isoDate = isoFormatter.string(from: now)
// "2026-07-01T14:30:00.000Z"
За формат ISO 8601 користите ISO8601DateFormatter — не захтева навођење обрасца и ради брже од DateFormatter-а. На iOS 10+ ова класа је пожељнија за рад са серверским датумима. За старе формате задржите DateFormatter, али обавезно кеширајте инстанцу као статичко својство или синглтон.
На Android-у се датум и време обрађују преко пакета java.time, доступног од API 26. Главне класе: LocalDate (само датум), LocalTime (само време), LocalDateTime (датум и време без временске зоне) и ZonedDateTime (са временском зоном). DateTimeFormatter — нитно безбедан форматирач за мобилну платформу Android. Датум у мобилним апликацијама се форматира преко DateTimeFormatter-а и LocalDate-а без губитка перформанси.
LocalDate чува датум без времена — идеално за рођендане. ZonedDateTime чува комплетне информације са временском зоном. DateTimeFormatter подржава унапред дефинисане обрасце (ISO_LOCAL_DATE, ISO_DATE_TIME) и прилагођене преко ofPattern. Све класе java.time-а су непроменљиве и нитно безбедне, што елиминише тркачке услове при раду у више нити.
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.time.ZoneId
// Креирање и форматирање тренутног датума
val today = LocalDate.now()
val formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy")
val formatted = today.format(formatter)
// Рад са временским зонама
val utcTime = ZonedDateTime.now(ZoneId.of("UTC"))
val moscowTime = utcTime.withZoneSameInstant(ZoneId.of("Europe/Moscow"))
DateTimeFormatter је знатно перформантнији од SimpleDateFormat-а јер не парсира образац при сваком позиву. Препоручује се креирање константи форматирача на нивоу класе или објекта-пратиоца. За конверзију Unix Timestamp-а користите Instant.ofEpochSecond, затим конвертујте у LocalDateTime или ZonedDateTime преко временске зоне.
Тачан датум и време на екрану корисника зависе од правилне обраде временских зона. Датум и време у мобилном развоју за Android захтева узимање у обзир временске зоне уређаја. Златно правило: чувајте време у UTC-у, конвертујте у локалну временску зону само за приказ. iOS пружа TimeZone из Foundation-а, Android пружа ZoneId из java.time-а. Оба API-ја за мобилне платформе подржавају аутоматско откривање тренутне временске зоне уређаја. Датум у мобилној апликацији зависи од ZoneId-а и TimeZone-а.
Летње рачунање времена ствара недоследност: један тренутак у времену може бити представљен са два различита локална времена. java.time и Foundation аутоматски обрађују DST. Користите IANA идентификаторе (Europe/Moscow, America/New_York), а не скраћенице (MSK, EST) — скраћенице су недоследне и игноришу прелазак на летње рачунање времена.
import Foundation
// Конверзија UTC-а у локално време на iOS-у
func formatToLocalTime(utcDate: Date, timeZoneId: String) -> String {
let formatter = DateFormatter()
formatter.dateFormat = "dd.MM.yyyy HH:mm"
formatter.timeZone = TimeZone(identifier: timeZoneId)
return formatter.string(from: utcDate)
}
// Одређивање временске зоне уређаја
let localTimeZone = TimeZone.current
let isDST = localTimeZone.isDaylightSavingTime()
let secondsFromGMT = localTimeZone.secondsFromGMT()
На Android-у користите ZoneId.systemDefault() за добијање временске зоне уређаја. При конверзији UTC-а у локално време креирајте ZonedDateTime са ZoneOffset.UTC и примените withZoneSameInstant. За стара API-ја без java.time-а користите TimeZone.getDefault() и Calendar — али боље је одмах додати ThreeTenABP.
import java.time.Instant
import java.time.ZonedDateTime
import java.time.ZoneId
// Конвертуј Unix Timestamp у локално време
fun toLocalDisplay(unixSeconds: Long): String {
val instant = Instant.ofEpochSecond(unixSeconds)
val local = instant.atZone(ZoneId.systemDefault())
return local.format(DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm"))
}
ThreeTenABP — библиотека-адаптер која преноси java.time на Android API испод 26. Пружа исте класе: LocalDate, LocalTime, ZonedDateTime, DateTimeFormatter, Instant. Ако апликација подржава Android 5 или 6 (API 21-25), ThreeTenABP је једини начин да користите савремени мобилни API без преласка на застарели Calendar. Датум и време у мобилном развоју за старе уређаје имплементирани су преко ове библиотеке. За старе уређаје датум и време су имплементирани преко ThreeTenABP-а.
Библиотека захтева иницијализацију у методи Application.onCreate() позивом AndroidThreeTen.init(). Ово учитава податке о временским зонама из assets-а. Након иницијализације API је потпуно идентичан java.time-у — код за API 26+ и за API 21+ биће исти. Величина библиотеке је око 400 KB, што је прихватљиво за већину мобилних апликација.
import org.threeten.bp.LocalDate
import org.threeten.bp.format.DateTimeFormatter
// Иницијализација у Application-у
class App : Application() {
override fun onCreate() {
super.onCreate()
AndroidThreeTen.init(this)
}
}
// API је идентичан java.time-у
val today = LocalDate.now()
val formatted = today.format(DateTimeFormatter.ISO_LOCAL_DATE)
Перформансе ThreeTenABP-а су упоредиве са оригиналним java.time-ом на савременим уређајима. На старим уређајима могуће је кашњење при првом позиву због учитавања података о временским зонама. Мигрирајте постојећи код са Calendar-а на ThreeTenABP постепено: замењујте Date и Calendar са Instant и LocalDate у новим модулима, остављајући стари код непромењеним.
Unix Timestamp — број секунди протеклих од 1. јануара 1970. 00:00 UTC. Ово је универзални формат за чување и размену времена између сервера и клијента. Међутим, време на уређају може се разликовати од стварног због подешавања корисника. За синхронизацију се користи NTP — протокол тачног времена преко UDP-а. Unix Timestamp је формат у коме се датум и време чувају на серверу.
Date().timeIntervalSince1970 на iOS-у враћа секунде од 1970. године. На Android-у System.currentTimeMillis() враћа милисекунде. За прецизност користите NTP: библиотека TrueTime за iOS и AndroidNtp за Android шаљу захтев NTP серверу и израчунавају временски помак. Прецизност NTP-а је 1-10 ms у локалној мрежи и 10-100 ms преко интернета.
import Foundation
// Добијање Unix Timestamp-а на iOS-у
let seconds = Date().timeIntervalSince1970
let milliseconds = Int64(seconds * 1000)
// NTP синхронизација са TrueTime-ом
TrueTime.shared.start { result in
switch result {
case .success:
let ntpTime = TrueTime.shared.now()
print("Тачно време: \(ntpTime)")
case .failure(let error):
print("NTP грешка: \(error)")
}
}
Без синхронизације у мобилној апликацији могуће су грешке: нетачне ознаке догађаја, десинхронизација са сервером. Време у мобилном развоју синхронизује се преко NTP-а једнократно при покретању апликације, након чега се користи израчунати помак. За критичне мобилне апликације (финансије, логистика) NTP протокол је обавезан пре слања података на сервер.
Често постављана питања
DateFormatter парсира образац форматирања, учитава локал и одређује временску зону при сваком креирању инстанце. Кеширајте форматирач као статичку константу или користите ISO8601DateFormatter за ISO 8601 — лакши је и бржи.
DateTimeFormatter из пакета java.time — нитно безбедан и перформантан. Доступан од API 26. За старије верзије користите ThreeTenABP који пружа идентичан API.
Додајте ThreeTenABP — бекпорт java.time-а за Android API 21+. Иницијализација преко AndroidThreeTen.init() у Application.onCreate(). API је потпуно идентичан оригиналном java.time-у.
Да, чувајте време у UTC-у на серверу и у локалној бази података. Конвертујте у локалну временску зону корисника само у фази приказа. Ово елиминише грешке при промени временске зоне или путовањима.
Date().timeIntervalSince1970 враћа број секунди од 1. јануара 1970. За милисекунде помножите са 1000 и конвертујте у Int64. За прецизну синхронизацију користите библиотеку TrueTime са NTP сервером.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.