Swift:设置 DateComponents 年份时的意外行为

标签 swift date swift3 nsdate nsdatecomponents

下面的示例代码从当前 Date 获取 DateComponents,修改组件,并从修改后的组件创建一个新的 Date。它还展示了创建一个新的 DateComponents 对象,填充它,然后从中创建一个新的 Date。

import Foundation

let utcHourOffset = -7.0
let tz = TimeZone(secondsFromGMT: Int(utcHourOffset*60.0*60.0))!
let calendar = Calendar(identifier: .gregorian)
var now = calendar.dateComponents(in: tz, from: Date())

// Get and display current date
print("\nCurrent Date:")
print("\(now.month!)/\(now.day!)/\(now.year!) \(now.hour!):\(now.minute!):\(now.second!)   \(now.timeZone!)")
let curDate = calendar.date(from: now)
print("\(curDate!)")

// Modify and display current date
now.year = 2010
now.month = 2
now.day = 24
now.minute = 0
print("\nModified Date:")
print("\(now.month!)/\(now.day!)/\(now.year!) \(now.hour!):\(now.minute!):\(now.second!)   \(now.timeZone!)")
let modDate = calendar.date(from: now)
print("\(modDate!)")

// Create completely new date
var dc = DateComponents()
dc.year = 2014
dc.month = 12
dc.day = 25
dc.hour = 10
dc.minute = 12
dc.second = 34
print("\nNew Date:")
print("\(dc.month!)/\(dc.day!)/\(dc.year!) \(dc.hour!):\(dc.minute!):\(dc.second!)   \(now.timeZone!)")
let newDate = calendar.date(from: dc)
print("\(newDate!)")

如果我修改组件,设置不同的年、月、日等,然后使用组件获取日期,我得到了意想不到的结果,新日期包含除年之外的所有修改组件,保持不变。

在我创建一个 DateComponents 对象并填充它然后从中创建一个 Date 的情况下,它按预期工作。

代码的输出如下所示:

Current Date:
3/9/2017 19:5:30   GMT-0700 (fixed)
2017-03-10 02:05:30 +0000

Modified Date:
2/24/2010 19:0:30   GMT-0700 (fixed)
2017-02-25 02:00:30 +0000

New Date:
12/25/2014 10:12:34   GMT-0700 (fixed)
2014-12-25 17:12:34 +0000

我预计修改后的日期是 2010-02-25 02:00:30 +0000 而不是 2017-02-25 02:00:30 +0000 .为什么不是呢?为什么它在第二种情况下有效?

docs对于 DateComponents 说:“NSDateComponents 的实例不负责回答有关超出其初始化信息的日期的问题......”。由于 DateComponents 对象是用一年初始化的,所以这似乎不适用,但这是我在文档中看到的唯一可以解释我观察到的行为的东西。

最佳答案

如果您登录 nowdc,您将看到问题所在。 now 是从 Date 创建的。这将填充所有日期组件,包括 yearForWeekOfYear 和几个与工作日相关的组件。这些组件导致 modDate 出现错误。

newDate 按预期工作,因为只设置了特定组件。

如果您重置一些额外的组件,您可以使 modDate 正确输出。具体来说,添加:

now.yearForWeekOfYear = nil

就在创建 modDate 之前将产生 modDate 的预期日期。当然,最好的解决方案是创建一个新的 DateComponents 实例,并根据需要使用以前的 DateComponents 中的特定值:

let mod = DateComponents()
mod.timeZone = now.timeZone
mod.year = 2010
mod.month = 2
mod.day = 24
mod.hour = now.hour
mod.minute = 0
mod.second = now.second
print("\nModified Date:")
print("\(mod.month!)/\(mod.day!)/\(mod.year!) \(mod.hour!):\(mod.minute!):\(mod.second!)   \(mod.timeZone!)")
let modDate = calendar.date(from: mod)
print("\(modDate!)")

关于Swift:设置 DateComponents 年份时的意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42708963/

相关文章:

ios - 如何增加导航栏高度

ios - 如何立即隐藏单个 View Controller 上的导航栏?

ios - 自动布局 - 使父 View 高度等于 subview 高度 + subview 为 textView 的常量

ios - 实时将 Metal MTKView 捕获为电影?

ios - 带标点符号的语音识别

ios - 从对象创建循环转换为在对象创建之间等待的 runBlock

java - 如何将字符串转换为日期对象?

r - 使用 ddply 根据日期值查找变量值

date - 在PL/SQL中将varchar2转换为Date ('MM/DD/YYYY')

arrays - 如何在Swift中从另一个类/文件访问数组