NSDate - конвертировать дату в GMT

Мне нужна возможность конвертировать значение NSDate в дату по Гринвичу.

Как я могу преобразовать значение NSDate в значение NSDate в формате GMT, независимо от того, какие настройки локали даты использует устройство iPhone?


person Mick    schedule 07.12.2009    source источник


Ответы (6)


Работа со временем в Cocoa может быть сложной. Когда вы получаете объект NSDate, он находится в местном часовом поясе. [[NSTimeZone defaultTimeZone] secondsFromGMT] дает вам смещение текущего часового пояса от GMT. Тогда вы можете сделать это:

NSDate *localDate = // get the date
NSTimeInterval timeZoneOffset = [[NSTimeZone defaultTimeZone] secondsFromGMT]; // You could also use the systemTimeZone method
NSTimeInterval gmtTimeInterval = [localDate timeIntervalSinceReferenceDate] - timeZoneOffset;
NSDate *gmtDate = [NSDate dateWithTimeIntervalSinceReferenceDate:gmtTimeInterval];

Теперь gmtDate должна иметь для вас правильную дату по Гринвичу. Чтобы отобразить его, посмотрите на NSDateFormatter, особенно на методы setDateStyle и setTimeStyle. Вы создаете NSDateFormatter, настраиваете его так, как хотите, а затем вызываете stringFromDate:, чтобы получить хорошо отформатированную строку.

person Alex    schedule 07.12.2009
comment
Хотя на первый взгляд это кажется хорошим, я настоятельно рекомендую не использовать этот метод, поскольку это может привести к путанице. Дата представляет один момент времени. Проблема в том, что вам нужны разные представления этой даты. Один и тот же момент времени имеет разные названия в Дели, в Нью-Йорке и т. д. Поэтому хорошенько подумайте, каков ваш контекст. Вы можете установить свойство calendar.timeZone в UIDatePickers, чтобы заставить их использовать другой часовой пояс, и, как показывает Ховард, вы можете настроить средства форматирования даты для работы с разными поясами. - person Felixyz; 25.04.2010
comment
Объект NSDate представляет момент времени, не зависящий от часового пояса и т. д., вам никогда не нужно преобразовывать NSDate в другой... только при сериализации (преобразовании в строки и из строк) часовой пояс/язык, будь то GMT или другое учитывается. Ответ Говарда правильный. - person Akusete; 10.08.2010
comment
@Akusete другими точками сериализации являются UIDatePicker и NSCalendar. - person Ben Challenor; 08.07.2011
comment
NSTimeInterval gmtTimeInterval = [localDate timeIntervalSinceReferenceDate] — timeZoneOffset; вводит в заблуждение, если вы находитесь на стороне + мира, тогда это должно быть NSTimeInterval gmtTimeInterval = [localDate timeIntervalSinceReferenceDate] + timeZoneOffset; - person Tomer Even; 07.01.2012
comment
Я согласен, код в этом примере неверен и вызвал ошибку в моем приложении. Я тогда потратил изрядное количество времени, копаясь в этом, и теперь я понимаю, что происходит. [Дата NSDate] дает вам дату, которая хранится внутри по Гринвичу. Если вы NSLog(@%@, localDate), вы увидите что-то вроде 2012-12-06 15:22:45 +0000; что +0000 указывает GMT. Кроме того, значение timeIntervalSinceReferenceDate отражает текущее количество секунд с 01 января 2001 г. в часовом поясе по Гринвичу, как я проверил, выполнив математические вычисления. Если вам нужен локальный временной интервал, вам нужно ДОБАВИТЬ смещение часового пояса. - person Joe Strout; 06.12.2012

Ответ Говарда правильный, проголосуйте за него и примите это.

Для справки, я думаю, полезно объяснить разницу между объектами даты и локализованными представлениями даты.

Во многих языках программирования объекты даты используются для представления уникальных моментов времени. Игнорируя релятивистские аргументы, можно предположить, что в любой момент мы можем определить момент времени, который одинаковы для всех, независимо от того, как мы измеряем время.

Если бы для каждого момента времени мы могли создать уникальную метку, эту метку можно было бы передавать и ссылаться на нее однозначно. Объекты даты предназначены для использования в качестве уникальной универсальной метки для заданного момента времени.

Можно придумать любое количество методов для создания такой схемы маркировки, и то, как каждый объект даты выбирает это, не имеет значения для любого, кто их использует.

Например, можно использовать числовое смещение от универсального события (X секунд с момента взрыва солнца).

Только когда мы хотим взять момент времени и сериализовать его в удобочитаемую строку, мы должны иметь дело со сложностями часовых поясов, локалей и т. д.

(Локальная строка даты) + (Формат даты) => Момент времени

Момент времени + (Формат даты) => (Локальная строка даты)

