[英]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.