C#:将 AS/400 日期转换为 DateTime

发布于 2024-07-28 22:13:38 字数 453 浏览 4 评论 0 原文

DB2 AS/400 中的日期是一个整数,包含自 20 世纪初的某个时间以来的天数。

问题 1:有人知道 IBM DB2/AS400“”日期吗? 例如:

  • 12/30/1899
  • 12/31/1899
  • 1/1/1900

问题 2:给定一个“AS/400”日期(例如 40010),如何将其转换为 CLR DateTime?

DateTime d = new DateTime(40010); //invalid

其他一些“零”日期是:

  • OLE 自动化:1899 年 12 月 30 日
  • SQL Server:1900 年 1 月 1 日

Dates in DB2 AS/400 are an integer, containing the number of days since sometime around the turn of the 20th century.

Question 1: Does anyone know the IBM DB2/AS400 "zero" date? e.g.:

  • 12/30/1899
  • 12/31/1899
  • 1/1/1900

Question 2: Given an "AS/400" date (e.g. 40010) how can you convert that to a CLR DateTime?

DateTime d = new DateTime(40010); //invalid

Some other "zero" dates are:

  • OLE Automation: 12/30/1899
  • SQL Server: 1/1/1900

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

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

发布评论

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

评论(6

蝶舞 2024-08-04 22:13:38

我不认为 AS/400 日期在内部存储为距纪元日期 1 的一定天数(这是您所说的“零日期”的更常见术语)。 正如 Tracy Probst 所说,这绝对不是本机 AS/400 物理文件中的日期字段。2

但是,如果您使用任何方法提取数据并将其作为自纪元以来的天数。 理想情况下,您应该通过直接查看 AS/400 或询问能够了解的人来找出预期日期。 如果 AS/400 上的日期是 2009-07-30 并且您得到的是 40022,那么您可以非常确信纪元日期是 1900 年 1 月 1 日。如果您得到 40024,那么纪元就是 12 月 30 日, 1899。(当然最好是比较一堆日期,最好是来自不同年份的日期,以防止可能使用儒略日期。)

此外,正如特雷西对他自己的答案的评论,日期以通用数字形式存储是非常常见的字段(如果您的检索方法将 Decimal 报告为数据类型,我会猜测),在这种情况下,它确实与 DB2 的内部日期格式无关。 您应该知道,到目前为止,存储在 AS/400 数字字段中的最常见日期格式如下或其变体:

  • yyyymmdd(公历,ISO 4 位数年份)
  • mmddyy(公历,美国 2 位数年份)
  • yyyyddd(因此-所谓的 Julian,4 位数字年份)
  • yyddd(所谓的 Julian,2 位数字年份)
  • yymmdd
  • cyymmdd(带有世纪标志的 IBM 疯狂发明)

Julian 日期中的 ddd 是从年初算起的天数。 IBM 疯狂日期中的 c 是 0 代表 19yy,1 代表 20yy。 我没有听说过有人在“四百”上存储自纪元以来的天数,但也许您遇到过来自其他平台的转换者。 AS/400 的大型机传统非常支持人类可读的日期。


1AS/400(现在称为 IBM i)确实有自己的日期数据类型,并且该数据类型实际上确实内部包含一个纪元的天数。 但那个时代是过去几千年,而不是20世纪初世纪,甚至还没有接近Common Era开始。 IBM 喜欢将这个天数称为“Scaliger 数”,但对于大多数研究这些东西的人来说,它被称为“儒略日数”。 正如您可能从我的回答的主要部分中注意到的那样,IBM 使用“Julian”一词来表示完全不同的东西(甚至与 儒略历)。 也就是说,IBM 所谓的“儒略日期”实际上是 ISO 8601 的序数日期

2日期数据类型的内部格式非常低级,并且大部分对用户(包括大多数程序员)隐藏。 DSPPFM 命令表面上显示文件的“实际内容”,但至少“为时已晚”了一步:它报告的值已经从内部 4 字节“Scaliger 数字”转换为人类可读的值形式。

I don't think AS/400 dates are stored internally as some number of days from an epoch date1 (this is the more common term for what you are calling "zero date"). As Tracy Probst said, this is definitely NOT what date fields in native AS/400 physical files look like.2

But that's immaterial if whatever method you are using to extract the data is giving it to you as the number of days since an epoch. Ideally, you should find out what the intended date is by looking directly at the AS/400, or asking someone who can. If the date on the AS/400 is 2009-07-30 and what you are getting is 40022, then you can be pretty confident the epoch date is Jan 1, 1900. If you are getting 40024, then the epoch is Dec 30, 1899. (Though it's of course best to compare a bunch of dates, preferably from different years to guard against possible use of Julian dates.)

