我遇到了从REST Web服务收到的日期字符串的问题,以及如何在不同时区的Swift中表示它。我刚刚能够重现这个问题,所以我将谈谈这个具体的例子。
我从Web服务获取的信息是日期时间字符串和时区标识符。在这种情况下,系统位于 America / New_York 或美国东部时区。我创建了一个游乐场,我有以下代码
let dateFormatString = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
let easternTimeZone = "America/New_York"
let serverDate = "2017-03-01T00:00:00-05:00"
我有一个方法,它接受日期字符串和时区标识符,并创建一个Date对象,如下所示
func dateForDateString(dateString: String, timeZone: String) -> Date?
{
let formatter = DateFormatter()
if timeZone != ""
{
formatter.timeZone = TimeZone(identifier: timeZone)
}
formatter.dateFormat = dateFormatString
return formatter.date(from: dateString)
}
当我使用从Web服务返回的内容调用此方法时
let easternDate = dateForDateString(dateString: serverDate, timeZone: easternTimeZone)
print("\(easternDate)")
print
语句输出预期的Optional(2017-03-01 05:00:00 +0000)
。没有问题。当设备处于不同的时区时会出现问题,为了这个例子,我正在太平洋时间进行测试。在操场上,easternTime
变量显示为Feb 28, 2017, 9:00 PM
。再一次,并非出乎意料。
日期将存储在Firebase数据库中,我根本不关心时间。所以我最终使用Calendar
方法startOfDay
,如下所示
let myDate = Calendar.current.startOfDay(for: ed)
正如您所料,这会返回日期Feb 28, 2017, 12:00 AM
。显然不是我想要存储在Firebase中的内容。最重要的是,我需要将日期放在Web服务返回的时区中。
更新 正如评论中所提到的,我还尝试创建一个Calendar实例,并将其timeZone属性设置为TimeZone,其中包含从服务器接收的标识符。代码看起来像这样
var easternCal = Calendar(identifier: .gregorian)
if let etz = TimeZone(identifier: easternTimeZone)
{
easternCal.timeZone = etz
}
if let ed = easternDate
{
let convertedDate = dateToTimeZone(date: ed, toTimezone: easternTimeZone)
let currentCalDate = Calendar.current.startOfDay(for: ed)
let myDate = easternCal.startOfDay(for: ed)
print("\(myDate)")
}
昨晚,我可以发誓这不起作用,但是当我现在在操场上试试时,它看起来工作得很好。 currentCalDate
是我不想要的日期Feb 28, 2017, 12:00 AM
,因为它使用的是设置了太平洋时区的用户日历。 myDate
正确显示为Feb 28, 2017, 9:00 PM
,正在打印为2017-03-01 05:00:00 +0000
,这是我一直想要的。
我认为这个问题已经解决了。
答案 0 :(得分:0)
正如我的问题更新中所提到的,创建一个Calendar实例并将timeZone
属性设置为从后端返回的属性解决了我的问题。