Date — это структура Foundation, представляющая конкретный момент времени независимо от календаря и часового пояса. Тип хранит количество секунд, прошедших с контрольной даты 1 января 2001 года (reference date), и обеспечивает базовые операции сравнения и вычисления временных интервалов. По данным Apple Developer Documentation (2025), Date используется во всех фреймворках Apple: от UIKit и SwiftUI до CloudKit и Core Data. Понимание работы Date обязательно для любого iOS-разработчика, поскольку без него невозможно управлять временем в приложении.
Главное
Date — это value-тип из фреймворка Foundation, который фиксирует один абсолютный момент времени. В отличие от календарных представлений (год, месяц, день), Date не зависит от часового пояса и календарной системы — это чисто числовое значение временной метки.
Внутреннее представление Date — это TimeInterval (псевдоним для Double), хранящий количество секунд относительно reference date — 1 января 2001 года 00:00:00 UTC. Apple выбрала эту дату, а не Unix epoch (1970 год), для совместимости со старыми системами NeXTSTEP, на основе которого построены iOS и macOS.
Date используется как стандартный тип времени во всех API Apple: UIDatePicker, DatePicker, UserDefaults, Codable, Core Data, CloudKit. Без Date невозможно работать с расписаниями, таймерами, событиями календаря, сериализацией данных и любыми операциями, связанными со временем.
Date отличается от календарных типов тем, что представляет физическую метку времени, а не человекочитаемое значение. Один и тот же Date может соответствовать разным календарным датам в разных часовых поясах. Для получения компонентов (год, месяц, день) Date преобразуется через Calendar и DateComponents.
Date также отличается от DispatchTime, который используется для диспетчеризации задач в Grand Central Dispatch. DispatchTime относителен к моменту запуска системы, в то время как Date — абсолютная метка, которую можно сохранять, передавать и восстанавливать.
Date() — это самый простой способ создать объект с текущим моментом времени. Инициализатор без аргументов возвращает точное время вызова. Для создания даты в прошлом или будущем используются TimeInterval и метод addingTimeInterval, либо инициализация от существующего Date.
Для создания произвольной даты из компонентов используется связка Calendar и DateComponents. Calendar преобразует человекочитаемые компоненты (год, месяц, день, час, минута) в Date. Также можно инициализировать Date через ISO8601DateFormatter из строки в формате ISO 8601 или через DateFormatter из произвольного строкового представления.
Date.distantPast и Date.distantFuture — два статических свойства, представляющих бесконечно удалённые моменты прошлого и будущего. Они используются как граничные значения при фильтрации и сортировке дат в алгоритмах.
import Foundation
// Sozdanie Date s tekushchim vremenem
let now = Date()
print("Current time: \(now)")
// Data cherez 1 chas (3600 sekund)
let inOneHour = now.addingTimeInterval(3600)
// Data iz komponentov
var components = DateComponents()
components.year = 2025
components.month = 12
components.day = 25
let christmas = Calendar.current.date(from: components)!
В примере показаны три способа создания Date: текущее время, добавление интервала и создание через DateComponents. Все три подхода возвращают значение типа Date с точностью до миллисекунды. Calendar.current использует системный календарь пользователя — на устройствах Apple это обычно григорианский календарь.
TimeInterval — это псевдоним для Double, представляющий количество секунд между двумя моментами времени. Точность TimeInterval достигает долей миллисекунды, что достаточно для большинства прикладных задач. Отрицательное значение TimeInterval указывает на прошлое относительно точки отсчёта.
Date поддерживает все стандартные операторы сравнения: ==, <, >, <=, >=. Swift автоматически сравнивает внутренние TimeInterval значений. Метод compare возвращает ComparisonResult с вариантами .orderedSame, .orderedAscending, .orderedDescending для более явного сравнения.
Date.distance(to:) — метод, возвращающий TimeInterval до указанной даты. Если целевая дата в прошлом, результат отрицательный. advanced(by:) создаёт новую дату, добавляя указанный TimeInterval к текущей. Эти методы реализуют протокол Strideable, позволяя использовать Date в диапазонах Range и ClosedRange.
let start = Date()
let end = start.addingTimeInterval(86400)
// Sravnenie cherez operatory
if start < end {
print("start is earlier")
}
// TimeInterval mezhdu dvumya datami
let interval: TimeInterval = end.timeIntervalSince(start)
print("Seconds: \(Int(interval / 60)) minutes")
// Using Date in range
let range = start...end
let mid = start.addingTimeInterval(43200)
if range.contains(mid) {
print("mid is between start and end")
}
TimeInterval в 86400 соответствует одним суткам. Для более сложных интервалов — недель, месяцев, лет — используйте Calendar и DateComponents, так как эти единицы имеют переменную длину (високосные года, переход на летнее время). TimeInterval применим только для фиксированных промежутков в секундах.
Calendar — это мост между Date и человекочитаемыми компонентами. Calendar преобразует Date в DateComponents (год, месяц, день, час, минута, секунда) с учётом часового пояса и локали. Без Calendar невозможно извлечь из Date год или месяц — Date не содержит этой информации из-за своей абсолютной природы.
Метод Calendar.component извлекает один компонент из Date: год, месяц, день, час, минута, секунда, weekday, quarter. Метод Calendar.dateComponents извлекает набор компонентов за один вызов — это эффективнее, чем вызывать component для каждого поля отдельно.
Calendar.isDateInToday, isDateInTomorrow, isDateInYesterday — удобные методы проверки относительных дат. Calendar.dateInterval возвращает начало и конец указанного периода (день, неделя, месяц, год). Calendar.compare сравнивает даты с точностью до указанного компонента — например, год без учёта месяца и дня.
let calendar = Calendar.current
// Izvlechenie komponentov
let year = calendar.component(.year, from: Date())
let month = calendar.component(.month, from: Date())
// Check relative date
if calendar.isDateInToday(someDate) {
print("Today!")
}
// Nachalo i konets dnya
let dayInterval = calendar.dateInterval(of: .day, for: Date())!
print("Day start: \(dayInterval.start)")
print("Day end: \(dayInterval.end)")
Calendar.current использует системные настройки пользователя — календарь, часовой пояс и локаль. Для тестирования или специфических расчётов можно создать Calendar с конкретными параметрами через Calendar(identifier: .gregorian) и установить нужный TimeZone через свойство timeZone.
DateFormatter — обязательный компонент, если Date нужно отобразить пользователю. DateFormatter преобразует Date в строку по заданному формату и локали. Прямое преобразование Date в строку через String(describing:) возвращает техническое представление с reference date и TimeInterval — оно не предназначено для пользователя.
Базовый подход — использование предустановленных стилей dateStyle и timeStyle. iOS поддерживает четыре стиля: .short, .medium, .long, .full. Комбинация стилей даты и времени позволяет гибко настроить отображение. ДатаFormatter автоматически применяет локализацию: для русской локали дата отобразится в формате "21 июля 2026 г.".
ISO8601DateFormatter — специализированный форматтер для ISO 8601, наиболее распространённого формата для API и обмена данными. Этот форматтер работает быстрее DateFormatter и не зависит от локали, что делает его предпочтительным для сериализации дат в JSON.
// Predustanovlennye stili
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
let userString = formatter.string(from: Date())
// ISO 8601 dlya API
let isoFormatter = ISO8601DateFormatter()
let apiString = isoFormatter.string(from: Date())
// Parsing iz stroki
let parsed = isoFormatter.date(from: "2026-07-21T10:30:00Z")!
При работе с DateFormatter важно помнить о производительности: создание нового форматтера — дорогая операция. Рекомендуется кэшировать форматтер или создать его один раз и переиспользовать. В свойствах форматтера можно настроить timeZone — по умолчанию используется системный часовой пояс, но для серверных дат часто требуется TimeZone(identifier: "UTC").
Рассмотрим типовые сценарии работы с Date в iOS-приложении. Первый сценарий — расчёт возраста пользователя из даты рождения. Второй — таймер обратного отсчёта до события. Третий — группировка записей по дате для отображения в виде секций таблицы.
Calendar.dateComponents с флагом [.year] вычисляет разницу между двумя датами. Установка правильного часового пояса критически важна — если не указать timeZone в Calendar, результат может отличаться на день из-за перехода через полночь в другом часовом поясе.
func calculateAge(from birthDate: Date) -> Int {
let calendar = Calendar.current
let now = Date()
let components = calendar.dateComponents(
[.year], from: birthDate, to: now
)
return components.year ?? 0
}
Таймер обратного отсчёта реализуется через TimeInterval. Вычисляем разницу между целевой датой и текущей, получаем остаток в секундах и преобразуем в дни, часы, минуты. Для регулярного обновления используется Timer с интервалом 1 секунда. ObservableObject с @Published свойством позволяет SwiftUI автоматически обновлять интерфейс.
Группировка по дате реализуется через словарь с ключом Date. Calendar.dateInterval(of: .day, for:) нормализует дату до начала дня, что позволяет сгруппировать записи, относящиеся к одному дню. Тот же подход работает для недель, месяцев и лет — достаточно изменить компонент в dateInterval на .weekOfYear или .month.
| Сценарий | Ключевой API | Особенность |
|---|---|---|
| Расчёт возраста | Calendar.dateComponents | Учесть timeZone |
| Обратный отсчёт | Date.timeIntervalSince | Timer+Combine |
| Группировка дат | Calendar.dateInterval | Нормализация до дня |
| Сериализация JSON | ISO8601DateFormatter | Locale не влияет |
Часто задаваемые вопросы
Date — это внутреннее представление времени без привязки к календарю и локали. Строка — это форматированное отображение, зависимое от настроек пользователя. Date можно сравнивать, сериализовать и математически обрабатывать со стопроцентной точностью, строковое представление всегда требует парсинга через форматтер.
Date — это абсолютная метка времени (количество секунд от reference date), которая не зависит от часового пояса. Часовой пояс — это контекст отображения. Тот же Date в UTC и в Москве представляет один и тот же физический момент, но отображается как разное календарное время.
Date напрямую поддерживается Core Data как тип атрибута. Core Data автоматически сериализует Date в хранилище. Для запросов с фильтрацией по дате используйте NSPredicate с операторами сравнения — Core Data корректно обрабатывает timezone на уровне SQLite.
CFAbsoluteTime — это Core Foundation тип, использующий ту же reference date (1 января 2001). Date и CFAbsoluteTime взаимозаменяемы через прямое преобразование. Date(timeIntervalSinceReferenceDate:) принимает CFAbsoluteTime, и Date.timeIntervalSinceReferenceDate возвращает CFAbsoluteTime.
Date имеет точность до миллисекунды, но не гарантирует наносекундную точность из-за аппаратных ограничений iOS/macOS. Для высокоточных измерений используйте mach_absolute_time или ContinuousClock из Swift 5.7+, которые работают на аппаратных счётчиках циклов процессора.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также