NSDate - 调整时区偏移量

7

我可能错过了一些小细节,但是想不出来。尝试创建一个日期进行比较,但是似乎无法将当前日期从格林威治标准时间偏移为东部标准时间(EST):

// current date (gmt) //
NSDate *currentDate = [NSDate date];

NSTimeZone *currentDateTimeZone = [NSTimeZone timeZoneWithAbbreviation:@"EST"];

NSDateFormatter *currentDateFormat = [[NSDateFormatter alloc]init];
[currentDateFormat setTimeZone:currentDateTimeZone];
[currentDateFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss zzz"];

NSString *currentDateString = [currentDateFormat stringFromDate:currentDate];
NSLog(@"currentDateString: %@", currentDateString); // returns 2011-01-05 13:30:30 EST

NSDate *currentDateWithOffset = [currentDateFormat dateFromString:currentDateString];

NSLog(@"currentDateWithOffset: %@", currentDateWithOffset); // returns 2011-01-05 18:30:30 +0000

谢谢!

编辑:

我正在调用另一个类中的方法(试图使其可移植),使用以下代码行:

[Expiration expires:[[NSDate alloc] initWithString:@"2011-01-07 12:00:00 +0000"] within:1.0]

在expires方法中,我有以下几行代码:
NSComparisonResult comparison = [currentDateWithOffset compare:expires]; // check for a fixed date to disable the demo

double withinRange = [installDate timeIntervalSinceDate:currentDateWithOffset]; // check for number of seconds between "within" and the install date

然后我会像这样比较这两个值:

if(withinRange >= within && withinRange > 0.0) {
    // app is expired //
}
else {
    // app is still enabled (so far...) //
    if(comparison == NSOrderedDescending || comparison == NSOrderedSame) {
        // app is expired //
    }
    else {
        // app is still enabled //
    }
}

这对您有帮助吗?感谢您的耐心!

编辑:

以下是expires:within方法的完整代码...

+(BOOL)expire:(NSDate*)expires within:(double)within {
   // default expired value //
    BOOL expired = NO;

    // convert within value from days to seconds //
    within *= 24.0 * 60.0 * 60.0;

    // current date (gmt) //
    NSDate *currentDate = [NSDate date];

    // install date //
    NSDate *installDate = [[NSUserDefaults standardUserDefaults]objectForKey:@"installDate"];

    // check for a value in installDate //
    if (nil == installDate) {
        // app is running for the first time //
        [[NSUserDefaults standardUserDefaults]setObject:currentDate forKey:@"installDate"];
        [[NSUserDefaults standardUserDefaults]synchronize];
        installDate = currentDate;
    }

    if([installDate timeIntervalSinceNow] < (-within)) {
        expired = YES;
    }
    else {
        if([expires timeIntervalSinceNow] < 0) {
            expired = YES;
        }
    }

    NSLog(@"installDate:%@", installDate);
    NSLog(@"expires:%@", expires);
    NSLog(@"currentDate:%@", currentDate);

    return expired; 
}

我现在需要从另一个类中调用它:

message.text = (YES == [Expiration expire:[[NSDate alloc] initWithString:@"2011-01-07 12:00:00 -0500"] within:(0.015625/2)]) ? @"This App is Expired" : @"This App is Active";

在模拟器中(新应用程序安装时),NSLog 显示了以下内容...
[Session started at 2011-01-06 10:43:46 -0500.]
2011-01-06 10:43:48.146 TimeBasedDemo[14717:207] installDate:2011-01-06 15:43:48 +0000
2011-01-06 10:43:48.147 TimeBasedDemo[14717:207] expires:2011-01-07 17:00:00 +0000
2011-01-06 10:43:48.147 TimeBasedDemo[14717:207] currentDate:2011-01-06 15:43:48 +0000

你能更具体地说明你实际想要做什么吗? - Nick Moore
我正在尝试将当前日期/时间与提供的日期/时间进行比较,以用于限时演示应用程序。让我感到困扰的部分是在我的时区(EST)而不是GMT中进行比较。当我调用包含方法时,使用自己的时区比转换为GMT更容易。 - Eric
那段代码看起来完全正确,输出也一样没问题。我猜你的问题是你期望在日志中看到 10:43:48 -0500 而不是 15:43:48 +0000。事实上,这没关系。它们是同一个时间。这只是在调用 NSLog 时的打印格式而已。 - Nick Moore
好的,我现在感觉自己像个真正的白痴... NSLog 在应用了 -0500 的偏移量后将 expires 打印为 GMT。我本来期望看到它是 07:00:00。我现在明白了。感谢你们的帮助。现在我只需要弄清楚如何在每次使用应用程序时调用此方法。再次感谢! - Eric
我想出了如何让最后一部分工作的方法,这样就可以节省一个新的线程了! - Eric
4个回答

17

这些答案都没有给我一个包含当前本地日期的NSDate对象。所以我是这样做的:

NSDate *currentDateWithOffset = [NSDate dateWithTimeIntervalSinceNow:[[NSTimeZone localTimeZone] secondsFromGMT]];

我到处都看到你的脸!感谢你的回答! - Séraphin Hochart

5

NSDate对象表示时间上的一个瞬间,与时区和日历无关。当您打印或解析日期时,时区信息是相关的,但它不会存储在NSDate中。

比如说,您可以像这样创建到期日期:

NSDate *exp=[[NSDate alloc] initWithString:@"2011-01-07 12:00:00 +0000"]

这意味着您希望到1月7日格林威治标准时间中午过期。如果您想在美国东部时间中午过期,请使用-0500创建。您不需要在比较时更改当前时间。

检查时间是否已经过去的一种简单方法是

if ([exp timeIntervalSinceNow]<0) { /* it's expired */ }

您可以通过以下方式查看自安装日期以来是否已经过了seconds秒钟:

if ([installDate timeIntervalSinceNow]<(-within)]) { /* it's expired */}