Also, as Tracy commented on his own answer, it's exceedingly common for dates to be stored in generic numeric fields (which is what I would guess if your retrieval method is reporting Decimal as the data type), in which case it really has nothing to do with DB2's internal date format anyway. You should be aware that by far the most common date formats stored in AS/400 numeric fields are the following, or variations thereof:

  • yyyymmdd (Gregorian, ISO 4-digit year)
  • mmddyy (Gregorian, U.S. 2-digit year)
  • yyyyddd (so-called Julian, 4-digit year)
  • yyddd (so-called Julian, 2-digit year)
  • yymmdd
  • cyymmdd (IBM's crazy invention with century flag)

The ddd in the Julian dates is the number of days from the beginning of year. The c in IBM's crazy date is 0 for 19yy or 1 for 20yy. I have not heard of anyone who stores days-since-epoch on "The Four Hundred" but maybe you've encountered a convert from another platform. The mainframe heritage of the AS/400 strongly favors human-readable dates.


1The AS/400 (now called IBM i) does have its own data type for dates, and this data type actually does consist internally of a number of days from an epoch. But that epoch is many thousands of years in the past, not somewhere near the turn of the 20th century, and not even near the beginning of the Common Era. IBM likes to call this number of days the Scaliger number, but for most people who study this stuff, it's called the Julian Day Number. As you may have noticed from the main part of my answer, IBM uses the word "Julian" to mean something completely different (and not even related to the Julian calendar). Namely, IBM's so-called "Julian date" is really the ordinal date from ISO 8601.

2The internal format of the date data type is very low-level and mostly hidden from the user (including most programmers). The DSPPFM command, which ostensibly shows the "actual contents" of a file, is at least one step "too late": the value it reports has already been converted from the internal, 4-byte "Scaliger number" to a human-readable form.

童话里做英雄 2024-08-04 22:13:38

问题 1:

我不知道 DB2 的开始日期是哪一天。 无论如何,谷歌并不是很有帮助。 您没有可以用来解决这个问题的示例数据吗?

更新:您确定日期存储为天数吗? 我发现此页面表明并非如此。

问题 2:

假设 1900-01-01 作为本示例中的开始日期,其中 days 是 AS/400 日期值。

DateTime myDate = new DateTime(1900, 1, 1).AddDays(days);

Question 1:

I have no idea what the start date is for DB2. Google isn't very helpful anyway. Don't you have any sample data you could use to figure it out?

Update: are you sure the date is stored as a number of days? I found this page that suggests otherwise.

Question 2:

Assuming 1900-01-01 as the start date in this example, where days is the AS/400 date value.

DateTime myDate = new DateTime(1900, 1, 1).AddDays(days);
玻璃人 2024-08-04 22:13:38

我不知道 1 的答案。但是对于 2,你可以这样做:

private DateTime AS400 = new DateTime(1900, 1, 1);

...


DateTime myClrDT = AS400.AddDays(days);

I don't know the answer for 1. But for 2, you can do something like this:

private DateTime AS400 = new DateTime(1900, 1, 1);

...


DateTime myClrDT = AS400.AddDays(days);
放血 2024-08-04 22:13:38

问题 1:

据我所知,AS/400 物理文件中不存在“零日期”。 如果我对其中包含时间戳字段的物理文件执行 DSPPFM,则该值将以 yyyy-MM-ddhh.mm.ss 格式存储为可读时间戳。 例如:“2005-08-0207.06.33”表示 2005 年 8 月 2 日上午 7:06:33。 特定编程语言中可能存在零日期,这确实是您需要关注的地方。 AS/400 ODBC 驱动程序在 SQL_TYPE_TIMESTAMP 字段中返回日期。

问题 2:

应该很简单:

DateTime d = Convert.ToDateTime(reader["DateField"]);

我邀请其他 C# 专家用更好的 C# 代码编辑响应。

Question 1:

As far as I can tell, there is no "zero date" in an AS/400 phsyical file. If I do a DSPPFM on a phsyical file with a timestamp field in it, the value is stored as a readable timestamp in the format yyyy-MM-ddhh.mm.ss. For example: "2005-08-0207.06.33" for 08/02/2005 at 7:06:33 AM. There can be a zero-date within a particular programming language and that's really where you need to focus. The AS/400 ODBC driver returns the date in a SQL_TYPE_TIMESTAMP field.

Question 2:

It should be as simple as:

DateTime d = Convert.ToDateTime(reader["DateField"]);

I invite other C# experts to edit the response with better C# code.

生生漫 2024-08-04 22:13:38

我只有 5 个月的 DB2 经验(在 AS400 上工作),所以我只能向您展示一些东西
关于我们处理日期的方式。 确实,我们在计算日期字段时考虑了“零”日期。 在我们的系统中,“零”日期=12/31/1971 0:00。
我不知道这是否是 AS400 中“唯一”的“零”日期。
在我们的系统文件中,我们使用的日期存储为从“零”日期(长度=5)开始的天数。

因此,每次我们必须从指定文件中获取日期字段时,我们都会将此字段转换为以下格式的日期:dd/mm/yyyy 或 yyyy-mm-dd(这取决于我们执行的环境)询问)。 其功能是:
date(field+719892),其中 field 是我们存储日期的字段,719892 是我们在每次未转换后添加的天数我们使用的日期(好像是x-12/31/1971之间的天数,你可以计算x)。
我会给你更多的例子:

