Почему `ordinality (of: .day, in: .era, for: date)` дает одинаковый результат для 2 дат в разных часовых поясах?

Рассмотрим следующий код:

import UIKit

let date = Date()

guard let nycTimeZone = TimeZone(abbreviation: "EST"),
  let nzTimeZone = TimeZone(abbreviation: "NZDT") else {
    fatalError()
}
var nycCalendar = Calendar(identifier: .gregorian)
nycCalendar.timeZone = nycTimeZone
var nzCalendar = Calendar(identifier: .gregorian)
nzCalendar.timeZone = nzTimeZone

let now = Date()

let nycDayOfEra = nycCalendar.ordinality(of: .day, in: .era, for: now)
let nycDayOfYear = nycCalendar.ordinality(of: .day, in: .year, for: now)

var nzDayOfEra = nzCalendar.ordinality(of: .day, in: .era, for: now)
var nzDayOfYear = nzCalendar.ordinality(of: .day, in: .year, for: now)

Когда я пишу это, время Нью-Йорка и время Окленда Новой Зеландии показывают разные дни. Это тот случай, который меня интересует.

В приведенном выше коде результаты для nycDayOfYear и nzDayOfYear различаются (на момент написания я получил nycDayOfYear = 42 и nzDayOfYear = 43).

Это соответствует ожиданиям и желаемым. (Я работал, чтобы ответить на вопрос: «Как мне рассчитать количество дней разницы в двух датах, оцениваемых в разных часовых поясах?».)

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

Поэтому я попытался произвести расчеты, используя ordinality(of: .day, in: .era, for: date).

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

Это почему?

Что было бы более простым способом рассчитать разницу в количестве календарных дней между двумя датами, ПРИ ВЫРАЖЕНИИ В РАЗНЫХ МЕСТНЫХ ЧАСОВЫХ ПОЯСАХ? Как я уже сказал, мой код, который вычисляет день года, потребует добавления дополнительной логики для обработки дат, которые охватывают границы календарного года.

Обратите внимание, что это другой вопрос, чем «Сколько дней разница между двумя датами». В моем вопросе я хочу, чтобы обе даты были выражены в разных часовых поясах, и меня интересует разница в календарной дате каждого из этих значений даты.


person Duncan C    schedule 11.02.2017    source источник
comment
это потребовало бы кучу беспорядочных корректировок. Подождите - с чего бы это? Выявить разницу между двумя датами, изначально выраженными в разных часовых поясах, легко, потому что NSDate сам, независимо от исходного часового пояса, является абсолютным.   -  person matt    schedule 11.02.2017
comment
Что означает разница в количестве календарных дней между двумя датами, ВЫРАЖЕННАЯ В РАЗНЫХ МЕСТНЫХ ЧАСОВЫХ ПОЯСАХ? NSDate - это абсолютный момент времени (как только что сказал Мэтт). Количество дней между двумя датами относится к конкретному календарю и часовому поясу.   -  person Martin R    schedule 11.02.2017
comment
Календарные вычисления с длительными интервалами могут привести к неожиданным результатам. Другой пример см. В stackoverflow.com/q/41860009/1187415. В вашем случае DateComponents(calendar: ..., era: 1).date! возвращает 0001-01-01 04:56:02 +0000 для календаря Нью-Йорка и 0000-12-31 12:20:56 +0000 для календаря Новой Зеландии, т.е. часовые пояса. - Моя догадка заключается в том, что количество дней в эре не дает разумного результата.   -  person Martin R    schedule 11.02.2017
comment
Мэтт, внимательно прочти описание проблемы. Цель состоит в том, чтобы вычислить разницу в количестве календарных дней между двумя датами, выраженными в разных часовых поясах. Например, один и тот же NSDate часто отличается на 1 день в часовых поясах Нью-Йорка и Новой Зеландии. См. Мой ответ на часть вопроса ниже.   -  person Duncan C    schedule 11.02.2017
comment
Мартин, я не знаю, как сформулировать вопрос так, чтобы это было понятно. Проблема, которую я пытаюсь решить, заключается в том, как зафиксировать тот факт, что NSDate может давать разные результаты мм / дд / гггг в зависимости от часового пояса, и вычислить разницу между двумя датами NSDate в местных условиях мм / дд / гггг.   -  person Duncan C    schedule 12.02.2017


Ответы (1)


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

Я придумал код, который вычисляет желаемую разницу в значениях календарной даты между двумя датами, выраженными в определенных часовых поясах:

let date = Date()

guard let nycTimeZone = TimeZone(abbreviation: "EST"),
  let nzTimeZone = TimeZone(abbreviation: "NZDT") else {
    fatalError()
}
var nycCalendar = Calendar(identifier: .gregorian)
nycCalendar.timeZone = nycTimeZone
var nzCalendar = Calendar(identifier: .gregorian)
nzCalendar.timeZone = nzTimeZone

let now = Date()


let nycDateComponents = nycCalendar.dateComponents([.month, .day, .year], from: now)
let nzDateComponents = nzCalendar.dateComponents([.month, .day, .year], from: now)

let difference = Calendar.current.dateComponents([.day],
  from: nycDateComponents,
    to: nzDateComponents)

let daysDifference = difference.days

Сначала я конвертирую 2 даты в значения месяца / дня / года DateComponents, используя календари, настроенные на их конкретный часовой пояс.

Затем я использую функцию календаря dateComponents(_:from:to:), которая позволяет вам вычислить разницу между 2 DateComponents значениями в любых единицах, которые вы хотите использовать для их сравнения. (в данном случае дни)

person Duncan C    schedule 11.02.2017