繁体   English   中英

Swift:查找并绘制两个日期之间的小时数

[英]Swift: Finding and plotting the hours in between two Dates

我正在尝试创建如下所示的 UI。 我有一个 startDate 和 endDate(例如上午 1:55 和上午 11:35)。 我怎样才能按比例(使用几何阅读器)找到两个日期和 plot 之间的每个小时,就像这里所做的那样? 我在想在某些时候我可能需要使用 seconds 或 timeIntervalSince,但我不太明白 go 的最佳方式是什么?

在此处输入图像描述

到目前为止,我的代码可以正确获取时间,但我需要根据时间按比例将它们分开:

我的代码是什么样的: 在此处输入图像描述

struct AsleepTimeView: View {
    
    @EnvironmentObject var dataStore: DataStore
    
    static let sleepTimeFormat: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateStyle = .none
        formatter.timeStyle = .short
        return formatter
    }()
    
    
    var body: some View {
        Color.clear.overlay(
            GeometryReader { geometry in
                if let mostRecentSleepDay = dataStore.pastSevenSleepDays?.last, let firstSleepSpan = mostRecentSleepDay.sleepSpans.first, let lastSleepSpan = mostRecentSleepDay.sleepSpans.last {
                    VStack(alignment: .center) {
                        HStack {
                            Text("\(firstSleepSpan.startDate, formatter: Self.sleepTimeFormat) ")
                                .font(.footnote)
                            Spacer()
                            Text("\(lastSleepSpan.endDate, formatter: Self.sleepTimeFormat)")
                                .font(.footnote)
                        }
                        HStack(spacing: 3) {
                            
                            ForEach(dataStore.sleepOrAwakeSpans) { sleepOrAwakeSpan in
                                
                                RoundedRectangle(cornerRadius: 5)
                                    .frame(width: getWidthForRoundedRectangle(proxy: geometry, spacing: 3, seconds: sleepOrAwakeSpan.seconds, sleepOrAwakeSpans: athlyticDataStore.sleepOrAwakeSpans), height: 10)
                                    
                                    .foregroundColor(sleepOrAwakeSpan.asleep == false ? TrackerConstants.scaleLevel5Color : TrackerConstants.scaleLevel8Color)
                                
                            }
                        }
                        HStack {
                            ForEach(getHoursBetweenTwoDates(startDate: firstSleepSpan.startDate, endDate: lastSleepSpan.endDate).map {  Calendar.current.component(.hour, from: $0) }, id: \.self) { hour in
                                HStack {
                                    Text("\(hour)")
                                        .font(.footnote)
                                    Spacer()
                                }
                            }
                        }
                        HStack {
                            HStack {
                                Circle()
                                    .foregroundColor(TrackerConstants.scaleLevel8Color)
                                    .frame(width: 10, height: 10)
                                Text("Asleep")
                                    .font(.footnote)
                            }
                            HStack {
                                Circle()
                                    .foregroundColor(TrackerConstants.scaleLevel5Color)
                                    .frame(width: 10, height: 10)
                                Text("Awake")
                                    .font(.footnote)
                            }
                            Spacer()
                        }
                    }
                }
 
            })     // end of overlay
    }
    
    //helper
    private func getWidthForRoundedRectangle(proxy: GeometryProxy, spacing: Int, seconds: TimeInterval, sleepOrAwakeSpans: [SleepOrAwakeSpan]) -> CGFloat {
        
        let totalSpace = (sleepOrAwakeSpans.count - 1) * spacing
        let totalSleepTime = sleepOrAwakeSpans.map { $0.endTime.timeIntervalSince($0.startTime) }.reduce(0, +)
        
        guard totalSleepTime > 0 else { return 0}
        
        let width =  (proxy.size.width - CGFloat(totalSpace)) * CGFloat(seconds / totalSleepTime)
        return width
    }
    
    func datesRange(from: Date, to: Date, component: Calendar.Component) -> [Date] {
        // in case of the "from" date is more than "to" date,
        // it should returns an empty array:
        if from > to { return [Date]() }
        
        var tempDate = from
        var array = [tempDate]
        
        while tempDate < to {
            tempDate = Calendar.current.date(byAdding: component, value: 1, to: tempDate)!
            array.append(tempDate)
        }
        
        return array
    }
    
    func getHoursBetweenTwoDates(startDate: Date, endDate: Date) -> [Date] {
        
        var finalArrayOfHours = [Date]()
        
        guard endDate > startDate else { return finalArrayOfHours }
        
        let arrayOfHours = datesRange(from: startDate, to: endDate, component: .hour)
        
        for date in arrayOfHours {
            let hour = date.nearestHour()
            finalArrayOfHours.append(hour)
        }
        
        return finalArrayOfHours
        
    }
    
}

extension Date {
    func nearestHour() -> Date {
        return Date(timeIntervalSinceReferenceDate:
                        (timeIntervalSinceReferenceDate / 3600.0).rounded(.toNearestOrEven) * 3600.0)
    }
}

日历 class 中有一整套方法可以帮助您完成尝试。

在我的脑海中,我说你会做如下的事情:

在一个循环中,使用date(byAdding:to:wrappingComponents:)一次将一个小时添加到您的 startDate。 如果结果 ≤ endDate,则使用component(_:from:)获取新计算日期的小时数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM