Data i czas w rozwoju mobilnym: co to jest, jakie formaty i jak pracować

Autor: IT Sectr Opublikowano: 2026-07-22 Czas czytania: 11 min

Data i czas w rozwoju mobilnym — jeden z kluczowych tematów w inżynierii mobilnej. iOS używa DateFormatter i ISO8601DateFormatter, Android używa DateTimeFormatter i LocalDate z java.time. Według Android Developer Docs, prawidłowy wybór mobilnego API do formatowania daty i czasu bezpośrednio wpływa na wydajność i poprawność wyświetlania w różnych strefach czasowych.

Najważniejsze

  • DateFormatter na iOS — potężny, ale wolny przy częstym tworzeniu. Buforuj instancje lub używaj ISO8601DateFormatter dla formatu ISO 8601.
  • DateTimeFormatter na Androidzie — bezpieczny wątkowo formater z java.time. Zastąpił przestarzały SimpleDateFormat od API 26.
  • ThreeTenABP — backport java.time dla Android API poniżej 26. Dodaje LocalDate, ZonedDateTime i DateTimeFormatter na starych urządzeniach.
  • TimeZone — krytyczny dla konwersji UTC na czas lokalny. Przechowuj czas w UTC, wyświetlaj w strefie czasowej użytkownika.
  • Unix Timestamp — standardowy format przechowywania czasu. Synchronizacja przez NTP gwarantuje dokładność do milisekund.

Data i czas na iOS: DateFormatter i ISO8601DateFormatter

Na iOS data i czas są tradycyjnie formatowane przez DateFormatter z Foundation. Ta klasa konwertuje Date na ciąg znaków i z powrotem, używając określonego wzorca, ustawień regionalnych i strefy czasowej. Główny problem DateFormatter — nie jest bezpieczny wątkowo i jest wolny w tworzeniu, więc w kodzie mobilnym instancje muszą być buforowane. Data w rozwoju mobilnym na iOS wymaga odpowiedniego formatera.

DateFormatter i wydajność

Utworzenie DateFormatter zajmuje około 1 milisekundy z powodu parsowania wzorca dateFormat, ładowania ustawień regionalnych i określania strefy czasowej. Podczas formatowania listy setek dat wielokrotne tworzenie prowadzi do zauważalnych opóźnień w interfejsie użytkownika. Rozwiązanie — utwórz formater raz dla całego ekranu i używaj go ponownie. Do dostępu wielowątkowego używaj synchronizacji przez DispatchQueue.

swift
import Foundation

// Zbuforowany DateFormatter — tworzony raz
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 — lekka alternatywa
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"

Dla formatu ISO 8601 używaj ISO8601DateFormatter — nie wymaga określania wzorca i działa szybciej niż DateFormatter. Na iOS 10+ ta klasa jest preferowana do pracy z datami serwerowymi. Dla starych formatów pozostaw DateFormatter, ale pamiętaj o buforowaniu instancji jako statycznej właściwości lub singletona.

Data i czas na Androidzie: java.time i DateTimeFormatter

Na Androidzie data i czas są obsługiwane przez pakiet java.time, dostępny od API 26. Główne klasy: LocalDate (tylko data), LocalTime (tylko czas), LocalDateTime (data i czas bez strefy czasowej) i ZonedDateTime (ze strefą czasową). DateTimeFormatter — bezpieczny wątkowo formater dla platformy mobilnej Android. Data w aplikacjach mobilnych jest formatowana przez DateTimeFormatter i LocalDate bez utraty wydajności.

LocalDate, ZonedDateTime i formatowanie

LocalDate przechowuje datę bez czasu — idealne do urodzin. ZonedDateTime przechowuje pełne informacje ze strefą czasową. DateTimeFormatter obsługuje predefiniowane wzorce (ISO_LOCAL_DATE, ISO_DATE_TIME) i niestandardowe przez ofPattern. Wszystkie klasy java.time są niezmienne i bezpieczne wątkowo, co eliminuje warunki wyścigu podczas pracy w wielu wątkach.

kotlin
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.time.ZoneId

// Tworzenie i formatowanie bieżącej daty
val today = LocalDate.now()
val formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy")
val formatted = today.format(formatter)

// Praca ze strefami czasowymi
val utcTime = ZonedDateTime.now(ZoneId.of("UTC"))
val moscowTime = utcTime.withZoneSameInstant(ZoneId.of("Europe/Moscow"))

