【问题标题】:Number of days in month returns wrong value after 10:00 PM晚上 10:00 后每月的天数返回错误值
【发布时间】:2021-12-06 15:11:50
【问题描述】:

我在使用 Swift 获取一个月中的总天数时遇到了一个小问题。 我扩展了 Date 类并创建了这个函数:

    func daysInMonth() -> Int {
        print(self.day)  ##30
        print(self.month) ##12
        print(self) ## 2021-11-30 23:46:29 +0000
        print(Calendar.current.range(of: .day, in: .month, for: self)?.count) ##31
        return Calendar.current.range(of: .day, in: .month, for: self)?.count ?? 0
    }

我已在我的 Mac 设置中的首选项中将日期和时间设置为 11 月 30 日晚上 11:45。 我在晚上 11:46 调用了上述函数并获得了上述结果(内联,在打印语句旁边)。 日期输出和日期一样正确。月份输出错误,结果为 11 月份的 31 天。 如果我在晚上 10:00 之前运行完全相同的代码,我会得到正确的结果,即 30 天。

有人知道为什么会这样吗?

谢谢,

辣椒粉

【问题讨论】:

  • 时差?
  • 即使我转换为本地时区,也会发生同样的事情。 @JoakimDanielson
  • self.month 是如何计算的?
  • self 在这种情况下基本上是Date().month。所以应该是当前月份。
  • Swift Date 没有属性 month

标签: ios swift date


【解决方案1】:

这是一个 GMT 偏移问题与一个月中的当前日期相结合。

当您创建一个没有设置日期的日期时,它将被设置为该月的第一天。

因此,如果您的时区偏移量为例如 -4 意味着您比 GMT 0 晚 4 小时,并且默认情况下Calendar.current 定义的时区等于系统时区。那么这意味着什么呢?意味着如果您在23 + (-4) 的边界内测试它,您将获得上个月的数据,如果您的偏移量为正数,您将获得下个月的数据。

您可以在 Playground 中复制并粘贴以下代码来测试此行为。

func getDaysInMonth(month: Int, year: Int, offset: Int = 0) -> Int? {
    let someDate = DateComponents(year: year, month: month, hour: 3)
    var current = Calendar.current
    let timezone = TimeZone(secondsFromGMT: 60 * 60 * offset)!
    current.timeZone = timezone
    guard let someDay = current.date(from: someDate) else { return nil }
    print("date: \(someDay)") // this will always
    return someDay.daysInCurrentMonth
}

for hour in -12...12 {
    print("hour: \(hour)\ndays: \(getDaysInMonth(month: 10, year: 2021, offset: hour) ?? -1)")
    print("---\n")
}

extension Date {
    var daysInCurrentMonth: Int? {
        Calendar.current.range(of: .day, in: .month, for: self)?.count
    }
}

请注意,从您当前的系统时区开始,日期会发生变化(请注意只有月份会发生变化)。

如何解决这个问题?

在你的情况下,我想你只是想显示一个月有多少天,所以你可以像这样将 设置为零:

TimeZone(secondsFromGMT: 0)

Calendar.current 的实例上进行此更改并检查它是否适合您。

【讨论】:

    【解决方案2】:

    您的 .day 和 .month 的日期扩展方法似乎有问题。 如果没有看到代码,很难确定问题是什么。下面是一些用于返回当前月份(Int)和当前月份编号(Int)的代码

    extension Date
    {
        var month: Int
        {
            let date = Date()
            let calendar = Calendar.current
            let components = calendar.dateComponents([.month], from: date)
            return components.month
        }
        
        var day: Int
        {
            let date = Date()
            let calendar = Calendar.current
            let components = calendar.dateComponents([.day], from: self)
            return components.day
        }
    }
    

    还请确保您的 Mac/模拟器/设备上的时间/日期设置正确。如果这些都是错误的 - 如果您处于提前几个小时的时区,它可能会跳到不同的月份。

    【讨论】:

    • 这正是我所拥有的。不过谢谢!
    • @paprika 我觉得那一定是时区/时间问题。我假设即使日期输出为 2021-11-30 23:46:29 +0000 也可能是 2021-12-01 01:46:29 +0000 或类似的日期未来的日期并返回 12 和 31。您实际位于哪个时区,您的 mac/模拟器/设备位于哪个时区?
    • 不管我在哪个时区。我只想根据我在地球上的任何地方获得一个月中的正确天数。
    猜你喜欢
    • 1970-01-01
    • 2021-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-20
    • 2022-12-15
    相关资源
    最近更新 更多