【问题标题】:Date range with correct TimeZone in SwiftSwift 中具有正确时区的日期范围
【发布时间】:2020-09-23 23:05:26
【问题描述】:

我知道有很多关于时区和日期的问题,但我真的很难弄清楚。

我的时区是 GMT+3(这是我的物理设备所说的)

我正在尝试从周日开始获取下周的范围。 所以它需要是 9 月 27 日 ... 10 月 3 日

每天晚上 09:PM 我得到的结果是从 9 月 28 日到 10 月 4 日。 一直保持到凌晨 03:00

我写这个问题的当前时间是凌晨 2 点,它显示了从 9 月 28 日开始的这个范围。

我为Date 做了一个扩展并添加了这个变量(我也在使用 SwiftDate)。

var closedRange: ClosedRange<Date> {
        let d = Date() //.timeInterval - Fix the problem until 03:AM
        let calendar = Calendar.autoupdatingCurrent
        let min = calendar.date(byAdding: .day, value: 0, to: d.nextWeekday(.sunday))!
        let max = calendar.date(byAdding: .day, value: 6, to: d.nextWeekday(.sunday))!
        return min...max
    }

如果我将此变量添加到d,则日期是正确的。但在凌晨 3:AM 之后又搞砸了。

var timeInterval: Date{
        var date = self
        date.addTimeInterval(TimeInterval(TimeZone.current.secondsFromGMT(for: self)))
        return date
    }

稍后查看:

let range = Date().closedRange
    
DatePicker(LocalizedStringKey("Choose day:"), selection: $shift.date, in: range, displayedComponents: .date)

当我将下周作为 String 或 Int 时,也会出现问题。 它从 9 月 28 日开始,而不是 9 月 27 日(再次取决于我的位置时间)

var nextWeek: [String]{
        
        let d = Date()
        var daysArr = [String]()
        let dateFormat = DateFormatter()
        let calendar = Calendar.autoupdatingCurrent
        let dayOfWeek = calendar.component(.weekday, from: d.nextWeekday(.sunday))
        let weekdays = calendar.range(of: .weekday, in: .weekOfYear, for: d.nextWeekday(.sunday))!
        let days = (weekdays.lowerBound ..< weekdays.upperBound).compactMap { calendar.date(byAdding: .day, value: $0 - dayOfWeek, to: d.nextWeekday(.sunday)) }
        
        dateFormat.dateFormat = DateFormats.format11.rawValue
        
        for d in days{
            daysArr.append(dateFormat.string(from: d))
        }
        
        return daysArr
        
    }

同样的问题也发生在这个日期数组上。

var nextWeekAsDates: [Date]{
        
        let d = Date()
        var daysArr = [Date]()
        let calendar = Calendar.autoupdatingCurrent
        let dayOfWeek = calendar.component(.weekday, from: d.nextWeekday(.sunday))
        let weekdays = calendar.range(of: .weekday, in: .weekOfYear, for: d.nextWeekday(.sunday))!
        let days = (weekdays.lowerBound ..< weekdays.upperBound).compactMap { calendar.date(byAdding: .day, value: $0 - dayOfWeek, to: d.nextWeekday(.sunday)) }
                
        for d in days{
            daysArr.append(d)
        }
        
        return daysArr
        
    }

【问题讨论】:

  • 日期与时区无关,但日历不是。您是否尝试过更改范围的最小和最大日期?似乎 SwiftDate 也考虑到了地区/时区
  • 我试过了,但要获得日期,您需要使用Date(),所以它总是会改变。那么我们如何在以色列获得正确的时间和日期为Date

标签: ios swift date time swiftui


【解决方案1】:

您可以简单地将今天的组件 weekOfYear 提前 1,即 yearForWeekOfYear 并从这些组件中获取日期。那将是下周的开始。如果你需要它的结束,你可以得到下周的开始,这标志着它的结束:

extension Calendar {
    static let gregorian: Calendar = .init(identifier: .gregorian)
}

extension Date {
    func nextWeekOfYear(using calendar: Calendar = .gregorian) -> Int {
        calendar.component(.weekOfYear, from: self) + 1
    }
    func yearForWeekOfYear(using calendar: Calendar = .gregorian) -> Int {
        calendar.component(.yearForWeekOfYear, from: self)
    }
    func startOfNextWeek(using calendar: Calendar = .gregorian) -> Date {
        DateComponents(calendar: calendar, weekOfYear: nextWeekOfYear(using: calendar), yearForWeekOfYear: yearForWeekOfYear(using: calendar)).date!
    }
}

Date().startOfNextWeek()  // "Sep 27, 2020 at 12:00 AM"

如果你需要一个范围:

var range: Range<Date> {
    let min = Date().startOfNextWeek()
    return min..<min.startOfNextWeek()
}

print(range) //  "2020-09-27 03:00:00 +0000..<2020-10-04 03:00:00 +0000\n"

【讨论】:

  • 我会尝试你的建议,但我认为它会给出相同的结果,因为它仍然与Date() 相关。当日期时间更改(如 UTC)时,它会在时间为晚上 9 点或上午 12 点时再次提前更改此范围。
  • 不要乱用时区。这适用于任何时区。打印的时区将始终为 UTC。如果您想打印当地时间,请使用 date.description(with: .current)
  • 最终我将范围返回为ClosedRange 并进行了一些更正:return min...min.startOfNextWeek() - 1 非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-04
  • 1970-01-01
  • 1970-01-01
  • 2020-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多