从 1600 年到 NSDate 的日期?

发布于 2024-10-11 09:33:07 字数 1495 浏览 2 评论 0原文

我需要处理一个日期,该日期存储为自 1600 年 1 月 1 日以来的天数。这是一种遗留的日期格式,我需要在我的应用程序中多次阅读它。

以前,我一直在创建一个日历、空日期组件和根日期,如下所示:

self.gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar
                    ] autorelease];
id rootComponents = [[[NSDateComponents alloc] init] autorelease];
[rootComponents setYear: 1600];
[rootComponents setMonth: 1];
[rootComponents setDay: 1];
self.rootDate = [gregorian dateFromComponents: rootComponents];
self.offset = [[[NSDateComponents alloc] init] autorelease];

然后,为了稍后将整数转换为日期,我使用这个:(

[offset setDay: theLegacyDate];
id eventDate = [gregorian dateByAddingComponents: offset
                                          toDate: rootDate
                                         options: 0];

我从不更改其他任何地方的偏移量中的任何值。)

问题是我在 iOS 和 Mac OS X 上,rootDate 的时间不同。在 Mac OS X 上,我的时间是午夜。在 iOS 上,我得到的是 8:12:28。 (到目前为止,这似乎是一致的。)当我稍后添加我的天数时,奇怪的时间仍然存在。

OS       | legacyDate | rootDate                  | eventDate
======== | ========== | ==========================|==========================
Mac OS X | 143671     | 1600-01-01 00:00:00 -0800 | 1993-05-11 00:00:00 -0700
iOS      | 143671     | 1600-01-01 08:12:28 +0000 | 1993-05-11 07:12:28 +0000

在我的产品的上一个版本中,我不关心时间;现在我知道了。为什么 iOS 上的时间很奇怪,我该怎么办? (我假设小时差是 DST。)

我尝试将 rootComponents 的小时、分钟和秒设置为 0。这没有影响。如果我将它们设置为 0 以外的值,则会将它们添加到 8:12:28。我一直想知道这是否与闰秒或其他累积时钟变化有关。

或者这在 iOS 上使用完全是错误的方法吗?

I have a date that's stored as a number of days since January 1, 1600 that I need to deal with. This is a legacy date format that I need to read many, many times in my application.

Previously, I'd been creating a calendar, empty date components and root date like this:

self.gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar
                    ] autorelease];
id rootComponents = [[[NSDateComponents alloc] init] autorelease];
[rootComponents setYear: 1600];
[rootComponents setMonth: 1];
[rootComponents setDay: 1];
self.rootDate = [gregorian dateFromComponents: rootComponents];
self.offset = [[[NSDateComponents alloc] init] autorelease];

Then, to convert the integer later to a date, I use this:

[offset setDay: theLegacyDate];
id eventDate = [gregorian dateByAddingComponents: offset
                                          toDate: rootDate
                                         options: 0];

(I never change any values in offset anywhere else.)

The problem is I'm getting a different time for rootDate on iOS vs. Mac OS X. On Mac OS X, I'm getting midnight. On iOS, I'm getting 8:12:28. (So far, it seems to be consistent about this.) When I add my number of days later, the weird time stays.

OS       | legacyDate | rootDate                  | eventDate
======== | ========== | ==========================|==========================
Mac OS X | 143671     | 1600-01-01 00:00:00 -0800 | 1993-05-11 00:00:00 -0700
iOS      | 143671     | 1600-01-01 08:12:28 +0000 | 1993-05-11 07:12:28 +0000

In the previous release of my product, I didn't care about the time; now I do. Why the weird time on iOS, and what should I do about it? (I'm assuming the hour difference is DST.)

I've tried setting the hour, minute and second of rootComponents to 0. This has no impact. If I set them to something other than 0, it adds them to 8:12:28. I've been wondering if this has something to do with leap seconds or other cumulative clock changes.

