Objective-C,如何以UTC时区获取当前日期?

时间:2013-01-29 21:23:36

标签: ios objective-c nsdate nsdateformatter

我在尝试:

NSDate *currentDateInLocal = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:SS.SSS'Z'"];
NSString *currentLocalDateAsStr = [dateFormatter stringFromDate:currentDateInLocal];

NSDateFormatter * dateFormatter2 = [[NSDateFormatter alloc] init];
NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
[dateFormatter2 setTimeZone:timeZone];
[dateFormatter2 setDateFormat:@"yyyy-MM-dd'T'HH:mm:SS.SSS'Z'"];
NSDate *currentDateInUTC = [dateFormatter2 dateFromString:currentLocalDateAsStr];

但它仍然不代表当前的UTC时间,我该如何实现呢?

由于

8 个答案:

答案 0 :(得分:51)

你过度复杂了。

NSDate没有时区或日历。 [NSDate date]获取当前日期,这是对历史时刻的衡量。如果我在欧洲运行[NSDate date]与您在美国运行它的时间完全相同,那么我们将获得完全相同的值。

如何打印日期取决于日历和时区。因此,在公历中打印的日期与在儒略历中打印的日期不同。 UTC格里高利历中打印的日期与PST公历中打印的日期不同。但他们仍然是同一个日子。

所以你想直接跳到你的dateFormatter2

答案 1 :(得分:42)

NSDate *currentDate = [[NSDate alloc] init];

现在是UTC,(至少在使用下面的方法之后)
要将此时间存储为UTC(自参考日期1970起),请使用

double secsUtc1970 = [[NSDate date]timeIntervalSince1970];

设置日期格式化程序以输出本地时间:

NSTimeZone *timeZone = [NSTimeZone defaultTimeZone];
// or Timezone with specific name like
// [NSTimeZone timeZoneWithName:@"Europe/Riga"] (see link below)
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:timeZone];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
NSString *localDateString = [dateFormatter stringFromDate:currentDate];

Available NSTimeZone names

NSDate对象始终使用UTC作为时间参考,但日期的字符串表示不一定基于UTC时区。

请注意,UTC不是(仅)一个时区,它是一个系统如何测量地球上的时间,如何协调(UTC中的C代表协调)。
NSDate与UTC时间1.1.1970午夜的参考日期相关,尽管Apple稍微错误地将其描述为1.1.1970 GMT。

在最初的问题中,最后一个词timeZone并不完美。

答案 2 :(得分:38)

接受的answer by Alex Wien 不正确

默认情况下,NSDateFormatter会将NSDate的日期时间值从UTC调整为用户的本地时区。要防止这种调整,请告诉NSDateFormatter使用UTC的时区。

要验证结果,请点击“当前时间utc”。

我的源代码应该完成这项工作,这意味着将当前日期时间作为ISO 8601 formatUTC)时区Zulu中的字符串获取,表示为{{1最后。

Z

您可以将此逻辑放在应用程序中的某个便捷方法中。

NSDate* datetime = [NSDate date];
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]]; // Prevent adjustment to user's local time zone.
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
NSString* dateTimeInIsoFormatForZuluTimeZone = [dateFormatter stringFromDate:datetime];

...和...

- (NSString*)now
{
    // Purpose: Return a string of the current date-time in UTC (Zulu) time zone in ISO 8601 format.
    return [self toStringFromDateTime:[NSDate date]];
}

使用示例......

- (NSString*)toStringFromDateTime:(NSDate*)datetime
{
    // Purpose: Return a string of the specified date-time in UTC (Zulu) time zone in ISO 8601 format.
    // Example: 2013-10-25T06:59:43.431Z
    NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
    [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
    NSString* dateTimeInIsoFormatForZuluTimeZone = [dateFormatter stringFromDate:datetime];
    return dateTimeInIsoFormatForZuluTimeZone;
}

或者将这些减号转换为加号以用作类方法而不是实例方法......

NSString* now = [self now];

提示:为了提高人类的可读性,请将格式中的NSString* now = [SomeClassNameHere now]; 更改为SPACE。为了通过软件实现更好的互操作性,请保留T。 ISO 8601规范允许空格,但建议保留T


提示:我没有测试过,但是......有人说实例化T很贵。如果经常这样做(例如在循环中),请考虑缓存单个实例以供重用。

答案 3 :(得分:10)

请设置日历标识符!!!

我还不太晚!因为我看到没有人设置日历标识符。对全球用户来说,非常重要。许多用户使用非公历。他们会错误的一年串。特别是,当您需要将其存储到您自己的数据库中时。 (我们之前遇到过这个问题)

NSCalendarIdentifierGregorian
NSCalendarIdentifierBuddhist
NSCalendarIdentifierChinese
NSCalendarIdentifierHebrew
NSCalendarIdentifierIslamic
NSCalendarIdentifierIslamicCivil
NSCalendarIdentifierJapanese
NSCalendarIdentifierRepublicOfChina
NSCalendarIdentifierPersian
NSCalendarIdentifierIndian
NSCalendarIdentifierISO8601

代码:

-(NSString *)getUTCFormateDate:(NSDate *)localDate
{
    NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
    NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
    [dateFormatter setCalendar:gregorianCalendar];
    [dateFormatter setTimeZone:timeZone];
    [dateFormatter setLocale:locale];
    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSString *dateString = [dateFormatter stringFromDate:localDate];
    return dateString;
}  

答案 4 :(得分:2)

[NSDate日期]是UTC。也许你被当地人看到了?然后它会转换为您的时区。

如果您在本地时间看到该值,则会在本地时间看到它,但如果您在控制台中打印它,则会以UTC格式看到它。

当您在时间之后看到'+0000'时,您知道它是UTC

答案 5 :(得分:1)

Swift 3

let utcTimestamp = Date().timeIntervalSince1970
print("timeStamp = \(utcTimestamp)")

跟随扩展可能会更容易。

Swift 4 :UTC /GMT⟺本地(当前/系统)

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)
    }

}


// Try it
let utcDate = Date().toGlobalTime()
let localDate = utcDate.toLocalTime()

print("utcDate - (utcDate)")
print("localDate - (localDate)")

答案 6 :(得分:0)

另一种方法是在Objective C项目的C ++类中这样做。 (因此,制作一个.mm文件并使用公共和私有部分构建一个C ++类,并将其粘贴在公共部分(除非您需要私有)。)然后,像NSString *sNowUTC = MyClass::getUTCTimestamp();一样引用它。

static NSString *getUTCTimestamp(){
  time_t rawtime;
  struct tm * timeinfo;
  char buffer [80];
  time (&rawtime);
  timeinfo = gmtime (&rawtime);
  // make format like "2016-06-16 02:37:00" for 
  //   June 16, 2016 @ 02:37:00 UTC time
  strftime (buffer,80,"%F %T",timeinfo);
  std::string sTime(buffer);
  NSString *sUTC = @(sTime.c_str());
  return sUTC;
}

答案 7 :(得分:0)

这就是我使用的。

static func makeISO8601Date(isoDateString: String) -> Date {
    let formatter = DateFormatter()
    formatter.calendar = Calendar(identifier: .iso8601)
    formatter.locale = Locale(identifier: "en_US_POSIX")
    formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"

    return formatter.date(from: isoDateString)
}

makeISO8601Date(isoDateString: "2017-12-31T23:59:59+00:00")