select date(15+719892) as date1 from library1.file1

结果是:date1=1972-01-15

I've just 5 months of experience in DB2(working on AS400), so i just can show you something
about the way we work with dates. It's true that we consider the 'zero' date in our calculation of the date fields. In our system, the 'zero' date =12/31/1971 0:00.
I don't know if this is the 'only' 'zero' date in AS400.
In our system files, the date we use is stored as the number of days from the 'zero' date(length=5).

So, every time we have to get the date field, from a specified file, we convert this field to get the date in the format : dd/mm/yyyy or yyyy-mm-dd(it depends from the environment where we execute the query). The function is:
date(field+719892), where field is the field where we store the date and 719892 is the number of days we add after each unconverted date we use(it seems like it is the number of days between x-12/31/1971, you can calculate x).
I'll give you on more example:

select date(15+719892) as date1 from library1.file1

The result is: date1=1972-01-15

那小子欠揍 2024-08-04 22:13:38

marc_s 有一条评论混淆了 SQL Server 中的“零”日期和“最小”日期。 只是为了让每个人都能看到这个例子:

SELECT 
   CAST(0 AS datetime) AS dateTimeZero,
   CAST(0 AS smalldatetime) AS smallDateTimeZero

dateTimeZero              smallDateTimeZero
=======================   ===================     
1900-01-01 00:00:00.000   1900-01-01 00:00:00

marc_s had a comment that confused the "zero" dates with "minimum" dates in SQL Server. Just so everyone gets to see the example:

SELECT 
   CAST(0 AS datetime) AS dateTimeZero,
   CAST(0 AS smalldatetime) AS smallDateTimeZero

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