Working with SQL Server Date/Time Variables

Wednesday Apr 16th 2003 by Gregory A. Larsen
Share:

In this first article in a series, Greg Larsen will discuss various aspects of working with SQL Server date/time columns.

This is the first article in a series of articles that I will discuss various aspects of working with SQL Server date/time columns. SQL Server has two different date/time columns. They are DATETIME and SMALLDATETIME. This article will define the difference between these two SQL Server date/time data types, as well as show you how to insert date and time data into SQL Server DATETIME and SMALLDATETIME columns.

The DATETIME column is used to hold a date and time value, where time is accurate to three-hundredth of a second. The date for a DATETIME column can range from January 1, 1753 to December 31, 9999. A DATETIME column takes 8 bytes of disk storage. The physical storage of these 8 bytes is divided into 2 - 4 byte integer pieces. The first 4 byte integer is used to store the number of days before or after the base date January 1, 1900, while the second 4 bytes integer is used to represent the number of milliseconds since midnight.

A SMALLDATETIME column also holds a date and time value, but the time portion is only accurate to one minute. Valid dates for a SMALLDATETIME column can range from January 1, 1900 to June 6, 2079. The SMALLDATETIME column takes 4 bytes of storage. This 4 bytes is broken into two 2 byte integer pieces. The first 2 bytes integer piece contains the number of days since January 1, 1900; the second 2 byte integer holds the number of minutes since midnight.

Most, if not all, applications need and manage date and time variables in their database. Since data from applications and external sources may come in many formats, you need to know how to insert these dispersant values into DATETIME and SMALLDATETIME columns.

SQL Server has a number of default formats it expects raw date and time data to be in when inserting dates into a DATETIME, or SMALLDATETIME columns. If you attempt to insert a date that does not match one of the default date formats, then SQL Server will reject the date/time value. If your raw data does match one of the default formats, SQL Server will automatically convert your raw data into a DATETIME value without any special consideration.

Let's review some TSQL code for inserting dates and times into SQL Server. Here is a sample script that inserts the same date 10/30/1956 into a sample table using a number of different string formats.

DROP TABLE X 
GO 
SET NOCOUNT ON
CREATE TABLE X(D DATETIME)

INSERT INTO X VALUES ('19561030')
INSERT INTO X VALUES ('561030')
INSERT INTO X VALUES ('10/30/1956')
INSERT INTO X VALUES ('10/30/56')
INSERT INTO X VALUES ('30 OCT 1956')
INSERT INTO X VALUES ('30 OCT 56')
INSERT INTO X VALUES ('OCT 30 1956')
INSERT INTO X VALUES ('OCT 30, 1956')
INSERT INTO X VALUES ('OCT 30, 56')
INSERT INTO X VALUES ('OCTOBER 10, 1956')
SELECT * FROM X

As you can see from this example, not all dates specified contain a 4 digit year. SQL Server has a two-digit year cutoff option that makes this possible. My SQL Server uses the default setting which is 2049. Meaning if the year looks to be from 00-49, SQL Server will assume the first two digits of the year will be 20. In my example, the year was greater than 49, so SQL Server set the year to 1956. The two digit year cutoff is a configurable option.

Here is what books online says about the acceptable aphabetic and numeric formats that are automatically recognized as dates by SQL Server:

Alphabetic Date Format

Microsoft. SQL Server™ 2000 allows you to specify date data with a month specified as the full month name (for example, April) or the month abbreviation (for example, Apr) given in the current language; commas are optional and capitalization (case) is ignored.