DateTimeFormatter jest znacznie wydajniejszy niż SimpleDateFormat, ponieważ nie parsuje wzorca przy każdym wywołaniu. Zaleca się tworzenie stałych formatera na poziomie klasy lub obiektu towarzyszącego. Do konwersji Unix Timestamp używaj Instant.ofEpochSecond, a następnie konwertuj na LocalDateTime lub ZonedDateTime przez strefę czasową.

Strefy czasowe: data i czas w aplikacjach mobilnych i TimeZone

Prawidłowa data i czas na ekranie użytkownika zależą od poprawnego obsługiwania stref czasowych. Data i czas w rozwoju mobilnym dla Androida wymaga uwzględnienia strefy czasowej urządzenia. Złota zasada: przechowuj czas w UTC, konwertuj do lokalnej strefy czasowej tylko do wyświetlania. iOS udostępnia TimeZone z Foundation, Android udostępnia ZoneId z java.time. Oba API dla platform mobilnych obsługują automatyczne wykrywanie bieżącej strefy czasowej urządzenia. Data w aplikacji mobilnej zależy od ZoneId i TimeZone.

Czas letni i identyfikatory IANA

Czas letni tworzy niejednoznaczność: jeden moment w czasie może być reprezentowany przez dwa różne lokalne czasy. java.time i Foundation obsługują DST automatycznie. Używaj identyfikatorów IANA (Europe/Moscow, America/New_York), a nie skrótów (MSK, EST) — skróty są niejednoznaczne i ignorują przejście na czas letni.

swift
import Foundation

// Konwersja UTC na czas lokalny na 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)
}

// Określanie strefy czasowej urządzenia
let localTimeZone = TimeZone.current
let isDST = localTimeZone.isDaylightSavingTime()
let secondsFromGMT = localTimeZone.secondsFromGMT()

Na Androidzie używaj ZoneId.systemDefault() aby uzyskać strefę czasową urządzenia. Podczas konwersji UTC na czas lokalny twórz ZonedDateTime z ZoneOffset.UTC i stosuj withZoneSameInstant. Dla starych API bez java.time używaj TimeZone.getDefault() i Calendar — ale lepiej od razu dodać ThreeTenABP.

kotlin
import java.time.Instant
import java.time.ZonedDateTime
import java.time.ZoneId

// Konwertuj Unix Timestamp na czas lokalny
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 — data i czas dla starych wersji Androida

ThreeTenABP — biblioteka adaptera, która przenosi java.time na Android API poniżej 26. Zapewnia te same klasy: LocalDate, LocalTime, ZonedDateTime, DateTimeFormatter, Instant. Jeśli aplikacja obsługuje Androida 5 lub 6 (API 21-25), ThreeTenABP to jedyny sposób na używanie nowoczesnego mobilnego API bez przechodzenia na przestarzały Calendar. Data i czas w rozwoju mobilnym dla starych urządzeń są zaimplementowane przez tę bibliotekę. Dla starych urządzeń data i czas są zaimplementowane przez ThreeTenABP.

Dodawanie i konfiguracja ThreeTenABP

Biblioteka wymaga inicjalizacji w metodzie Application.onCreate() przez wywołanie AndroidThreeTen.init(). To ładuje dane stref czasowych z assets. Po inicjalizacji API jest w pełni identyczne z java.time — kod dla API 26+ i dla API 21+ będzie taki sam. Rozmiar biblioteki wynosi około 400 KB, co jest akceptowalne dla większości aplikacji mobilnych.

kotlin
import org.threeten.bp.LocalDate
import org.threeten.bp.format.DateTimeFormatter

// Inicjalizacja w Application
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        AndroidThreeTen.init(this)
    }
}

// API jest identyczne z java.time
val today = LocalDate.now()
val formatted = today.format(DateTimeFormatter.ISO_LOCAL_DATE)

Wydajność ThreeTenABP jest porównywalna z oryginalnym java.time na nowoczesnych urządzeniach. Na starych urządzeniach możliwe jest opóźnienie przy pierwszym wywołaniu z powodu ładowania danych stref czasowych. Migruj istniejący kod z Calendar do ThreeTenABP stopniowo: zastępuj Date i Calendar Instant i LocalDate w nowych modułach, pozostawiając stary kod bez zmian.

Unix Timestamp i synchronizacja czasu przez NTP

