Датум и време у мобилном развоју: шта је то, који формати и како радити

Аутор: IT Sectr Објављено: 2026-07-22 Време читања: 11 мин

Датум и време у мобилном развоју — једна од кључних тема у мобилном инжењерству. iOS користи DateFormatter и ISO8601DateFormatter, Android користи DateTimeFormatter и LocalDate из java.time. Према Android Developer Docs, правилан избор мобилног API-ја за форматирање датума и времена директно утиче на перформансе и исправност приказа у различитим временским зонама.

Главне тачке

  • DateFormatter на iOS-у — моћан, али спор при честом креирању. Кеширајте инстанце или користите ISO8601DateFormatter за формат ISO 8601.
  • DateTimeFormatter на Android-у — нитно безбедан форматирач из java.time. Заменио је застарели SimpleDateFormat од API 26.
  • ThreeTenABP — бекпорт java.time-а за Android API испод 26. Додаје LocalDate, ZonedDateTime и DateTimeFormatter на старим уређајима.
  • TimeZone — критичан за конверзију UTC-а у локално време. Чувајте време у UTC-у, приказујте у временској зони корисника.
  • Unix Timestamp — стандардни формат чувања времена. Синхронизација преко NTP-а гарантује прецизност до милисекунди.

Датум и време на iOS-у: DateFormatter и ISO8601DateFormatter

На iOS-у се датум и време традиционално форматирају путем DateFormatter-а из Foundation-а. Ова класа конвертује Date у низ и назад користећи одређени образац, локал и временску зону. Главни проблем DateFormatter-а — није нитно безбедан и споро се креира, зато се у мобилном коду инстанце обавезно кеширају. Датум у мобилном развоју на iOS-у захтева прави форматирач.

DateFormatter и перформансе

Креирање DateFormatter-а траје око 1 милисекунде због парсирања обрасца dateFormat, учитавања локала и одређивања временске зоне. При форматирању листе од стотина датума, вишеструко креирање доводи до приметних застоја у UI-ју. Решење — креирајте форматирач једном за цео екран и поново га користите. За више нитни приступ користите синхронизацију преко DispatchQueue-а.

swift
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 и DateTimeFormatter

На Android-у се датум и време обрађују преко пакета java.time, доступног од API 26. Главне класе: LocalDate (само датум), LocalTime (само време), LocalDateTime (датум и време без временске зоне) и ZonedDateTime (са временском зоном). DateTimeFormatter — нитно безбедан форматирач за мобилну платформу Android. Датум у мобилним апликацијама се форматира преко DateTimeFormatter-а и LocalDate-а без губитка перформанси.

LocalDate, ZonedDateTime и форматирање

LocalDate чува датум без времена — идеално за рођендане. ZonedDateTime чува комплетне информације са временском зоном. DateTimeFormatter подржава унапред дефинисане обрасце (ISO_LOCAL_DATE, ISO_DATE_TIME) и прилагођене преко ofPattern. Све класе java.time-а су непроменљиве и нитно безбедне, што елиминише тркачке услове при раду у више нити.

kotlin
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 преко временске зоне.

Временске зоне: датум и време у мобилним апликацијама и TimeZone

Тачан датум и време на екрану корисника зависе од правилне обраде временских зона. Датум и време у мобилном развоју за Android захтева узимање у обзир временске зоне уређаја. Златно правило: чувајте време у UTC-у, конвертујте у локалну временску зону само за приказ. iOS пружа TimeZone из Foundation-а, Android пружа ZoneId из java.time-а. Оба API-ја за мобилне платформе подржавају аутоматско откривање тренутне временске зоне уређаја. Датум у мобилној апликацији зависи од ZoneId-а и TimeZone-а.

Летње рачунање времена и IANA идентификатори

Летње рачунање времена ствара недоследност: један тренутак у времену може бити представљен са два различита локална времена. java.time и Foundation аутоматски обрађују DST. Користите IANA идентификаторе (Europe/Moscow, America/New_York), а не скраћенице (MSK, EST) — скраћенице су недоследне и игноришу прелазак на летње рачунање времена.

swift
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.

