Microsoft SQL Server 2008 Bible

Handling dates and times is probably one of the most complicated and inconsistent topics in SQL. According to our personal experiences, operations with dates often cause confusion and even frustration not only among database users, but in the developers' community, too.

Introduction to complex data types

One of the problems is dates are not actually what they look like. So far we were talking only about simple data types that store one value per row. Date and time data types hold a number of elements (year, day, month, hour, etc.). In programming, such data types are called complex and are often represented as structures. When returned as a database query result, date and time fields appear like strings, but in fact they rather are parts of structures, similar to ones in the example below. (We don't use any specific programming language in this example, but rather some kind of pseudocode.)

STRUCTURE DATE { YEAR DECIMAL(4,0), MONTH DECIMAL(2,0), DAY DECIMAL(2,0) }

STRUCTURE TIME { HOUR DECIMAL(2,0), MINUTE DECIMAL(2,0), SECOND DECIMAL(5,2) }

STRUCTURE DATETIME { YEAR DECIMAL(4,0), MONTH DECIMAL(2,0), DAY DECIMAL(2,0), HOUR DECIMAL(2,0), MINUTE DECIMAL(2,0), SECOND DECIMAL(5,2) }

The displayed value just formats and concatenates the fields of this structure. For example, for the YYYY/DD/MM format, the pseudocode may look like this:

CONCAT(CAST(DATETIME.YEAR, STRING), '/', CAST(DATETIME.DAY, STRING), '/', CAST(DATETIME.MONTH, STRING))

Note 

The Dot (.) notation used in the above example is explained in Chapter 1.

These structures should also have some methods to handle situations when users want to display dates and times in different formats, for example to display time on the 12- or 24-hour scale, show day of week for a certain date, display century, convert it into a different time zone, and so on.

We'll talk more about complex data types later in this chapter.

Date and time implementations

As we've mentioned before, date and time data types are mandated by SQL99 and handled by different RDBMS implementations quite in a different way. Date and time data types are summarized in Table 3-5.

Table 3-5: Date and Time Data Types

SQL99

Oracle 9i

DB2 UDB 8.1

MS SQL SERVER 2000

DATE

DATE

DATE

DATETIME SMALLDATETIME

TIME [WITH TIME ZONE]

DATE

TIME

DATETIME SMALLDATETIME

TIMESTAMP[(p)] [WITH TIME ZONE]

DATE TIMESTAMP [WITH[LOCAL] TIME ZONE]

TIMESTAMP

DATETIME SMALLDATETIME

INTERVAL

INTERVAL DAY TO SECOND INTERVAL YEAR TO MONTH

  

SQL99

SQL99 supports DATE, TIME, TIMESTAMP, TIME WITH TIME ZONE, and TIMESTAMP WITH TIME ZONE data types.

Oracle 9i

Oracle has DATE, TIMESTAMP, TIMESTAMP WITH TIME ZONE, and TIMESTAMP WITH LOCAL TIME ZONE data types.

DB2 UDB 8.1

DB2 has three standard SQL99 date and time data types — DATE, TIME, and TIMESTAMP.

MS SQL Server 2000

MS SQL Server has two date and time data types, DATETIME and SMALLDATETIME that both represent the combination of date and time values, but have different ranges.

Date and time literals

Date and time literals are implementation-specific and vary significantly among different vendors.

Oracle 9i

Oracle lets you specify DATE values as literals if they match special database initialization parameter NLS_DATE_FORMAT, which defaults to DD-MON-YY. (Oracle initialization parameters are usually handled by DBA and are not covered in this book.) You can also use SQL99 literal standard (YYYY-MM-DD) with a DATE prefix, or convert literals into string using the Oracle function TO_DATE (covered in Chapter 10). The three following statements are valid date literals examples. (SHIPMENT_ARRIVDATE_D is a DATE field in Oracle ACME database.)

UPDATE shipment SET shipment_arrivdate_d = '03-SEP-02' WHERE shipment_id_n = 30661;

UPDATE shipment SET shipment_arrivdate_d = DATE '2003-09-02' WHERE shipment_id_n = 30661;

UPDATE shipment SET shipment_arrivdate_d = TO_DATE('September, 02 2003', 'Month, DD YYYY') WHERE shipment_id_n = 30661;

But these are illegal:

UPDATE shipment SET shipment_arrivdate_d = 'YYYY-MM-DD' WHERE shipment_id_n = 30661;

UPDATE shipment SET shipment_arrivdate_d = '03-SEP-02 23:12:45' WHERE shipment_id_n = 30661;

TIMESTAMP and TIMESTAMP WITH TIME ZONE data types also accept the DD-MON-YY format for literals (with optional TIME part); in addition, you can specify literals with a TIMESTAMP prefix:

TIMESTAMP '1997-01-31 09:26:50.124' TIMESTAMP '1997-01-31 09:26:56.66 +02:00' TIMESTAMP '1999-04-15 8:00:00 -8:00' TIMESTAMP '1999-04-15 8:00:00 US/Pacific' TIMESTAMP '1999-10-29 01:30:00 US/Pacific PDT'

The first of these lines is for TIMESTAMP data type, and the other four are for TIMESTAMP WITH TIME ZONE.

Note 

TIMESTAMP WITH LOCAL TIME ZONE data type does not have any literals associated with it.

Oracle gives you a great deal of flexibility when specifying interval values as literals. Reference Table 3-6 for examples.

Table 3-6: Interval Literals in Oracle

INTERVAL LITERAL

INTERPRETATION

INTERVAL '23-5' YEAR TO MONTH

Interval of 23 years and 5 months

INTERVAL '67' YEAR(3)

Interval of 67 years and 0 months

INTERVAL '500' MONTH(3)

Interval of 500 months

INTERVAL '7' YEAR

Interval of 4 years (maps to INTERVAL '7-0' YEAR TO MONTH)

INTERVAL '74' MONTH

Maps to INTERVAL '6-2' YEAR TO MONTH and indicates 6 years and 2 months

INTERVAL '7 6:15' DAY TO MINUTE

Interval of 7 days, 6 hours and 15 minutes

INTERVAL '40' DAY

Interval of 40 days

INTERVAL '11:20' HOUR TO MINUTE

Interval of 11 hours and 20 minutes

INTERVAL '10:22' MINUTE TO SECOND

Interval of 10 minutes 22 seconds

INTERVAL '25' HOUR

Interval of 25 hours

INTERVAL '40' MINUTE

Interval of 40 seconds

DB2 UDB 8.1

The following formats for DATE literals are recognized: YYYY-MM-DD (ANSI/ISO), MM/DD/YYYY (IBM US), and DD.MM.YYYY (IBM Europe).

So, these three statements are legal:

UPDATE shipment SET shipment_arrivdate_d = '2003-09-02' WHERE shipment_id_n = 30661

UPDATE shipment SET shipment_arrivdate_d = '09/02/2003' WHERE shipment_id_n = 30661

UPDATE shipment SET shipment_arrivdate_d = '02.09.2003' WHERE shipment_id_n = 30661

But this one is not:

UPDATE shipment SET shipment_arrivdate_d = '02-SEP-2003' WHERE shipment_id_n = 30661

The valid TIME literal formats are: HH.MM.SS (ANSI/ISO and IBM Europe), HH:MM AM|PM (IBM USA), and HH:MM:SS (Japanese Industrial Standard). Also, trailing blanks may be included, and a leading zero may be omitted from the hour part of the time; seconds may be omitted entirely:

'12.23.56' '23:15 AM' '8:45'

The valid string formats for TIMESTAMP literals are YYYY-MM-DD-HH.MM.SS.NNNNNN and YYYY-MM-DD HH:MM:SS.NNNNNN:

UPDATE shipment SET shipment_createdate_d = '2003-10-12-23.34.29' WHERE shipment_id_n = 30661

UPDATE shipment SET shipment_createdate_d = '2003-10-12 23:34:29.345678' WHERE shipment_id_n = 30661

MS SQL Server

MS SQL Server is probably the friendliest RDBMS in terms of handling date and time. It recognizes the date and time literals enclosed in single quotation marks in many different formats. For example:

'August 15, 2003' '15 August, 2003' '15-AUG-2003' '15 Aug, 2003' '030815' '2003/08/15' '08/15/03' '14:30:24' '04:24 PM' '15 August, 2003 23:00' '15-AUG-2003 22:45:34.345'

All these (and many other) formats are valid for both DATETIME and SMALLDATETIME.

Категории