【问题标题】:RFC 3339 date formatters - why is output date shifted by one day?RFC 3339 日期格式化程序 - 为什么输出日期会偏移一天?
【发布时间】:2017-02-15 23:15:14
【问题描述】:

我们在使用 Objective-c 开发的现有 iOS 应用程序中收到了一个问题。

问题:输出日期前移一天,仅适用于 PST 时区。

我们编写了以下代码,用于将日期转换为短格式。

-(NSString *)getDisplayDateFormat:(NSString *)dateString
{
    NSLocale *enUSPOSIXLocale;
    NSDateFormatter *inputformatter = [[NSDateFormatter alloc] init];
    enUSPOSIXLocale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
    [inputformatter setLocale:enUSPOSIXLocale];
    inputformatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
    [inputformatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssSSSZZZZ"];
    NSDate *date= [inputformatter dateFromString:dateString];
    NSDateFormatter *OutPutformatter = [[NSDateFormatter alloc] init];
    [OutPutformatter setDateFormat:@"yyyy-MM-dd"];
    NSString *dispalyDateString = [OutPutformatter stringFromDate:date];
    return dispalyDateString;
}

输入日期字符串 = 2017-01-16T00:00:00-06:00

UTC 格式:日期 = 2017-01-16 06:00:00 +0000

输出日期字符串 = 2017-01-15

请帮助我们解决问题。

【问题讨论】:

  • 没有错。你所看到的是预期的。不仅仅是 PST(美国西海岸)。对于时区偏移大于 -6(更西部)的任何设备,它将显示 1 月 15 日。
  • 2017-01-16T00:00:00-06:00(例如芝加哥 1 月 16 日凌晨的午夜),洛杉矶 1 月 15 日晚上 10 点。所以你的输出是有意义的。问题是你更广泛的目标是什么。你是说你不在乎什么时候发生的事情,只关心它发生在哪一天?那么您可能根本不应该在日期字符串中包含时间部分。退后一步,您应该编辑您的问题以描述更广泛的设计目标,我们可以建议如何解决它。
  • 感谢您的澄清,我从服务器获取日期“2017-01-16T00:00:00-06:00”,需要转换为 2017-01-16。请提出建议。
  • 如果日期字符串没有反映某个时刻,而只是反映了一个日期,那么您确实应该更改 Web 服务以仅返回日期。实际上,您应该只获取前 10 个字符,然后通过格式化程序运行它。

标签: ios objective-c nsdate nsdateformatter rfc3339


【解决方案1】:

如果您想捕获日期时间字符串的日期部分的字符串表示形式,无论使用的本地时区是否与您自己的不同,最简单的方法是忽略所有时间和时区信息,直接抓取日期部分。以最简单的形式,您可以这样做:

- (NSString *)getDisplayDateFormat:(NSString *)dateString {
    return [dateString substringToIndex:10];
}

或者,如果您真的打算将其转换为设备的区域设置(以防用户不使用公历),那么您可以这样做:

- (NSString *)getDisplayDateFormat:(NSString *)dateString {
    NSDateFormatter *inputFormatter = [[NSDateFormatter alloc] init];
    NSLocale *enUSPOSIXLocale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
    [inputFormatter setLocale:enUSPOSIXLocale];
    [inputFormatter setDateFormat:@"yyyy-MM-dd"];
    NSDate *date = [inputFormatter dateFromString:[dateString substringToIndex:10]];
    NSDateFormatter *outputFormatter = [[NSDateFormatter alloc] init];
    [outputFormatter setDateFormat:@"yyyy-MM-dd"];
    return [outputFormatter stringFromDate:date];
}

再一次,如果您尝试转换为用户的日历,您可能不会使用yyyy-MM-dd 格式,而是使用一些用户友好的dateStyle

【讨论】:

    【解决方案2】:

    有人真的知道现在几点吗?试试这个:

    - (void)viewDidLoad {
        [super viewDidLoad];
        NSString *d = @"2017-01-16T00:00:00-06:00";
    
        NSArray *abbrevs = @[@"UTC", @"EDT", @"PST", @"HST", @"JST"];
    
        NSArray *names = @[@"UTC", @"America/New York", @"America/Los Angeles", @"Pacific/Honolulu", @"Asia/Japan"];
    
        for (int n = 0; n < abbrevs.count; n++) {
    
            NSString *na = abbrevs[n];
            NSString *nm = names[n];
            NSString *r = [self getDisplayDateFormat:d inTimeZone:[NSTimeZone timeZoneWithAbbreviation:na]];
    
            NSLog(@"Time is %@ in %@ (%@)", r, nm, na );
    
        }
    }
    
    -(NSString *)getDisplayDateFormat:(NSString *)dateString inTimeZone:(NSTimeZone*)tz
    {
        NSLocale *enUSPOSIXLocale;
        NSDateFormatter *inputformatter = [[NSDateFormatter alloc] init];
        enUSPOSIXLocale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
        [inputformatter setLocale:enUSPOSIXLocale];
        inputformatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
        [inputformatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssSSSZZZZ"];
        NSDate *date= [inputformatter dateFromString:dateString];
        NSDateFormatter *OutPutformatter = [[NSDateFormatter alloc] init];
        //[OutPutformatter setDateFormat:@"yyyy-MM-dd"];
        // show the time also, for clarity 
        [OutPutformatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
        // This is important! You must set the TimeZone for the output string - otherwise you get the local / device timezone
        OutPutformatter.timeZone = tz;
        NSString *dispalyDateString = [OutPutformatter stringFromDate:date];
        return dispalyDateString;
    }
    

    【讨论】:

    • 所以,我对在 SO 上发帖还是比较陌生...很好奇为什么有人会否决这个答案?
    • 我没有投反对票,但它可能被否决了,因为这并不能解决 OP 的问题。他有一个 ISO8601 字符串,他想知道日期组件是什么。他不想在他的本地时区看到日期。这就是他的原始代码的问题,您在这里简单地复制了它。
    • 感谢罗布的评论。我试图向 OP 传达实际的 date 和日期如何呈现,是两个独立的东西。如果我用通俗易懂的语言解释它,而不是提供演示代码,也许会是一种更好的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-06
    • 1970-01-01
    • 2012-01-08
    • 1970-01-01
    • 2012-11-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多