谢谢,invariant!这有助于澄清一些事情,谢谢。不幸的是,我仍然在时区问题上遇到了问题。installDate是使用currentDate设置的(NSDate *currentDate = [NSDate date];),因此在比较过程中仍存在差异。由于目标是重用类而无需编辑,并允许时区偏移,NSDate是否是实际解决这个问题的方法? - Eric
我相信NSDate是正确的选择,我自己也是这样做的。我认为你误解了NSDate的工作原理。如果你使用[NSDate date]记录安装日期,存储它,然后稍后再次使用[NSDate date](或timeIntervalSinceNow)进行比较,那么它将始终给出在调用这些方法之间经过的时间。时区根本不涉及其中,它只是一种表示方式,用于显示或将其存储为字符串。我在自己的代码中也是这样做的,没有任何问题。 - Nick Moore
我想我还是不明白。我已经编辑了上面的代码,并展示了NSLog的结果... - Eric

0

我进行了一些尝试,并找到了一种“欺骗”偏移量以满足我的需求的方法。从其他阅读中,我猜测NSCalendar可能是更好的长期解决方案,但现在我最终还是进行了更改。

NSDate *currentDateWithOffset = [currentDateFormat dateFromString:currentDateString];

NSDate *currentDateWithOffset = [[NSDate alloc] initWithString:[NSString stringWithFormat:@"%@ +0000", currentDateString]];

这让我得到了所需的结果,并且在我后来使用的比较中起作用。感谢所有背景信息!


你最好花点功夫正确地创建参考日期,这样你就不必混淆当前日期来使其正常工作了。 - Nick Moore
我会试着想办法做到那个。 - Eric

0
在Cocoa中,NSDate是一个没有应用时区信息的日期的抽象表示。请注意,currentDateWithOffset与日期字符串相同,只是处于不同的时区(比其早五个小时)。这是预期的行为,因为NSDate不会保留用于创建它的时区。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接