【问题标题】:NSDate - Convert Date to GMTNSDate - 将日期转换为 GMT
【发布时间】:2010-12-24 04:33:43
【问题描述】:

我需要能够将 NSDate 值转换为 GMT 日期。

如何将 NSDate 值转换为 GMT 格式的 NSDate 值,而与 iPhone 设备使用的日期区域设置无关?

【问题讨论】:

    标签: ios objective-c swift nsdate gmt


    【解决方案1】:
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm";
            
    NSTimeZone *gmt = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
    [dateFormatter setTimeZone:gmt];
    NSString *timeStamp = [dateFormatter stringFromDate:[NSDate date]];
    [dateFormatter release];
    

    【讨论】:

    • DateFormatter 是否适用于“%d”类型代码...和“d”类型代码?
    • @Donna:最新的 NSDateFormatter 使用 UTS#35 标准。 unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns 。它不适用于 C 风格的 %d 语法。
    • 旧线程,但我也鼓励使用霍华德的方法,而不是像其他一些建议那样搞乱日期本身。值得注意的是,NSDate 的“描述”总是在 GMT 中。这意味着 NSLog(@"%@", [NSDate date]) 也始终以 GMT 显示给定日期。
    • 我想详细说明 Olaf 的评论,补充说 NSDate 描述不仅显示 GMT 的日期/时间,而且 timeIntervalSinceReferenceDate 反映了自 2001 年 1 月 1 日以来 GMT 的秒数(不在您当地的时区),也是。
    • 我应该如何快速完成?
    【解决方案2】:

    在 Cocoa 中处理时间可能很复杂。当您获得 NSDate 对象时,它位于本地时区。 [[NSTimeZone defaultTimeZone] secondsFromGMT] 为您提供当前时区与 GMT 的偏移量。然后你可以这样做:

    NSDate *localDate = // get the date
    NSTimeInterval timeZoneOffset = [[NSTimeZone defaultTimeZone] secondsFromGMT]; // You could also use the systemTimeZone method
    NSTimeInterval gmtTimeInterval = [localDate timeIntervalSinceReferenceDate] - timeZoneOffset;
    NSDate *gmtDate = [NSDate dateWithTimeIntervalSinceReferenceDate:gmtTimeInterval];
    

    现在gmtDate 应该为您提供正确的 GMT 日期。为了显示它,查看NSDateFormatter,特别是setDateStylesetTimeStyle 方法。您创建一个NSDateFormatter,按照您想要的方式对其进行配置,然后调用stringFromDate: 以获得一个格式良好的字符串。

    【讨论】:

    • 虽然这起初看起来不错,但我强烈建议不要使用这种方法,这可能会导致很多混乱。日期代表一个时间点。问题是您想要此日期的不同表示。同一时间点在德里和纽约等地有不同的“名称”。因此,请仔细考虑您的上下文是什么。您可以在 UIDatePickers 上设置 calendar.timeZone 属性,使它们使用另一个时区,正如 Howard 所示,您可以自定义日期格式化程序以使用不同的时区。
    • 一个 NSDate 对象代表一个时间点,独立于时区等......你永远不需要将一个 NSDate 转换为另一个......只有当你序列化时(与字符串相互转换)时区/区域设置,无论是格林威治标准时间还是其他时间都考虑在内。霍华德的答案是正确的。
    • @Akusete 其他序列化点是 UIDatePicker 和 NSCalendar。
    • NSTimeInterval gmtTimeInterval = [localDate timeIntervalSinceReferenceDate] - timeZoneOffset;如果你在世界的 + 一边是误导,那么它应该是 NSTimeInterval gmtTimeInterval = [localDate timeIntervalSinceReferenceDate] + timeZoneOffset;
    • 我同意,此示例中的代码不正确,导致我的应用程序出现错误。然后我花了相当多的时间深入研究它,现在我明白发生了什么。 [NSDate date] 为您提供一个以 GMT 格式在内部存储的日期。如果你 NSLog(@"%@", localDate) 你会看到类似 2012-12-06 15:22:45 +0000; “+0000”表示格林威治标准时间。此外,timeIntervalSinceReferenceDate 值反映了自 2001-01-01 GMT 时区 以来的当前秒数,正如我通过数学验证的那样。如果您想要本地时间间隔,则必须添加时区偏移量。
    【解决方案3】:

    Howard's Answer是正确的,请投票接受。

    作为参考,我认为解释日期对象和本地化日期表示之间的区别是有用的。

    在许多编程语言中,日期对象用于表示唯一的时间点。忽略Relativistic 参数,可以假设在任何情况下我们都可以定义一个时间点,该时间点对每个人来说都是普遍相等的,而不管我们如何测量时间。

    如果我们可以为每个时间点构造一个唯一的标签,则该标签可以被传递并明确引用。 日期对象的目的是充当给定时间点的唯一通用标签

    人们可以想出任何数量的技术来构建这样的标签方案,而每个日期对象如何选择这样做对任何使用它们的人来说都无关紧要。

    一个例子可能是使用一个通用事件的数字偏移量(太阳爆炸后 X 秒)。

    只有当我们希望获取一个时间点并将其序列化为人类可读的字符串时,我们才必须处理时区、语言环境等的复杂性......

    (本地日期字符串) + (日期格式化程序) => 时间点

    时间点 + (日期格式化程序) => (本地日期字符串)

    每个时间点都是通用的...没有纽约时间点格林威治标准时间点之类的东西,只有将时间点转换为本地字符串(使用日期格式化程序)是否会出现与时区的任何关联。

    注意:我确信有很多关于这个问题的博客/文章,但是我的 google foo 在这个时间点让我失望了。如果有人有热情就这个问题展开讨论,请随时这样做。

    【讨论】:

    • 假设有一个服务器说我只计算和工作在 GMT 时间并且不接受时区的概念。它基本上会和你所说的一样。所有时区处理都可以在客户端完成。服务器在一个唯一的参考点上工作。
    【解决方案4】:

    Swift 4

    //UTC or GMT ⟺ Local 
    
    extension Date {
    
        // Convert local time to UTC (or GMT)
        func toGlobalTime() -> Date {
            let timezone = TimeZone.current
            let seconds = -TimeInterval(timezone.secondsFromGMT(for: self))
            return Date(timeInterval: seconds, since: self)
        }
    
        // Convert UTC (or GMT) to local time
        func toLocalTime() -> Date {
            let timezone = TimeZone.current
            let seconds = TimeInterval(timezone.secondsFromGMT(for: self))
            return Date(timeInterval: seconds, since: self)
        }
    
    }
    

    【讨论】:

      【解决方案5】:

      虽然 Alex 的回答是一个好的开始,但它没有处理 DST(夏令时),并添加了与参考日期的不必要转换。以下对我有用:

      要从 localDate 转换为 GMT,将 DST 考虑在内:

      NSDate *localDate = <<your local date>>
      NSTimeInterval timeZoneOffset = [[NSTimeZone systemTimeZone] secondsFromGMTForDate:localDate];
      NSDate *gmtDate = [localDate dateByAddingTimeInterval:-timeZoneOffset]; // NOTE the "-" sign!
      

      要从 GMT 日期转换为 localDate,将 DST 考虑在内:

      NSDate *gmtDate  = <<your gmt date>>
      NSTimeInterval timeZoneOffset = [[NSTimeZone systemTimeZone] secondsFromGMTForDate:gmtDate];
      NSDate *localDate = [gmtDate dateByAddingTimeInterval:timeZoneOffset];
      

      一个小提示:我使用了 dateByAddingTimeInterval,它仅适用于 iOS 4。如果您使用的是 OS 3 或更早版本,请使用 addTimerInterval。

      【讨论】:

      • 这也是一个不太理想的解决方案。正如 Felixyz 在对 Alex 的回复中指出的那样,您不想弄乱 NSDate 本身,而是弄乱它的表示。 Howard 的回答将给出 NSDate 的“本地化”表示。
      • 一个 NSDate 代表一个时间点,与时区无关。您的对象 localDate 代表与 gmtDate 相同的点。当您将其转换为字符串时,您仍然需要在两者上使用 DateFormatter,并获得相同的结果。
      【解决方案6】:

      您是否尝试过查看 NSDateFormatter 的文档?

      NSDateFormatter

      NSDateFormatter 似乎有一些玩 TimeZones 的方法,特别是

      -setTimeZone:

      我自己没有测试过,但我想如果您将 GMT 设置为最初以另一个时区表示的日期的时区,它将显示正确调整以匹配新时区的日期。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-01-28
        • 2014-01-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-15
        • 2018-04-13
        相关资源
        最近更新 更多