Unix Timestamp — liczba sekund, które upłynęły od 1 stycznia 1970 00:00 UTC. To uniwersalny format przechowywania i wymiany czasu między serwerem a klientem. Jednak czas na urządzeniu może różnić się od rzeczywistego z powodu ustawień użytkownika. Do synchronizacji używany jest NTP — protokół precyzyjnego czasu przez UDP. Unix Timestamp to format, w którym data i czas są przechowywane na serwerze.

Pobieranie Unix Timestamp i synchronizacja NTP

Date().timeIntervalSince1970 na iOS zwraca sekundy od 1970 roku. Na Androidzie System.currentTimeMillis() zwraca milisekundy. Dla dokładności używaj NTP: biblioteka TrueTime dla iOS i AndroidNtp dla Androida wysyłają zapytanie do serwera NTP i obliczają przesunięcie czasu. Dokładność NTP wynosi 1-10 ms w sieci lokalnej i 10-100 ms przez internet.

swift
import Foundation

// Pobieranie Unix Timestamp na iOS
let seconds = Date().timeIntervalSince1970
let milliseconds = Int64(seconds * 1000)

// Synchronizacja NTP z TrueTime
TrueTime.shared.start { result in
    switch result {
    case .success:
        let ntpTime = TrueTime.shared.now()
        print("Dokładny czas: \(ntpTime)")
    case .failure(let error):
        print("Błąd NTP: \(error)")
    }
}

Bez synchronizacji w aplikacji mobilnej możliwe są błędy: nieprawidłowe znaczniki czasu zdarzeń, desynchronizacja z serwerem. Czas w rozwoju mobilnym jest synchronizowany przez NTP jednorazowo przy starcie aplikacji, po czym używane jest obliczone przesunięcie. Dla krytycznych pod względem dokładności aplikacji mobilnych (finanse, logistyka) protokół NTP jest obowiązkowy przed wysłaniem danych na serwer.

Często zadawane pytania

Dlaczego DateFormatter jest wolny na iOS?

DateFormatter parsuje wzorzec formatowania, ładuje ustawienia regionalne i określa strefę czasową przy każdym tworzeniu instancji. Buforuj formater jako stałą statyczną lub używaj ISO8601DateFormatter dla ISO 8601 — jest lżejszy i szybszy.

Czego użyć zamiast SimpleDateFormat na Androidzie?

DateTimeFormatter z pakietu java.time — bezpieczny wątkowo i wydajny. Dostępny od API 26. Dla starszych wersji używaj ThreeTenABP, który zapewnia identyczne API.

Jak pracować z datami sprzed Java 8 na Androidzie?

Dodaj ThreeTenABP — backport java.time dla Android API 21+. Inicjalizacja przez AndroidThreeTen.init() w Application.onCreate(). API jest w pełni identyczne z oryginalnym java.time.

Czy należy przechowywać czas w UTC?

Tak, przechowuj czas w UTC na serwerze i w lokalnej bazie danych. Konwertuj do lokalnej strefy czasowej użytkownika tylko na etapie wyświetlania. Eliminuje to błędy przy zmianie strefy czasowej lub podróżach.

Jak uzyskać Unix Timestamp na iOS?

Date().timeIntervalSince1970 zwraca liczbę sekund od 1 stycznia 1970 roku. Dla milisekund pomnóż przez 1000 i przekonwertuj na Int64. Do precyzyjnej synchronizacji używaj biblioteki TrueTime z serwerem NTP.

Podsumowanie

  • DateFormatter na iOS — główne narzędzie do formatowania daty i czasu, wymaga obowiązkowego buforowania instancji. ISO8601DateFormatter to lżejsza alternatywa dla ISO 8601.
  • DateTimeFormatter na Androidzie — bezpieczny wątkowo formater z java.time dla API 26+. LocalDate i ZonedDateTime to główne klasy do pracy z datami.
  • ThreeTenABP — ujednolicone API dla wszystkich wersji Androida. Dodaj dla wstecznej kompatybilności z API 21-25. Kod nie różni się od java.time.
  • TimeZone i UTC — przechowuj czas w UTC, konwertuj do lokalnej strefy czasowej tylko do wyświetlania. Używaj identyfikatorów IANA.
  • Unix Timestamp — uniwersalny format wymiany czasu między serwerem a klientem. Uzyskaj przez Date().timeIntervalSince1970 na iOS.
  • Synchronizacja NTP — zapewnia dokładność czasu do milisekund. TrueTime (iOS) i AndroidNtp (Android) to standardowe biblioteki.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt