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

Bac*_*tnz 38 objective-c nsdate nsdateformatter ios

我在尝试:

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];
Run Code Online (Sandbox Code Playgroud)

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

谢谢

Tom*_*mmy 51

你的事情太复杂了.

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

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

所以你想直接跳到你的身边dateFormatter2.

  • 这应该是公认的答案.`NSDate只代表一个绝对的时刻,并没有附带时区.目前在这里的其他答案,包括当前接受的答案,错误地断言"NSDate'是'UTC',这是不正确的.只有这个答案是正确的. (10认同)
  • @AlexWien我完全理解GMT = UTC.文件将"NSDate"的时代指定为"2001年1月1日午夜,格林尼治标准时间"而不仅仅是"2001年1月1日午夜"的原因是"2001年1月1日午夜"并未定义一个时刻.这并不意味着参考日期是"UTC",它只是意味着已经使用UTC来指定它.他们同样可以写"2001年1月1日中欧时间凌晨1点",它的确具有*与他们实际写的相同的含义.然而,并不是所有的"NSDate"都在"CET"中. (2认同)

Ale*_*ien 41

NSDate *currentDate = [[NSDate alloc] init];
Run Code Online (Sandbox Code Playgroud)

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

double secsUtc1970 = [[NSDate date]timeIntervalSince1970];
Run Code Online (Sandbox Code Playgroud)

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

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];
Run Code Online (Sandbox Code Playgroud)

可用的NSTimeZone名称

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

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

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

  • -1没有回答问题; 他要求提供UTC的日期,你已经给了他代码,在当地时区吐出日期. (6认同)
  • 编写的示例代码不正确."Z"表示祖鲁(UTC)时间,但此代码返回当地时间.我建议加入一行:`[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@ "UTC"];` (4认同)
  • @AlexWien不,'Z'表示[祖鲁时间](https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC),这是一个说时区偏移为零("+00:00")的简短方法.换句话说,UTC时间.你应该**永远不要在当地时间结束时加上'Z'.这是荒谬的,比如在日元价格上加上美元符号. (2认同)

Bas*_*que 40

Alex Wien接受的答案错误的.

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

要验证结果,请点击"当前时间utc".

我下面的源代码应该做的工作,这意味着获取当前日期时间为一个字符串ISO 8601格式UTC(祖鲁由表示)时区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];
Run Code Online (Sandbox Code Playgroud)

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

- (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]];
}
Run Code Online (Sandbox Code Playgroud)

…和…

- (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;
}
Run Code Online (Sandbox Code Playgroud)

用法示例......

NSString* now = [self now];
Run Code Online (Sandbox Code Playgroud)

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

NSString* now = [SomeClassNameHere now];
Run Code Online (Sandbox Code Playgroud)

提示:为了提高人类的可读性T,请将格式更改为SPACE.为了通过软件实现更好的互操作性,请保留T.ISO 8601规范允许空间,但建议保留空间T.


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


Yi *_*ang 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;
}  
Run Code Online (Sandbox Code Playgroud)