Here are some guidelines for the use of alphabetic date formats:

  • Enclose the date and time data in single quotation marks (').
  • These are the valid alphabetic formats for SQL Server date data (characters enclosed in brackets are optional):
  • Apr[il] [15][,] 1996
  • Apr[il] 15[,] [19]96
  • Apr[il] 1996 [15]
  • [15] Apr[il][,] 1996
  • 15 Apr[il][,][19]96
  • 15 [19]96 apr[il]
  • [15] 1996 apr[il]
  • 1996 APR[IL] [15]
  • 1996 [15] APR[IL]
  • If you specify only the last two digits of the year, values less than the last two digits of the value of the two digit year cutoff configuration option are in the same century as the cutoff year. Values greater than or equal to the value of this option are in the century that precedes the cutoff year. For example, if two digit year cutoff is 2050 (default), 25 is interpreted as 2025 and 50 is interpreted as 1950. To avoid ambiguity, use four-digit years.
  • If the day is missing, the first day of the month is supplied.
  • The SET DATEFORMAT session setting is not applied when you specify the month in alphabetic form.

Numeric Date Format

Microsoft® SQL Server™ 2000 allows you to specify date data with a numeric month specified. For example, 5/20/97 represents the twentieth day of May, 1997. When using numeric date format, specify the month, day, and year in a string with slash marks (/), hyphens (-), or periods (.) as separators. This string must appear in the following form:

number separator number separator number [time] [time]

These numeric formats are valid:

[0]4/15/[19]96 -- (mdy)
[0]4-15-[19]96 -- (mdy)
[0]4.15.[19]96 -- (mdy)
[04]/[19]96/15 -- (myd)
15/[0]4/[19]96 -- (dmy)
15/[19]96/[0]4 -- (dym)
[19]96/15/[0]4 -- (ydm)
[19]96/[04]/15 -- (ymd)

When the language is set to us_english, the default order for the date is mdy. You can change the date order with the SET DATEFORMAT statement, which can also affect the date order, depending on the language.

The setting for SET DATEFORMAT determines how date values are interpreted. If the order does not match the setting, the values are not interpreted as dates (because they are out of range), or the values are misinterpreted. For example, 12/10/08 can be interpreted as one of six dates, depending on the DATEFORMAT setting.

Due to many variables in the format of input data for a date, the date may not always be a string of characters that is recognizes as a date by SQL Server. When you have this kind of raw date data, you will need to manipulate the input data to look like a date, before inserting it into a date/time column. A good example of a date format that is not recognized by SQL Server is an 8 digit date in MMDDYYYY format, this 8 character date format is not recognized by SQL Server as a date. In order to get the MMDDYYYY date into SQL Server you will need to convert it to a format that SQL Server knows is a date, like 'MM-DD-YYYY'. Let's look at ways to convert date/time data into a format that SQL Server can recognize.

As mentioned above a string in MMDDYYYY format, like '10301956' would not be accepted by SQL Server as a date. Therefore, if your input date was in this format you would need to stuff a couple of dashes into your data to make SQL Server recognize this as a date. There are a number of ways to do this. Here is some code that shows two different ways, there are many more. The first example uses the STUFF function to insert dashes in the appropriate place within the input date, while the second example uses the SUBSTRING and concatination ('+') function.

SET NOCOUNT ON
CREATE TABLE Y(D DATETIME)
DECLARE @INPUT CHAR(8)
SET @INPUT = '10301956'
-- FIRST EXAMPLE
INSERT INTO Y VALUES(STUFF(STUFF(@INPUT,3,0,'-'),6,0,'-'))
SELECT * FROM Y
TRUNCATE TABLE Y
-- SECOND EXAMPLE
INSERT INTO Y VALUES(SUBSTRING(@INPUT,1,2) + '-' + 
                     SUBSTRING(@INPUT,3,2) + '-' + 
                     SUBSTRING(@INPUT,5,4))
SELECT * FROM Y	
DROP TABLE Y

Depending on your input date format, normally the SUBSTRING, STUFF and concatenation functions are about all you need to reformat an input date into a format that SQL Server will except.

Another way to tell SQL Server how to interpret a string as a date is to use the SET DATEFORMAT command. This command allows you to input strings that would normally not be recognized by SQL server as dates. The SET DATEFORMAT command lets you specify what part of the date is first, second or third.

The format for the SET DATEFORMAT command is: SET DATEFORMAT <format> where <format> is one of the following: mdy, dmy, ymd, ydm, myd, or dym. The default DATEFORMAT is mdy. Let's looks a few examples on how the SET DATEFORMAT will allow you to specify the format of your input date.

SET NOCOUNT ON 
CREATE TABLE X(EXAMPLE INT, D SMALLDATETIME)
-- EXAMPLE 1
SET DATEFORMAT MDY
INSERT INTO X VALUES (1, '10/30/56')
-- EXAMPLE 2
SET DATEFORMAT YDM
INSERT INTO X VALUES (2, '56/31/10')
-- EXAMPLE 3 
SET DATEFORMAT YMD
INSERT INTO X VALUES (3, '56/10/31')
SELECT * FROM X
DROP TABLE X

In the above example, note how I changed the date format between each INSERT statement. The "SET DATEFORMAT" allowed me to INSERT dates with three different formats without doing any special data conversions.

Up to this point I have only been describing how to input the date portion of a date/time variable, there is still the time portion to consider. It is highly likely that you will be working with data that needs to be stored in SQL Server that has a time portion. One example of this might be converting data from a legacy system that stored the date and time in two different fields, where the date is in YYYYMMDD format, and the time is HHMMSSMMM or some other format.

Just as SQL Server accepts dates that meet a specific format, SQL Server also has some formats that it automatically expects for strings that contain times. Here is some information about the formats for time that SQL Server will accept. This information can be found in SQL Server 2000 Books Online.

Microsoft® SQL Server™ 2000 recognizes the following formats for time data. Enclose each format with single quotation marks (').

14:30
14:30[:20:999]
14:30[:20.9]
4am
4 PM
[0]4[:30:20:500]AM

You can specify a suffix of AM or PM to indicate if the time value is before or after 12 noon. The case of AM or PM is ignored.

Hours can be specified using either a 12-hour or 24-hour clock. This is how the hour values are interpreted:

  • The hour value of 0 represents the hour after midnight (AM), regardless of whether or not you specify AM. You cannot specify PM when the hour equals 0.
  • Hour values from 1 through 11 represent the hours before noon if neither AM nor PM is specified. They also represent the hours before noon when AM is specified. They represent hours after noon if PM is specified.
  • The hour value 12 represents the hour that starts at noon if neither AM nor PM is specified. If AM is specified, it represents the hour that starts at midnight. If PM is specified, it represents the hour that starts at noon. For example: 12:01 is 1 minute after noon, as is 12:01 PM, while 12:01 AM is 1 minute after midnight. Specifying 12:01 AM is the same as specifying 00:01 or 00:01 AM.
  • Hour values from 13 through 23 represents hours after noon if AM or PM is specified. They also represent the hours after noon when PM is specified. You cannot specify AM when the hour value is from 13 through 23.
  • An hour value of 24 is not valid, use 12:00 AM or 00:00 to represent midnight.

Milliseconds can be preceded by either a colon (:) or a period (.). If preceded by a colon, the number means thousandths-of-a-second. If preceded by a period, a single digit means tenths-of-a-second, two digits mean hundredths-of-a-second, and three digits mean thousandths-of-a-second. For example, 12:30:20:1 indicates twenty and one-thousandth seconds past 12:30; 12:30:20.1 indicates twenty and one-tenth




Let's review a few examples on setting SQL Server date/time variables with not only the date portion, but also the time portion. The following example will insert the same date and time (October 30, 1956 2:01:29.000 PM) into a table, where the time is specified in different SQL Server acceptable formats.




SET NOCOUNT ON
CREATE TABLE X(EXAMPLE INT, D DATETIME)
-- EXAMPLE 1
INSERT INTO X VALUES(1, '19561030 2:01:29 PM')
-- EXAMPLE 2
INSERT INTO X VALUES(2, '19561030 14:01:29')
-- EXAMPLE 3
INSERT INTO X VALUES(3, '19561030 14:1:29 PM')
-- EXAMPLE 4
INSERT INTO X VALUES(4, '19561030 14:01:29.000 PM')
SELECT * FROM X ORDER BY EXAMPLE
DROP TABLE X

Note that you can enter the time with or without the PM identifier, provided the hour value is between 13 and 23. If Example 1 was to not have the PM identifier then SQL Server would have interpreted that time value as 2:01:29 AM. Also, since we are placing these dates into a datetime column within table X, each that does not have a millisecond identifier will default to '000' milliseconds'

Let review another example that does something different with the time when saving a time value in HH:MM:SS format into a smalldate variable. Remember a smalldate variable will only store time down to the minute. Here is the example script:

SET NOCOUNT ON
CREATE TABLE X(EXAMPLE INT, D SMALLDATETIME)
-- EXAMPLE 1
INSERT INTO X VALUES(1, '19561030 2:01:29 PM')
-- EXAMPLE 2
INSERT INTO X VALUES(2, '19561030 14:01:30')
-- EXAMPLE 3
INSERT INTO X VALUES(3, '19561030 14:01:29.999 PM')
SELECT * FROM X
DROP TABLE X

Here is the output from the "SELECT" statement in the above script:

EXAMPLE     D                                                      
----------- 	------------------------------------------------------ 
1           	1956-10-30 14:01:00
2           	1956-10-30 14:02:00
3           	1956-10-30 14:02:00

If you look at the times that were inserted they all had the same minute. So why did SQL Server change the minute on a couple of the values? This was done because SQL Server does some rounding of the seconds and milliseconds when trying to determine the minute that was being inserted.

SQL Server also has a function to validate your input data to verify that it really contains a date. The name of this fuction is ISDATE. This function determines whether an input expression is a valid date, based on whether the input date meets one of SQL Server's designated date formats, as described above.

The ISDATE function returns a 1 when a valid date expression is pass to the function, and a 0 if an invalid date expression is passed. Here is an example on how one might use the ISDATE function to validate input data.

SET NOCOUNT ON
CREATE TABLE X(VALID_DATE DATETIME)
DECLARE @IDATE1 CHAR(20)
SET @IDATE1 = '10-30-1956'
IF ISDATE (@IDATE1) = 1
BEGIN
  PRINT 'VALID DATE: ' + @IDATE1 + ' ROW INSERTED'
  INSERT INTO X VALUES (@IDATE1)
END
ELSE 
  PRINT 'INVALID DATE: ' + @IDATE1

SET @IDATE1 = '10-30-1956 AM'
IF ISDATE (@IDATE1) = 1
  INSERT INTO X VALUES (@IDATE1)
ELSE 
  PRINT 'INVALID DATE: ' + @IDATE1 + ' INSERT NOT PERFORMED'
SELECT * FROM X
DROP TABLE X

Output from this example:

VALID DATE: 10-30-1956           ROW INSERTED
INVALID DATE: 10-30-1956 AM        INSERT NOT PERFORMED
VALID_DATE                                             
------------------------------------------------------ 
1956-10-30 00:00:00.000

From this example, you can see that the first setting of the variable @IDATE1 has a valid date and a row was inserted into table X. Although the second setting of @IDATE1 does not contain a valid date and therefore the ISNULL function returned a 0 and caused an INVALID DATE message to be displayed.

Depending what you are trying to accomplish, the ISDATE function might be a method to validate your input date prior to having SQL Server reject your date when trying to place it into a DATETIME or SMALLDATETIME variable.

Conclusion

As you can see, there are many different formats and things to consider when using character strings to populate date/time columns. Care needs to be taken to make sure the character strings are in the proper format, and whether rounding of milliseconds, or seconds will give you a final time that you are not expecting.

This article only dealt with inserting dates into SQL Server. My next article, part 2, will discuss displaying datetime and smalldate time column values in different formats.

» See All Articles by Columnist Gregory A. Larsen

Share:
Home
Mobile Site | Full Site
Copyright 2017 © QuinStreet Inc. All Rights Reserved