【问题标题】:NSDateFormatter dateFromString returns incorrect date [duplicate]NSDateFormatter dateFromString 返回不正确的日期 [重复]
【发布时间】:2012-07-01 15:31:53
【问题描述】:

我试图在我的应用程序中使用NSDateFormatter,它接受一个日期字符串并将其格式化为NSDate,以便我可以进行日期比较,但是我发现当我使用 dateFromString 并对其进行格式化时,日期正在丢失一天。

NSString *dateString = @"02-06-2012";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"dd-MM-yyyy"];
NSDate *dateFromString = [[NSDate alloc] init];
dateFromString = [dateFormatter dateFromString:dateString];
NSLog(@"My Date = %@", dateFromString);
[dateFormatter release];

这会输出到控制台:

我的日期 = 2012-06-01 23:00:00 +0000

【问题讨论】:

    标签: objective-c ios nsdate nsdateformatter


    【解决方案1】:

    我不相信 Dhruv 的回答是正确的。事实上,根本不清楚有什么问题。您似乎对应该发生的事情和/或对正在发生的事情的解释有错误的期望。

    NSDate 代表一个时刻。这一刻没有一个唯一的名字。它将在不同的地方和不同的命名系统(时区、日历)下以不同的名称而闻名。 NSDate 不处理任何这些,除了在其 -description 方法中蹩脚,它必须生成那个时刻的字符串表示。

    其次,像“02-06-2012”这样的字符串没有指定精确的时间点。首先,它只是一个没有时间信息的日期,所以NSDateFormatter 只是默认为该日期的第一刻。其次,它没有指定时区。日历日的第一时刻在每个时区都是不同的时刻。除非您使用 -setTimeZone: 指定时区或字符串本身带有时区信息,否则 NSDateFormatter 假定您要求它解析的任何日期字符串都在当前时区中。

    因此,您的 dateFromString 对象表示您所在时区中指定日期 02-06-2012 的第一刻。我希望这就是你想要的。但是,您随后对 NSDate 在登录时描述自己的方式感到困惑。正如我所说,NSDate 必须在它代表的那一刻选择一些“名称”(字符串表示),而它选择的名称是相当随意的。这些天来,它正在选择以 UTC 为已知时刻的名称。我从您的问题中显示的日志输出中收集到您位于 UTC+0100。因此,日期可能看起来提前一天,但实际上是您指定的同一时刻。换句话说,“2012-06-01 23:00:00 +0000”和“2012-06-02 00:00:00 +0100”是完全相同的时间点的两个等效名称。您只是不习惯看到第一个并误解了它。

    教训是,您必须停止依赖NSDate 的自我描述才能处于任何特定时区。真的,你不必依赖任何关于它的东西,因为它没有记录在案。事实上,-[NSDate description] 的文档指出,“不能保证表示在操作系统的不同版本中保持不变。”

    Dhruv 的解决方案似乎有帮助,仅仅是因为它使NSDateFormatter-[NSDate description] 就时区达成一致。但这是不可靠的。例如,它不适用于 Snow Leopard,因为 -[NSDate description] 在该版本的框架中使用本地时区而不是 UTC。

    不过,更重要的是,它会改变您从NSDateFormatter 对日期字符串的解释中获得的NSDate 对象所代表的实际时刻。我怀疑您确实希望它具有特定含义-您希望将字符串解释为在本地时区中-而他的解决方案阻碍了您的意图。

    tl;dr:你一直在得到你想要的日期;不要依赖-[NSDate description];不要使用 Dhruv 的解决方案

    【讨论】:

    • 嗨,Ken,感谢您的详细回复,您会推荐我做什么或使用什么?在我的应用程序中,我需要检查是否等于或大于我需要放入我的应用程序的特定硬编码日期。谢谢
    • 你必须决定你真正的意思是什么时候。硬编码的日期是否意味着被解释为在某个特定的固定时区(例如您公司的家庭办公室)?还是应该将其解释为处于用户的时区?如果是前者,则应在日期格式化程序上设置固定时区。如果是后者,您可以将其保留为默认值,也可以将其显式设置为[NSTimeZone defaultTimeZone](或+systemTimeZone)。
    • 谢谢 Ken 我会试一试 - 固定时间基本上是一个特定的日期,所以如果你打开应用程序和你在世界任何地方的基地,它应该使用特定的日期,看看今天是否更大或相等,我们这样做是因为我们必须在我们的应用程序中显示从某个日期开始的不同信息。你的解释也更有意义,所以我会标记你的答案。谢谢
    • 这实际上是对NSDateNSDateFormatter 概念上的错误假设的很好的解释。
    【解决方案2】:

    尝试将此行添加到您的代码中,

    [dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT+0:00"]];
    

    [dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
    

    SWIFT 更新:

    问题代码,

    let dateString = "02-06-2012"
    var dateFormatter = NSDateFormatter()
    dateFormatter.dateFormat = "dd-MM-yyyy"
    var dateFromString : NSDate = dateFormatter.dateFromString(dateString)!
    println("My Date \(dateFromString)")
    

    以及解决方案,

    dateFormatter.timeZone = NSTimeZone(name: "GMT")
    

    dateFormatter.timeZone = NSTimeZone(abbreviation: "GMT+0:00")
    

    【讨论】:

    • 这不是一个非通用的解决方案吗?如果设备不是 GMT 怎么办?
    • @stavash 这就是重点,GMT 与 UTC 或世界时相同。这是每个人都可以使用的一个标准化时区,并且永远不会改变(由于夏令时等)。这就是 iOS 存储日期/时间的方式......
    • 那么在所有时区的应用程序中使用 GMT 是否有效?我实际上正在获取当前日期 NSDate *now = [[NSDate alloc] init];然后将其与上面的字符串进行比较。
    • 您知道输入时间是 UTC,这比当前检查的答案要好得多。 +1
    • 我爱谷歌! (把我带到这里)THX :)
    猜你喜欢
    • 2015-12-14
    • 1970-01-01
    • 1970-01-01
    • 2015-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多