Дата и час в мобилната разработка: какво е това, какви формати и как се работи

Автор: 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 — backport на 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 са неизменяеми и нишково безопасни, което елиминира race conditions при работа в няколко нишки.

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 — backport на 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 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта