【问题标题】:How can I treat dates as if there were no DST adjustment?如何将日期视为没有 DST 调整?
【发布时间】:2013-02-08 12:53:15
【问题描述】:

编辑:我的解决方案如下。

我有一种与日历相关的应用程序,用户可以在其中前后跳转特定整数天数。在午夜左右测试应用程序时,我意识到存在与 DST 相关的问题,我正在寻找最佳解决方案。

该应用并非真正基于 iOS 中的任何日历。但是,我显示的是公历日期和时间,以便用户参考熟悉的日期和时间。

其中一个内置的时间跳跃是 73 天,大约是 1/5 年。常用日期为 3 月春分 +/- 73 天的整数倍。例如,当从 3 月分点跳到 73 天前的某个日期时,问题就出现了,因为 3 月分点可能在 DST,而另一个则不是。这取决于系统上的时区设置。但是,该应用程序与时区无关,因此我宁愿显示时间,就好像没有 DST 这样的东西,但仍使用本地时区。我希望这是有道理的。

关于如何实现这一点的任何建议?如果问题太模糊,也许我可以添加更多细节,但我不想通过添加太多来混淆事情。

编辑:我决定链接来自应用程序的示例屏幕打印以说明正在发生的事情。这张照片: http://victorspictures.com/trollart/h37a90c77#h56122c20 显示了今年春分的配置。标题说明了如何读取设备。按照图库中接下来的两张图片,了解如何使用该设备计算复活节的日期。

无论如何,滑动手势允许用户移动 +/- 1 天或 +/- 73 天,这就是问题所在。我正在为日期显示添加时间,也许这就是我需要做的。

解决方案:Celeda 的建议

添加了这个方法:

- (NSDate *)setNoon: (NSDate *)date
{
   NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
   NSDateComponents *components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:date];
   [components setHour:12];
   NSDate *todayNoon = [calendar dateFromComponents:components];
   return todayNoon;
}

然后,无论哪里发生跳转,它都被简单地封装在新方法中:

newDate = [self setNoon:[previousCode]];

【问题讨论】:

  • 如果您的日期在中午而不是午夜前后跳跃会有帮助吗(然后如果需要,在流程结束时转换回午夜以进行数据库存储/显示)?这是一种技巧,但它可能比“真正”的解决方案更容易解决您的问题。
  • 我想到了这一点,并开始在脑海中思考如何去做。我的应用程序的时代是 1975 年春至,即当地时间午夜前 3 分钟,起初我认为午夜前几分钟是问题,所以我将时代切换到午夜,这只是将问题转移了一个多小时。我发现了这一点,因为我做了大约一个小时的同类测试,呵呵。我在想也许我应该做一些事情,比如获取本地时区,检查 DST 是否生效,然后将时区设置为与 GMT 的偏移量,而不是使用时区名称。
  • 我不是 iOS 程序员,所以我不能这么说,但总的来说,每当你尝试使用整数而不是日期时,你都会遇到这样的问题。日期/时间库的良好实现会考虑 DST 和时区。 “一天”并不总是 24 小时,它可能是 23、24、25 甚至介于两者之间的一小部分 - 取决于有效的 DST 规则。
  • @Matt,我使用的是日期对象,而不是整数。对于有问题的设备,“一天”并不总是 24 小时,因为该设备根本不计算小时数。该设备的基本单位是一天。应用程序中的当地时间午夜更改日期。
  • 如果没有 DST,您的计算就会出错,并且您向用户显示的日期也会不正确。某个日期+/-某个天数应该包括夏令时,否则计算错误,你“错过”了一天。

标签: ios timezone dst


【解决方案1】:

根据您对 Hot Licks 的回答的评论,您似乎有一些数字 d 代表自 1975 年春分(UTC 时间为 1975 年 3 月 21 日 05:57:00)以来的天数,并且您想要算出公历上对应的日子。

我们可以使用NSDateNSCalendarNSDateComponents 类来执行此计算。为了避免 DST 的影响,我们需要将日历和格式化程序的时区设置为 UTC。

NSInteger d = 73 * 189; // days since the 1975 vernal equinox

NSTimeZone *utcTimeZone = [NSTimeZone timeZoneWithName:@"UTC"];

NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
calendar.timeZone = utcTimeZone;
NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 
formatter.dateFormat = @"yyyy-MM-dd";
formatter.timeZone = utcTimeZone;

NSDateComponents *epochComponents = [[NSDateComponents alloc] init];
epochComponents.year = 1975;
epochComponents.month = 3;
epochComponents.day = 21;
epochComponents.hour = 5;
epochComponents.minute = 57;
epochComponents.timeZone = utcTimeZone;
NSDate *epochDate = [calendar dateFromComponents:epochComponents];
NSLog(@"epochDate=%@", epochDate);
NSLog(@"epochDate from formatter=%@", [formatter stringFromDate:epochDate]);

NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
offsetComponents.day = d;

NSDate *computedDate = [calendar dateByAddingComponents:offsetComponents toDate:epochDate options:0];
NSLog(@"computedDate=%@", computedDate);
NSLog(@"computedDate from formatter=%@", [formatter stringFromDate:computedDate]);

尝试在日历和/或格式化程序上注释掉将时区设置为 UTC 的行,以查看 DST 如何更改结果。

欲了解更多信息,请阅读Date and Time Programming Guide

【讨论】:

  • 公历中没有进行日期跳转,因此使用 NSDate 方法不相关。无论如何,我的问题是一个简单的问题:我可以以某种方式使用一个虚构的时区,就像当地时区但没有 DST?我想我已经决定不走那条路了,但我还是想知道答案。
  • UTC 没有夏令时。既然可以使用真实时区,为什么还要使用虚构时区?
  • 另外,您还没有提供有关如何表示日期或进行计算的任何信息。因此可以合理地假设您使用的是 SDK 提供的标准对象。如果不是这样,您需要解释您如何表示您的日期并使用它们进行计算。
  • 我说,“该应用程序并非真正基于 iOS 中的任何日历。” NSDate 类假定一个日历。我正在使用的日历不是可用的日历之一,因为它是我发明的。请参阅我的原始帖子,我已通过应用程序的屏幕打印链接对其进行了编辑。如果您愿意,还可以在 victorengel.com/trollcalendar 阅读该应用程序的工作原理。不过,它需要更新应用程序的新版本。
  • 我已根据您对 Hot Licks 答案的评论修改了我的答案。
猜你喜欢
  • 2013-02-21
  • 2016-07-29
  • 2013-10-31
  • 2019-11-20
  • 1970-01-01
  • 2021-12-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多