简体   繁体   中英

Swift: Finding and plotting the hours in between two Dates

I am trying to create a UI like the below. I have a startDate and endDate (eg 1:55am and 11:35am). How can I proportionally (using Geometry reader) find each hour in between two dates and plot them as is done here? I am thinking at some point I need to use seconds or timeIntervalSince perhaps, but can't quite get my head around how best to go about it?

在此处输入图像描述

my code so far which gets the hours correctly, but I need to space them out proportionally according to their times:

What my code looks like: 在此处输入图像描述

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)
    }
}

There are a whole suite of methods in the Calendar class to help with what you're trying to do.

Off the top of my head, Id say you'd do something like the following:

In a loop, use date(byAdding:to:wrappingComponents:) to add an hour at a time to your startDate. If the result is ≤ endDate, use component(_:from:) to get the hour of the newly calculated date.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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