Каждая временная точка универсальна... не существует таких вещей, как временная точка Нью-Йорка или временная точка по Гринвичу, только если вы преобразуете временную точку в локальную строку. (с использованием средства форматирования даты) появляется какая-либо связь с часовым поясом.

Примечание: я уверен, что есть много блогов/статей по этому вопросу, но мой google foo не работает в этот час. Если у кого-то есть желание расширить эту тему, пожалуйста, сделайте это.

person Community    schedule 10.08.2010
comment
Допустим, есть сервер, который говорит, что я рассчитываю и работаю только с временем по Гринвичу и не рассматриваю концепцию часовых поясов. Это в основном сделает то же самое, о чем вы говорите. Вся обработка часового пояса может быть выполнена на клиенте. Сервер работает на уникальной контрольной точке. - person penduDev; 09.02.2015

Свифт 4:

//UTC or GMT ⟺ Local 

extension Date {

    // Convert local time to UTC (or GMT)
    func toGlobalTime() -> Date {
        let timezone = TimeZone.current
        let seconds = -TimeInterval(timezone.secondsFromGMT(for: self))
        return Date(timeInterval: seconds, since: self)
    }

    // Convert UTC (or GMT) to local time
    func toLocalTime() -> Date {
        let timezone = TimeZone.current
        let seconds = TimeInterval(timezone.secondsFromGMT(for: self))
        return Date(timeInterval: seconds, since: self)
    }

}
person Krunal    schedule 09.01.2018

Хотя ответ Алекса был хорошим началом, он не касался летнего времени (летнего времени) и добавлял ненужное преобразование в/из исходной даты. Для меня работает следующее:

Чтобы преобразовать из localDate в GMT с учетом летнего времени:

NSDate *localDate = <<your local date>>
NSTimeInterval timeZoneOffset = [[NSTimeZone systemTimeZone] secondsFromGMTForDate:localDate];
NSDate *gmtDate = [localDate dateByAddingTimeInterval:-timeZoneOffset]; // NOTE the "-" sign!

Чтобы преобразовать дату по Гринвичу в локальную дату с учетом летнего времени:

NSDate *gmtDate  = <<your gmt date>>
NSTimeInterval timeZoneOffset = [[NSTimeZone systemTimeZone] secondsFromGMTForDate:gmtDate];
NSDate *localDate = [gmtDate dateByAddingTimeInterval:timeZoneOffset];

Одно небольшое замечание: я использовал dateByAddingTimeInterval, который есть только в iOS 4. Если вы используете OS 3 или более раннюю версию, используйте addTimerInterval.

person thevoid    schedule 09.08.2010
comment
Это тоже далеко не идеальное решение. Как указал Felixyz в своем ответе Алексу, вы не хотите возиться с самим NSDate, а скорее с его представлением. Ответ Говарда даст локализованное представление NSDate. - person Marcus S. Zarra; 10.08.2010
comment
NSDate представляет момент времени, не зависящий от часового пояса. Ваш объект localDate представляет ту же точку, что и gmtDate. Когда вы собираетесь преобразовать его в строку, вам все равно нужно будет использовать DateFormatter для обоих и получить те же результаты. - person Akusete; 10.08.2010

Вы пробовали смотреть документацию для NSDateFormatter?

NSDateFormatter

NSDateFormatter, похоже, имеет некоторые методы для игры с часовыми поясами, в частности

-setTimeZone:

Я не проверял это сам, но я предполагаю, что если вы установите GMT ​​в качестве часового пояса на дату, которая изначально представлена ​​​​в другом часовом поясе, он будет отображать дату с правильными настройками, чтобы соответствовать новому часовому поясу.

person Jasarien    schedule 07.12.2009

person    schedule
comment
Работает ли DateFormatter как с кодами типов %d..., так и только с кодами типов d? - person Donna; 27.01.2010
comment
@Donna: последний NSDateFormatter использует стандарт UTS # 35. unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns . Это не будет работать с синтаксисом %d в стиле C. - person Akusete; 10.08.2010
comment
Старый поток, но я также рекомендую использовать подход Говарда вместо того, чтобы возиться с самой датой, как это делают некоторые другие предложения. Стоит отметить, что описание NSDate всегда указано по Гринвичу. Это означает, что NSLog(@%@, [NSDate date]) также всегда показывает данную дату по Гринвичу. - person Olaf Monien; 30.11.2011
comment
Я хотел бы уточнить комментарий Олафа, добавив, что описание NSDate не только показывает дату/время по Гринвичу, но и timeIntervalSinceReferenceDate отражает количество секунд с 01 января 2001 г. по Гринвичу (не в вашем местном часовом поясе) , слишком. - person Joe Strout; 06.12.2012
comment
Как мне сделать это быстро? - person Vikram Pote; 05.10.2015