建议多个日历,日期和持续时间使用哪种数据结构?

时间:2011-03-25 01:05:22

标签: delphi datetime date calendar firebird

我需要存储多个不同日历的日期和持续时间。特别是我需要存储以下日期:

  1. 在不同时间将更改跨越到不同国家/地区的Gregorian日历
  2. 涵盖至少500年的历史性时期
  3. 处理多种类型的日历 - 月球,太阳能,中国,金融,基督教,UTC,穆斯林。
  4. 处理英国3月31日至12月31日年底的变化,以及其他国家的可比变化。
  5. 我还需要存储我定义为两个时间戳(日期和时间)之间差异的持续时间。这意味着需要能够存储“零”日期 - 所以我可以存储持续时间,比如说,三个半小时;或10分钟。

    我需要details次计算。 Firebird的时间戳基于日期函数,该函数从公元100年1月1日开始,因此无法按照我需要记录它们的方式使用。此外,此数据类型已准备好(与大多数时间戳功能一样),以记录自基准日期以来的天数;它不适合记录日历日期。

    有人可以建议:

    1. 用于存储符合上述要求的日期和持续时间的数据结构或
    2. 对此类数据结构的引用或
    3. 提供指导以构建此类存储的准则或
    4. 任何可以帮助我解决的问题。
    5. 修改

      @Warren P在他的回答中提供了一些出色的工作。我显然没有完全解释我所寻求的内容,因为他的工作主要集中在计算以及如何计算这些计算上。所有有价值和有用的东西,但不是我打算传达的问题。

      我确实掌握了在各种日期表示之间进行转换所需的所有计算的详细信息,并且我对如何实现它们有了相当好的想法(使用Warren建议的元素)。但是,我的要求是存储符合上面列出的各种标准的日期。示例:要存储的日期 - 'June June 13 Charles II'。我正在尝试确定存储此类日期的适当结构。

      修改

      我修改了我提出的架构。我已在每个表中列出了属性,并通过示例定义了表和属性,在实体框的第三部分中给出。我通过示例在我的定义中使用了此questionanswer中给出的示例,并修改了我的问题中的示例以进行对应。虽然我通过描述其他人的例子证明了我的模式,但这种模式可能仍然过于复杂;过分析;错过了一些明显的简化,可能很难实现(事实上,这可能是完全错误的)。任何意见或建议都是最受欢迎的。

      enter image description here

2 个答案:

答案 0 :(得分:10)

如果您正在编写自己的,我假设您打算这样做,我会创建一个包含TDateTime和其他字段的类,并且我将基于Python编写的非常好的mxDateTime扩展中的功能,是非常容易阅读,开源,C代码,您可以用来提取您将需要的格里历日历逻辑。

在一定限度内,TDateTime始终是正确的。它的纪元价值(0)是1899年12月30日午夜。从那里,您可以计算其他朱利安日数。它支持负值,因此它将支持超过400年。我相信在最后一次格里高利历改革时你将开始做更正。如果你从1582年10月15日星期五开始,并找出它的朱利安日数,以及之前和之后的改革,你应该能够做你需要的一切。请注意,一天中的时间在1899年之前“向后”运行,但这在人脑中纯粹是一个问题,计算机将是准确的,并将计算分钟数和秒数,直到双精度浮点数的极限数学为你。坚持使用TDateTime作为基础。

我发现了一些非常古老的BorlandPascal / TurboPascal代码,可以处理各种各样的日期here

如果您需要处理阿拉伯语,犹太语和其他日历,我再次将您称为Python作为工作示例的重要来源。不仅仅是mxdatetime扩展,还有this等内容。

对于数据库持久性,如果您需要的最大分辨率为1秒,您可能希望将日期存储基于朱利安日数,将您的时间作为自午夜以来的C样秒数。

这是我要开始的代码片段,并在以下代码完成代码:

TCalendarDisplaySubtype = ( cdsGregorian,cdsHebrew,cdsArabic,cdsAztec,
   cdsValveSoftwareCompany, cdsWhoTheHeckKnows );
TDateInformation = class
      private
         FBaseDateTime:TDateTime;
         FYear,FMonth,FDay:Integer; // if -1 then not calculated yet.
         FCalendarDisplaySubtype:TCalendarDisplaySubtype;
      public 

        function SetByDateInCE(Y,M,D,h,m,s:Integer):Boolean;
        function GetAsDateInCE(var Y,M,D,h,m,s:Integer):Boolean;
        function DisplayStr:String;
        function SetByDateInJewishCalendar( ... );
        property BaseDateTime:TDateTime read FDateTime write FDateTime;
        property JulianDayNumber:Integer read GetJulianDayNumber write SetJulianDayNumber;
        property CalendarDisplaySubType:TCalendarDisplaySubtype;



   end;

我认为没有理由同时存储朱利安日数和TDateTime,只需使用常量,从Trunc(FBaseDateTime)值中减去/加,然后在GetJulianDayNumber中返回SetJulianDayNumber函数。可能值得拥有您为给定日历计算年,月,日的字段,并存储它们,使显示为字符串函数更简单,更快。

更新:看起来你在ER建模方面比我更好,所以如果你发布了这个图表,我就会投票给它,那就是它。至于我,我将存储三个领域;标准化为现代日历标准的Datetime字段,包含任何形式的原始学术日期的文本字段(自由格式),以及一些其他字段,即子类型查找表外键,以帮助我组织和搜索日期按日期和子类型。那对我来说就是IT。

答案 1 :(得分:3)

只是部分答案,但重要的一部分。

由于您要在很大范围内存储日期,日历中发生了很多事情,因此您需要适应这些变化。

时区数据库TZ-database和TZ数据库周围的Delphi TZDB wrapper将会有很大帮助。
它有一个数据库,规定了时区的历史表现。

我知道它们基于当前的日历方案,您需要先转换为UTC。

您需要为要支持的其他日历方案设计类似的内容。

编辑:

我使用的方案是这样的:

  • 找到所有日历转换为UTC的方法
  • 存储日历类型
  • 以原始格式存储日期,以及日期来源(以防万一您的来源搞砸了,您需要重新计算)。
  • 使用UTC转换从原始版本通过UTC转换为UI中的日历类型

- 的Jeroen