Or is this entirely the wrong approach to use on iOS?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

我想你对闰秒/累积时钟变化解释时间问题的看法是正确的。您正在处理的日期实际上是过去的日期,还是纯粹是任意的纪元?

无论哪种情况,您都可以尝试定义一个更接近当今的新纪元(例如,Cocoa 纪元)。计算新纪元和旧纪元之间的日差并将其保存为常量。当您需要处理日期时,将此增量应用于日期,然后使用现有的 NSCalendar 技术,但使用新纪元而不是旧纪元。这有望避免您所看到的时钟漂移问题。

I imagine you're right about the leap seconds/cumulative clock changes accounting for the time issue. Are the dates you're dealing with actually in the past, or is it purely an arbitrary epoch?

In either case, you could try defining a new epoch that's much closer to present day (say, the Cocoa epoch). Calculate a day delta between the new epoch and the old and save it as a constant. When you need to process a date, apply this delta to the date and then use your existing NSCalendar technique, but with your new epoch instead of the old. That will hopefully avoid the clock drift issue you're seeing.

跨年 2024-10-18 09:33:07

看起来正确的答案是让事情变得更简单。我每次都只是从组件构建日期,而不是创建 rootDate。这应该不会慢,并且仍然使代码真正接近想法。

初始设置:(

self.gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar
                    ] autorelease];
self.components = [[[NSDateComponents alloc] init] autorelease];
[components setYear: 1600];
[components setMonth: 1];

显然,调整了属性和 ivars。)

稍后,将旧日期实际转换为 NSDate

[components setDay: 1 + theLegacyDate];
id eventDate = [gregorian dateFromComponents: components];

这对我来说有以下优点:

  1. 它使用更少的 ivars。
  2. 代码更少了。
  3. 无论 DST 是否生效,它总是在当天的午夜返回。

It looks like the right answer is to make things simpler. Instead of making a rootDate, I just build the date from components every time. This should be no slower, and is still keeps the code really close to the idea.

Initial setup:

self.gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar
                    ] autorelease];
self.components = [[[NSDateComponents alloc] init] autorelease];
[components setYear: 1600];
[components setMonth: 1];

(Obviously, properties and ivars are adjusted.)

Later, to actually convert a legacy date to a NSDate:

[components setDay: 1 + theLegacyDate];
id eventDate = [gregorian dateFromComponents: components];

This has these advantages for me:

  1. It users fewer ivars.
  2. It's less code.
  3. It always returns midnight on that day, regardless of whether DST is in effect.
北风几吹夏 2024-10-18 09:33:07

请注意,iOS 考虑了不同时区的非常模糊的规则。最有可能的是 1 月 1 日午夜。您所在时区的 1600 实际上是 UTC 时间 7:12:28。在很多情况下,人们抱怨日期转换中的错误,然后有人发现实际上他们所在的时区多年前就发生了一些奇怪的日历更改。

您需要首先找出您的数据代表的确切 NSDate 。 “自 1600 年 1 月 1 日以来的天数”是无稽之谈,因为您需要一个时区!你应该做什么:找到一个“旧”数字,你知道它应该代表哪一天。例如,如果您“知道”您所在时区的 143671 应该是 1993 年 5 月 11 日,则以该日期作为根日期开始并向其添加 (x - 143671) 天。

Note that iOS takes into account very obscure rules for various time zones. It is most likely that midnight, Jan 1st. 1600 in your timezone actually was at 7:12:28 UTC. There have been many cases where people complained about bugs in date conversions and then someone figured out that actually they are in a time zone that made some strange calendar change many years ago.

You need to find out first what exact NSDate your data represents. "Number of days since Jan 1st 1600" is nonsense, because you need a time zone! What you should do: Find a "legacy" number where you know what day it is supposed to represent. For example, if you "know" that 143671 is supposed to be 11th May 1993 in your time zone, then start with that date as the root date and add (x - 143671) days to it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文