Получение минутной разницы между двумя датами без расчета 60 секунд

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

Я имею в виду :

(год-месяц-день часы-минуты-секунды)

  • 2023-04-17 13:42:00
  • 2023-04-17 13:43:00

между этими двумя датами разница всего 1 минута.

  • 2023-04-17 13:42:58
  • 2023-04-17 13:43:00

Если я изменился на секунды первой даты до 58, я все равно хочу вывести как 1. Технически разница составляет всего 2 секунды, но минута отличается, а разница равна 1.

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

Коды, которые я пробовал:

let diff = Int(end.timeIntervalSince1970 - start.timeIntervalSince1970)

let hours = diff / 3600
let minutes = (diff - hours * 3600) / 60

Этот, очевидно, вычисляет минуты на основе секунд, поэтому, если разница в секундах меньше 60, но все же 2 даты находятся в разных минутах, вывод равен 0.

Я также пробовал .dateComponents

let calendar = Calendar.current

let startDate = Date() // replace with your start date
let endDate = Date() // replace with your end date

let components = calendar.dateComponents([.minute], from: startDate, to: endDate)

if let minutes = components.minute {
    print("Number of minutes between start and end dates: \(minutes)")
}

Но и здесь такая же проблема.

Вы пробовали Calendar + DateComponents?

lorem ipsum 17.04.2023 14:51
developer.apple.com/documentation/foundation/calendar/… Вы можете точно определить, какие компоненты вы хотите рассмотреть.
Rob Napier 17.04.2023 14:55

Можете ли вы предоставить какой-либо код, который показывает, что вы пробовали?

Carsten 17.04.2023 15:06

Что вам нужно, так это вторая разница + 30 секунд, разделенная на 60 (количество секунд в I e минутах). Возьмите слово этого результата или конвертируйте его в Int

Ptit Xav 17.04.2023 17:45
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
67
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Насколько я понимаю, логика здесь такова: «взять наибольшую единицу разницы и округлить ее до 1 следующей большей единицы разницы».

В комментариях упоминается использование DateComponents, что, безусловно, является правильной отправной точкой, но я не вижу встроенного способа сделать именно это. Например. если ваш набор компонентов [.minute], но не включает .second, вы просто полностью теряете вторую степень детализации. Вы не увидите, что разница округляется до 1 минуты только потому, что вы не запрашивали разницу в секундах.

Вот как бы я начал:

import Foundation

extension Date {
    static private let allComponents: [Calendar.Component] = [.year, .month, .day, .hour, .minute, .second]
    static private let allComponentsSet = Set(allComponents)
    
    static func approximatedDifference(from start: Date, to end: Date) -> DateComponents {
        var differenceComponents = Calendar.current.dateComponents(Self.allComponentsSet, from: start, to: end)
        
        // E.g. for `2023-04-17 13:42:58` and `2023-04-17 13:43:00`, this will be `.second`.
        let largestDifferingComponent = Self.allComponents.first(where: { differenceComponents.value(for: $0) != 0 })!
        
        // This is the next large component. E.g. if `largestDifferingComponent` is `.second`, then this will be `.minute`.
        let largerComponentIndex = Self.allComponents.index(allComponents.firstIndex(of: largestDifferingComponent)!, offsetBy: -1, limitedBy: 0)!
        let largerComponent = allComponents[largerComponentIndex]
        
        // Zero out the smaller differing component
        differenceComponents.setValue(0, for: largestDifferingComponent)
        // Increment the difference in the next larger component
        differenceComponents.setValue(differenceComponents.value(for: largerComponent)! + 1, for: largerComponent)
        
        return differenceComponents
    }
}

let start = DateComponents(calendar: .current, year: 2023, month: 04, day: 17, hour: 13, minute: 42, second: 58).date!
let end = DateComponents(calendar: .current, year: 2023, month: 04, day: 17, hour: 13, minute: 43, second: 00).date!
print(Date.approximatedDifference(from: start, to: end)) // 1 minute

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

Ответ принят как подходящий

Вот функция, которая вычисляет разницу. Он начинается с использования того же метода, который вы используете, но проверяет, равен ли результат в минутах нулю, и поэтому использует вторую функцию из Calendar, чтобы увидеть, совпадают ли даты или нет, а затем равны, сравнивая с минутами, isDate(:equalTo:toGranularity:)

func minuteDifference(from startDate: Date, to endDate: Date) -> Int {
    let minutes = calendar.dateComponents([.minute], from: startDate, to: endDate).minute!

    if minutes != 0 {
        return minutes
    } else {
        let factor = startDate <= endDate ? 1 : -1
        return calendar.isDate(startDate, equalTo: endDate, toGranularity: .minute) ? 0 : 1 * factor
    }
}

Другие вопросы по теме