文章介绍
本篇文章的主体是学习并理解DateFormatter,知道Date和String如何进行转换。在此,我们也可以灵活运用DateFormatter处理JSON文件。
DateFormatter是Swift中的一个类,用来将日期(Date类型)和字符串(String类型)进行相互转换。它可以根据特定的格式解析日期字符串,或将Date对象转换为特定格式的字符串。
例如,我们将一个日期字符串”2024-10-03”解析为Swift的Date类型。
首先,我们创建一个DateFormatter实例。
let formatter = DateFormatter()
设置DateFormatter的日期格式:
formatter.dateFormat = "y-MM-dd"
DateFormatter的.dateFormat属性用于指定日期和时间的显示格式。它接收一个格式字符串,用来定义日期和时间的输出样式。其中“y-MM-dd”是一种日期格式,表示年份、月份和日期。
1、Y表示年份(Year),例如2024。
2、MM表示月份(Month),是两位数,零填充。例如01表示一月,12表示十二月。
3、dd表示日期,也是两位数,零填充。例如01表示一号,31表示三十一号。
4、HH表示小时,也是两位数,零填充。例如01表示1点,23表示23点。
5、mm表示分钟,也是两位数,零填充。例如01表示1分,59表示59分。
6、ss表示秒钟,也是两位数,零填充。例如13表示13秒。
这里可能存在疑问,那就是y和yyyy有什么区别?
我在这里整理了一个对应表格,不难看出,只有年份有部分规律,月、日、小时、分钟和秒钟,数字长度小于格式长度位数时,前面填0。
年份方面的规律:
1、y格式在显示两位数年份时,会自动转换为四位数的年份,其余的位数都正常显示。
2、yy格式是截取年份的后面两位数。
3、其他y格式,显示小于y位数时,年份前面添0,如yyy显示12时为012,但显示1234时,就会显示全部的年份。
常见的日期格式:
1、”yyyy-MM-dd”: 表示 2024-10-03(标准年-月-日格式)。
2、”dd/MM/yyyy”: 表示 03/10/2024(日/月/年格式)。
3、”MMM d, yyyy”: 表示 Oct 3, 2024(缩写月份、日期和年份)。
4、”EEEE, MMMM d, yyyy”: 表示 Thursday, October 3, 2024(完整的星期几、月份、日期和年份)。
注意,我们的formatter是DateFormatter类型,不是Date类型,它是专门用于处理日期和字符串之间转换的类。
示例:格式化日期
let formatter = DateFormatter()
formatter.dateFormat = "y-MM-dd"
let date = Date() // 当前日期
let dateString = formatter.string(from: date) // 将 Date 转为 "2024-10-06"
print(dateString)
示例:解析日期字符串
let formatter = DateFormatter()
formatter.dateFormat = "y-MM-dd"
let dateString = "2024-10-06"
if let date = formatter.date(from: dateString) {
print(date) // 解析字符串为 Date 对象
}
根据上面两个示例,我们可以看到formatter有两种格式化方法,一种是将Date类型格式化为字符串,另一种是将字符串解析为Date类型。
formatter.string(from: Date()) // Date类型转换为String字符串
formatter.date(from: String) // String字符串转换为Date类型
这两种方法可以让我们快速转换时间的两种格式,以便处理更多的使用场景。
处理JSON文件
JSON文件中,日期通常以字符串的形式存储,例如“1968-12-21”。当我们使用JSONDecoder解码JSON文件时,默认情况下,它不会自动将字符串转换为Date对象。所以,我们应该告诉JSONDecoder解码器如何识别并解析日期。
例如,我们有一个missions文件,其中有一个launchDate日期字符串字段,虽然launchDate是一个日期,但它实际是字符串类型。
"launchDate": "1968-10-11"
因此,我们可以通过DateFormatter定义解码的日期格式
let formatter = DateFormatter()
formatter.dateFormat = "y-MM-dd" // 解析的日期格式
然后我们将DateFormatter定义的解码日期格式,给JSONDecoder的dateDecodingStrategy(日期解码策略)属性。
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(formatter) // 告诉解码器使用这个格式来解析
dateDecodingStrategy是JSONDecoder的一个属性,用于定义从JSON字符串中解析日期,可以通过自定义日期格式解析JSON中的日期。
常见的dateDecodingStrategy有以下几种:
1、.deferredToDate:使用 Date 自身的编码/解码方法。
2、.secondsSince1970:将日期表示为自 1970 年 1 月 1 日 00:00:00 UTC 以来的秒数。
3、.millisecondsSince1970:将日期表示为自 1970 年 1 月 1 日 00:00:00 UTC 以来的毫秒数。
4、.iso8601:使用 ISO 8601 标准格式来解析日期(比如 “2024-10-03T00:00:00Z”)。
5、.formatted(formatter):使用自定义的 DateFormatter 来解析日期。
所以,.formatted(formatter)就表示我们将自定义的DateFormatter传递给dateDecodingStrategy属性。然后,我们的JSONDecoder就可以按照我们设置的日期格式对JSON文件的日期字段进行解析。
此外,我们还需要知道的话,dateDecodingStrategy是一个属性,所以我们采用赋值的方式:
decoder.dateDecodingStrategy = .formatted(formatter) // 告诉解码器使用这个格式来解析
将我们自定义的DateFormatter对象定义日期解析的格式,赋值给JSONDecoder的dateDecodingStrategy属性。
Date.formatted()方法
我们知道.formatted()是dateDecodingStrategy的一种策略,我们还可以扩展学习一下Date.formatted()方法。
这是Swift中Date类型的一个方法,用于将Date类型转换为字符串,所以跟前面提到的decoder.dateDecodingStrategy中的解析策略不同。Formatted()是更简洁的API,可以在Date()上直接调用.formatted()将Date转换为某种默认格式的字符串。
比如格式化当前日期:
let date = Date()
let formattedDate = date.formatted() // 将当前日期转换为默认格式的字符串
print(formattedDate) // 比如输出: "Oct 6, 2024"
我们在使用.formatted(formatter)表示通过一个自定义的格式化器(formatter)来对数据进行格式化。与前面的formatter.dateFormat相比更加简洁,但缺点就是不能更加灵活的自定义日期格式。
我们也可以传递自定义的格式选项来生成不同格式的字符串,比如:
let formattedDate = date.formatted(date: .abbreviated, time: .shortened)
这标识,我们将输出
Oct 6, 2024, at 22:04
Date().formatted(date:time)方法允许你根据不同的格式化选项将Date转换为字符串,对date和time参数,Swift提供了一些内置的选项,分别控制日期和时间部分的格式。
date参数选项:
1、.omitted:不显示日期部分
2、.numeric:日期以数字形式显示,例如“2024/10/6”
3、.abbreviated:月份缩写,日期数字,年份缩写,例如” Oct 6, 24”
4、.long:完整显示日期,例如“October 6, 2024”
5、.complete:完整的日期格式,例如“Sunday, October 6, 2024”
time参数选项:
1、.omitted:不显示时间部分
2、.shortened:时间的简短表示,例如“22:09”
3、.standard:标准时间显示,例如”22:10:00”
4、.complete:完整的时间显示,例如“22:10:16 GMT+8”
因此,我们可以灵活允许这些选项来格式化日期和时间。
Date转换为字符串
当我们想要使用Text()展示Date数据时,代码如下:
Text(mission.launchDate)
通过Text()展示Date类型的数据时,会提示:
Cannot convert value of type 'String' to expected argument type 'Date'
Initializer 'init(_:)' requires that 'Date' conform to 'StringPro
1)我们可以根据上面提到的Date.formatted()方法进行转换:
Text(mission.launchDate?.formatted() ?? "N/A")
2)也可以使用formatter.string(from: Date())进行转换。
struct Mission: Codable, Identifiable {
let launchDate: Date?
...
var formattedLaunchDate: String {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .short
return launchDate != nil ? formatter.string(from: launchDate!) : "N/A"
}
}
Text(mission.formattedLaunchDate)
我们可以看到,我在mission结构体中定义了一个formattedLaunchDate计算属性,然后创建DateFormatter实例后,配置dateStyle和timeStyle,然后判断launchDate是否为nil,不为nil就强制解包,为nil的话就输出“N/A”。
这里之所以强制解包,是因为我们的launchDate是一个Date?可选项,所以,我们在使用formatter.string()时,就必须考虑launchDate为nil时,提供一个默认值。
因为formatter.string(from:)只接受Date类型,而我们希望在launchDate为nil时,输出字符串”N/A”,而不是一个Date内容。
因此,我们只能在开头先判断launchDate是否为nil,不是的话就强制解包,是的话就返回字符串“N/A”。
其他设想
有人可能会认为这个比较复杂,想要尝试在Text()中使用formatter.string(from:Date())输出字符串。
Text(mission.launchDate != nil ? DateFormatter().string(from: mission.launchDate!) : "N/A")
这种方式只会导致为nil时输出”N/A”,而不会在不为nil时输出对应的日期和时间。
正如下图所示,只有第一个输出为“N/A”,其他的日期和时间都没有输出。
原因是我们的DateFormatter没有设置格式,默认格式可能会不符合预期,导致显示的内容不是想要的格式,甚至为空。因此,我们每次使用DateFormatter时必须正确格式化日期和时间的格式,才能正常输出。
另一种思路
let formatter = DateFormatter()
formatter.dateStyle = .long
formatter.timeStyle = .none
我们将这段代码放在View中,然后通过return返回视图。
var body: some View {
let formatter = DateFormatter()
formatter.dateStyle = .long
formatter.timeStyle = .none
return NavigationStack {
... // 更多代码
Text(mission.launchDate != nil ? formatter.string(from: mission.launchDate!) : "N/A")
... // 更多代码
}
}
首先,解释一下为什么我们要在View视图当中使用return。这是因为当我们的body属性的类型是some View,因此我们需要返回一个符合View协议的对象。既然要返回,那就要用我们的return关键词。
formatter.dateStyle和formatter.timeStyle是DateFormatter的属性,用于定义日期和时间的样式。它们提供了一些预设的样式选项,适用于大多数常见的日期/时间格式。
1、dateStyle:控制日期部分的格式(如年、月、如)。
2、timeStyle:控制时间部分的格式(如时、分、秒)
日期和时间的预设值包括:
1、.short: 短格式,例如 10/6/24 或 2:34 PM
2、.medium: 中等长度,例如 Oct 6, 2024 或 2:34:00 PM
3、.long: 长格式,例如 October 6, 2024
4、.full: 完整格式,例如 Sunday, October 6, 2024
5、.none: 表示不显示日期或时间。
let formatter = DateFormatter()
formatter.dateStyle = .long
formatter.timeStyle = .none
所以,我们的设置显示日期格式为October 6, 2024 ,并省略时间部分。
总结
我们学习到了DateFormatter是用于Date和String类型之间相互转换的类。在创建DateFormatter实例时,必须格式化日期或时间格式,否则可能会存在不显示的情况。
然后,我们学习了DateFormatter的日期和时间格式,以及格式化日期或解析日期字符串。
接着,我们学习如何处理JSON文件中的日期字段。并额外学习了解了Date.formatted()方法,它可以将Date类型转换为字符串,并且也可以设置日期和时间的格式。
最后,是在实际运用中将Date类型转换为字符串,可以使用Date.formatter()方法以及DateFormatter.string(Date())这两种方法处理,同时提到了在Text()中转换并输出的Date内容的设想,在另一种思路中,我们学习了dateStyle和timeStyle这两种日期或时间格式。
以上是全部的DateFormatter的内容。