views:

2036

answers:

6

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
A: 

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
Ian Boyd
Sheesh - you're right. I always assumed the minimal allowed value (1/1/1753) would be the zero date (would have made sense to me)
marc_s
+1  A: 

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);
Thorarin
There's some subtle differences between DB2 and DB2 for AS/400. i guess you could think of "DB2 for AS/400" as "DB2 Lite"
Ian Boyd
i like your, and Erich Mirabal's, idea of adding the decimal value. i was envision things like dividing the difference of ticks...
Ian Boyd
Under the hood, adding days becomes adding ticks. Check using Reflector.
Erich Mirabal
+1  A: 

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);
Erich Mirabal
+1  A: 

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.

Tracy Probst
The DB2 ODBC driver returns the column as 'Currency', which maps to CLR type Decimal.
Ian Boyd
I'm much more of an AS/400 guy than a C# guy, so I invite others to comment. I used the iSeries ODBC driver and created a DSNless Microsoft.Data.Odbc.OdbcConnection. I ran a simple SQL using OdbcCommand. Then I used OdbcReader to read through the data and my timestamp field shows up as a System.DateTime when I look in the locals window during a debug session. Are you reading data differently?
Tracy Probst
Another thing to consider is that the timestamp field in your AS400 physical file might not actually be a timestamp, date, or time field. We RPG and COBOL programmers are notorious for storing dates in numeric fields and then converting them in our programs.
Tracy Probst
I've provided my own answer, but it's largely based on yours, and I've voted you up because it's clear you've at least got actual AS/400 experience.
John Y
+1  A: 

I don't think AS/400 dates are stored internally as some number of days from an epoch date (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.

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.

John Y
Well said, John. You covered what I intended to say, only better said. :-)
Tracy Probst
A: 

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

I hope this can help you.

Jolma