kotlin
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 — датум и време за старе верзије Android-а

ThreeTenABP — библиотека-адаптер која преноси java.time на Android API испод 26. Пружа исте класе: LocalDate, LocalTime, ZonedDateTime, DateTimeFormatter, Instant. Ако апликација подржава Android 5 или 6 (API 21-25), ThreeTenABP је једини начин да користите савремени мобилни API без преласка на застарели Calendar. Датум и време у мобилном развоју за старе уређаје имплементирани су преко ове библиотеке. За старе уређаје датум и време су имплементирани преко ThreeTenABP-а.

Додавање и подешавање ThreeTenABP-а

Библиотека захтева иницијализацију у методи Application.onCreate() позивом AndroidThreeTen.init(). Ово учитава податке о временским зонама из assets-а. Након иницијализације API је потпуно идентичан java.time-у — код за API 26+ и за API 21+ биће исти. Величина библиотеке је око 400 KB, што је прихватљиво за већину мобилних апликација.

kotlin
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 и синхронизација времена преко NTP-а

Unix Timestamp — број секунди протеклих од 1. јануара 1970. 00:00 UTC. Ово је универзални формат за чување и размену времена између сервера и клијента. Међутим, време на уређају може се разликовати од стварног због подешавања корисника. За синхронизацију се користи NTP — протокол тачног времена преко UDP-а. Unix Timestamp је формат у коме се датум и време чувају на серверу.

Добијање Unix Timestamp-а и NTP синхронизација

Date().timeIntervalSince1970 на iOS-у враћа секунде од 1970. године. На Android-у System.currentTimeMillis() враћа милисекунде. За прецизност користите NTP: библиотека TrueTime за iOS и AndroidNtp за Android шаљу захтев NTP серверу и израчунавају временски помак. Прецизност NTP-а је 1-10 ms у локалној мрежи и 10-100 ms преко интернета.

swift
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 спор на iOS-у?

DateFormatter парсира образац форматирања, учитава локал и одређује временску зону при сваком креирању инстанце. Кеширајте форматирач као статичку константу или користите ISO8601DateFormatter за ISO 8601 — лакши је и бржи.

Шта користити уместо SimpleDateFormat-а на Android-у?

DateTimeFormatter из пакета java.time — нитно безбедан и перформантан. Доступан од API 26. За старије верзије користите ThreeTenABP који пружа идентичан API.

Како радити са датумима пре Java 8 на Android-у?

Додајте ThreeTenABP — бекпорт java.time-а за Android API 21+. Иницијализација преко AndroidThreeTen.init() у Application.onCreate(). API је потпуно идентичан оригиналном java.time-у.

Да ли треба чувати време у UTC-у?

Да, чувајте време у UTC-у на серверу и у локалној бази података. Конвертујте у локалну временску зону корисника само у фази приказа. Ово елиминише грешке при промени временске зоне или путовањима.

Како добити Unix Timestamp на iOS-у?

Date().timeIntervalSince1970 враћа број секунди од 1. јануара 1970. За милисекунде помножите са 1000 и конвертујте у Int64. За прецизну синхронизацију користите библиотеку TrueTime са NTP сервером.

Резиме

  • DateFormatter на iOS-у — главни алат за форматирање датума и времена, захтева обавезно кеширање инстанци. ISO8601DateFormatter је лакша алтернатива за ISO 8601.
  • DateTimeFormatter на Android-у — нитно безбедан форматирач из java.time-а за API 26+. LocalDate и ZonedDateTime су главне класе за рад са датумима.
  • ThreeTenABP — јединствени API за све верзије Android-а. Додајте за уназад компатибилност са API 21-25. Код се не разликује од java.time-а.
  • TimeZone и UTC — чувајте време у UTC-у, конвертујте у локалну временску зону само за приказ. Користите IANA идентификаторе.
  • Unix Timestamp — универзални формат за размену времена између сервера и клијента. Добијајте преко Date().timeIntervalSince1970 на iOS-у.
  • NTP синхронизација — обезбеђује прецизност времена до милисекунди. TrueTime (iOS) и AndroidNtp (Android) су стандардне библиотеке.

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту