【问题标题】:Swift DateFormatter string loaded from bytes not parsing with valid format从未使用有效格式解析的字节加载的 Swift DateFormatter 字符串
【发布时间】:2020-02-05 10:06:38
【问题描述】:

我正在使用以下代码从 Swift 中的字节数组中加载字符串

let bytes = data[position...position + length]
guard let let dateString = String(bytes: bytes, encoding: .utf8)
    else {return}

这给了我一个有效的字符串,例如"20160714"

使用DateFormatter 然后我尝试使用以下内容从字符串中解析日期

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYYMMdd"
let date = dateFormatter.date(from: dateString)

应该工作,但date 始终是nil。当我在操场上用字符串文字 (let dateString = "20160714") 尝试同样的事情时,它按预期工作,我认为这与编码有关。

非常感谢任何帮助。

编辑: 我已经尝试了 YYYY 和 yyyy 一年,都返回 nil

还值得注意的是,字节数组来自使用

将文件加载到内存中
guard let data = try? NSData(contentsOfFile: urlString, 
                             options: .alwaysMapped)
    else {fatalError("Invalid file")}

根据@vadian 的要求,在控制台中打印Data(bytes) as NSData 会得到以下输出

{length = 8, bytes = 0x3230313630373134}

【问题讨论】:

  • 使用“yyyy”而不是“YYYY”
  • @JoakimDanielson 我尝试了两种变体都没有成功,我更新了我的问题以反映这一点。谢谢
  • print(bytes as NSData) 并将结果添加到问题中。 Joakim 是对的 YYYY 是错的。您可能会在一年的第一周和最后一周出现意外行为,
  • 完成了,这对您有什么启示吗?
  • 不,我的错,我的意思是print(Data(bytes) as NSData)

标签: ios arrays swift nsdateformatter


【解决方案1】:

您编写的代码是正确的。也是它在 Date 对象中的转换。尝试在控制台上打印日期。

let dateString = "20160714"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYYMMdd"
let date = dateFormatter.date(from: dateString)

只需将您的日期对象转换为您想要的字符串格式(即 yyyy/MM/dd)

【讨论】:

  • 是的,代码是正确的,这就是为什么我很困惑,问题似乎出在格式化的字符串上,而不是解析日期的代码。
【解决方案2】:

尝试用ISO8601DateFormatter 解析dateString(需要iOS 10.0+、tvOS 10.0+ 或macOS 10.12+):

let dateFormatter = ISO8601DateFormatter()
dateFormatter.formatOptions = [.withYear, .withMonth, .withDay]
let date = dateFormatter.date(from: dateString)

使用 Swift 5.1.3/Xcode 11.3.1 测试。

【讨论】:

  • 谢谢,很遗憾这没有用,但这是一个很好的建议。
【解决方案3】:
let dateString = String(bytes: bytes, encoding: .'t)

这给了我一个有效的字符串

不,它会给你Optional<String>

所以编译器不会编译

let date = dateFormatter.date(from: dateString)

这意味着你必须检查这两行代码之间发生了什么,才能找到错误......

好的,更新一些例子来查看错误并不是那么容易。 在 Playground 中试试这个,看看它会打印什么!

let str = "0170101"
var data = Data(str.utf8)
// this makes a trouble
data[0] = UInt8(1)
let dateString = String(bytes: data[0 ..< data.count], encoding: .utf8)

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYYMMdd"
dateFormatter.locale = Locale(identifier: "en_US_POSIX")

let date = dateFormatter.date(from: dateString ?? "")

let strd = "170101"
let date2 = dateFormatter.date(from: strd)

print(dateString ?? "", date)
print(strd, date2)

它会打印出来

170101 nil
170101 Optional(2016-12-31 23:00:00 +0000)

你期待吗? 尝试在代码中的其他地方找到错误...

如果日期看起来有效,请查看它如何显示日期。很有趣,不是吗?

将第一行改为

let str = "020170101"

它会打印出来

20170101 nil
20170101 Optional(2016-12-31 23:00:00 +0000)

【讨论】:

  • 我认为我不必说它可以编译...在实际代码中我解开字符串,但为了简单起见,我把它省略了。不过,我会更新我的问题以消除任何困惑。
  • 所以有一个地方,在哪里可以找到你的错误......而不是你放在这里的代码。您的 dateFormatter 部分没有问题。
  • @AlexBrown 看到我的更新并思考,我在说什么
  • 这很有帮助,似乎说明了我的问题的根本原因。将字符串直接从字节转换为 UTF8 会产生(看起来是)正确的字符串,但由于某种原因 DateFormatter 不喜欢它。这与我在测试中看到的一致,如果我使用具有相同值的字符串文字,它可以按预期工作,那么字符串转换肯定会发生一些事情......
  • 正确,虽然如果它是坏数据,我想它会在字符串解析级别失败
【解决方案4】:

首先将字节转换为字符串,然后再将其转换为有效日期

让字节=数据[位置...位置+长度] let dateString = NSString(bytes: bytes!, length: data!.count, encoding: NSUTF8StringEncoding)

让 dateFormatter = DateFormatter()

dateFormatter.dateFormat = "YYYYMMdd"

让 date = dateFormatter.date(from: dateString)

【讨论】:

  • 这似乎与问题中已经存在的代码没有任何不同。如果您认为某个特定差异可以解决问题,您能否强调一下?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-30
  • 1970-01-01
相关资源
最近更新 更多