SQL Server 日付フォーマット徹底解説:変換・表示形式まとめ
SQL Serverにおける日付と時刻の扱いは、データベースアプリケーション開発において非常に重要な要素です。データの記録、検索、分析、表示など、あらゆる場面で日付・時刻データが登場します。しかし、その多様な表示形式や変換方法、そして背後にあるシステム設定などが複雑に絡み合い、意図しない結果になることも少なくありません。
この記事では、SQL Serverにおける日付・時刻データの基本的な扱いから、表示形式の制御、そして主要な変換関数 (CONVERT, FORMAT, CAST) を中心に、その他の関連関数や注意点まで、網羅的かつ詳細に解説します。この記事を読むことで、SQL Serverでの日付・時刻フォーマットに関する疑問を解消し、より正確で意図通りのデータ処理を実現できるようになることを目指します。
1. SQL Serverの日付・時刻データ型を理解する
SQL Serverには、日付と時刻を格納するための複数のデータ型が用意されています。それぞれのデータ型は、格納できる値の範囲、精度、ストレージ容量、そしてタイムゾーン情報の有無などが異なります。これらの特性を理解し、要件に合った適切なデータ型を選択することが、効率的で正確なデータ管理の第一歩です。
主な日付・時刻データ型は以下の通りです。
- DATE: 日付のみを格納します。
- 範囲: 0001-01-01 から 9999-12-31
- 精度: 日単位
- ストレージ: 3バイト
- 時刻情報は格納しません。
- TIME: 時刻のみを格納します。
- 範囲: 00:00:00.0000000 から 23:59:59.9999999
- 精度: 100ナノ秒 (秒の小数点以下7桁)
- ストレージ: 5バイト
- タイムゾーン情報は格納しません。
- DATETIME: 日付と時刻を格納します。最も古くから存在するデータ型の一つです。
- 範囲: 1753-01-01 00:00:00 から 9999-12-31 23:59:59.997
- 精度: 約3.33ミリ秒 (秒の小数点以下3桁)
- ストレージ: 8バイト
- 精度が低く、秒の小数点以下が丸められる可能性があります。
- DATETIME2: 日付と時刻を、より広い範囲と高い精度で格納します。
DATETIMEの後継として推奨されます。- 範囲: 0001-01-01 00:00:00 から 9999-12-31 23:59:59.9999999
- 精度: 100ナノ秒 (秒の小数点以下7桁)。精度は宣言時に指定できます(デフォルトは7桁)。
- ストレージ: 6~8バイト (精度によって変化)
DATETIMEに比べて精度が高く、範囲も広いです。
- SMALLDATETIME: 日付と時刻を格納しますが、
DATETIMEよりも範囲が狭く、精度が低いです。- 範囲: 1900-01-01 00:00:00 から 2079-06-06 23:59:59
- 精度: 1分
- ストレージ: 4バイト
- メモリ効率は良いですが、現代ではあまり推奨されません。
- DATETIMEOFFSET: 日付と時刻に加え、タイムゾーンのオフセット情報も格納します。
- 範囲: 0001-01-01 00:00:00 +in:nn から 9999-12-31 23:59:59.9999999 +in:nn
- 精度: 100ナノ秒 (秒の小数点以下7桁)。精度は宣言時に指定できます(デフォルトは7桁)。
- タイムゾーンオフセットの範囲: -14:00 から +14:00
- ストレージ: 8~10バイト (精度によって変化)
- 世界中の異なるタイムゾーンのデータを正確に扱う場合に不可欠です。
データ型の選択の指針:
- 日付のみ:
DATE - 時刻のみ:
TIME - 日付と時刻 (高精度、広い範囲):
DATETIME2(最も推奨される汎用的な型) - 日付と時刻 + タイムゾーン情報:
DATETIMEOFFSET - レガシーシステムとの互換性、または非常に限られた範囲と低い精度で十分な場合:
DATETIME,SMALLDATETIME(ただし、新規開発では避けるのが一般的)
新しいシステムを構築する場合、特別な理由がない限り、DATE, TIME, DATETIME2, DATETIMEOFFSET の使用を検討すべきです。特に DATETIME2 は DATETIME のほぼ上位互換であり、より高精度で広い範囲を扱えるため、推奨されます。
2. 日付・時刻データの入力 (リテラル)
SQL文で日付・時刻の値を直接記述する場合(リテラル)、いくつかの形式が利用可能です。SQL Serverの言語/地域設定(SET LANGUAGE, SET DATEFORMAT)に依存する形式と依存しない形式があります。移植性や正確性を考慮すると、設定に依存しない形式を使用することが強く推奨されます。
推奨される、言語/地域設定に依存しない形式:
- YYYYMMDD: 日付のみ。最もシンプルで明確な形式。
sql
SELECT CAST('20231027' AS DATE); - YYYY-MM-DD: 日付のみ。ISO 8601 標準に近い形式。
sql
SELECT CAST('2023-10-27' AS DATE); - YYYY-MM-DD HH:MI:SS: 日付と時刻。時刻部分は省略可能。
sql
SELECT CAST('2023-10-27 14:30:00' AS DATETIME2); - YYYY-MM-DDTHH:MI:SS: ISO 8601 標準形式。’T’ で日付と時刻を区切る。ミリ秒以下の指定も可能 (
.sss,.sssssss)。
sql
SELECT CAST('2023-10-27T14:30:00' AS DATETIME2);
SELECT CAST('2023-10-27T14:30:00.1234567' AS DATETIME2);
DATETIMEOFFSETの場合、タイムゾーンオフセットも付けられます。
sql
SELECT CAST('2023-10-27T14:30:00+09:00' AS DATETIMEOFFSET);
注意が必要な、言語/地域設定に依存する形式:
-
‘MM/DD/YYYY’, ‘DD/MM/YYYY’, ‘YYYY/MM/DD’ など、スラッシュやハイフンで区切られた形式は、
SET DATEFORMATの設定によって月の位置が変わる可能性があります。
“`sql
— デフォルト (US 形式が多い)
SET DATEFORMAT mdy; — Month-Day-Year
SELECT CAST(’10/27/2023′ AS DATE); — 2023-10-27— ヨーロッパ形式
SET DATEFORMAT dmy; — Day-Month-Year
SELECT CAST(’10/27/2023′ AS DATE); — エラーまたは意図しない日付になる可能性 (例: 2023-07-10?)
``YYYYMMDD
このように、設定によって解釈が変わるため、アプリケーションやスクリプトの移植性を低下させます。可能な限りやYYYY-MM-DDTHH:MI:SS` の形式を使用しましょう。
3. 日付・時刻データの表示形式を制御する
データベースに格納された日付・時刻データは、そのまま出力すると特定のデフォルト形式で表示されます。このデフォルト形式は、SQL Serverのバージョン、データベースの言語設定、そして接続しているセッションの言語/地域設定(SET LANGUAGE, SET DATEFORMAT)に影響を受けます。
しかし、多くの場合はアプリケーションやレポートでユーザーフレンドリーな形式で表示したい、あるいは特定のデータ連携形式に合わせたいといったニーズがあります。ここで日付フォーマット変換関数の出番となります。
SQL Serverで日付・時刻データを任意の文字列形式に変換するための主要な関数は以下の2つです。
CONVERT関数: 以前から存在する標準的な変換関数。特定の「スタイル」番号を指定してフォーマットを制御します。FORMAT関数: SQL Server 2012で導入された関数。より柔軟で、.NET Frameworkの書式設定ルールに基づいています。
それぞれの関数について詳しく見ていきましょう。
3.1. CONVERT 関数によるフォーマット変換
CONVERT 関数は、あるデータ型から別のデータ型へ値を変換する汎用的な関数です。日付・時刻データを文字列型に変換する際に、特定の「スタイル」番号を指定することで、出力される日付・時刻の形式を制御できます。
構文:
sql
CONVERT ( data_type [ ( length ) ] , expression [ , style ] )
data_type: 変換後のデータ型。日付フォーマットを指定する場合は、VARCHARやNVARCHARなどの文字列型を指定します。expression: 変換元の値。日付・時刻型のカラムや変数、関数 (例:GETDATE()) など。style: 変換形式を指定する整数コード。この引数が日付・時刻フォーマットの制御において最も重要です。省略した場合、デフォルトのスタイルが適用されますが、これはシステム設定に依存します。
主要な日付/時刻 style コード:
style コードは、世紀の扱い(YYYY または YY)や、日付、時刻、両方を含むかなどによって分けられています。ここではよく使われるスタイルを中心に紹介します。
| Style | Standard | 入力/出力形式 | 例 (GETDATE() = 2023-10-27 14:30:59.123) |
|---|---|---|---|
| 日付と時刻 | |||
| 0 | Default | mon dd yyyy hh:miAM (or PM) | Oct 27 2023 2:30PM |
| 100 | Default | mon dd yyyy hh:miAM (or PM) | Oct 27 2023 2:30PM |
| 1 | US | mm/dd/yy | 10/27/23 |
| 101 | US | mm/dd/yyyy | 10/27/2023 |
| 2 | ANSI | yy.mm.dd | 23.10.27 |
| 102 | ANSI | yyyy.mm.dd | 2023.10.27 |
| 3 | British/French | dd/mm/yy | 27/10/23 |
| 103 | British/French | dd/mm/yyyy | 27/10/2023 |
| 4 | German | dd.mm.yy | 27.10.23 |
| 104 | German | dd.mm.yyyy | 2023.10.27 |
| 5 | Italian | dd-mm-yy | 27-10-23 |
| 105 | Italian | dd-mm-yyyy | 2023-10-27 |
| 6 | – | mon dd yy | Oct 27 23 |
| 106 | – | mon dd yyyy | Oct 27 2023 |
| 7 | – | mon dd, yy | Oct 27, 23 |
| 107 | – | mon dd, yyyy | Oct 27, 2023 |
| 8 | – | hh:mi:ss | 14:30:59 |
| 108 | – | hh:mi:ss | 14:30:59 |
| 9 | Default+ | mon dd yyyy hh:mi:ss:mmmAM (or PM) (use 109) | Oct 27 2023 2:30:59:123PM |
| 109 | Default+ | mon dd yyyy hh:mi:ss:mmmAM (or PM) | Oct 27 2023 2:30:59:123PM |
| 10 | – | mm-dd-yy | 10-27-23 |
| 110 | US | mm-dd-yyyy | 10-27-2023 |
| 11 | Japanese | yy/mm/dd | 23/10/27 |
| 111 | Japanese | yyyy/mm/dd | 2023/10/27 |
| 12 | ISO | yyoidd | 231027 |
| 112 | ISO | yyyymmdd | 20231027 |
| 13 | Europe Default | dd mon yyyy hh:mi:ss:mmm (24h) | 27 Oct 2023 14:30:59:123 |
| 113 | Europe Default | dd mon yyyy hh:mi:ss:mmm (24h) | 27 Oct 2023 14:30:59:123 |
| 20 | ODBC | yyyy-mm-dd hh:mi:ss (24h) | 2023-10-27 14:30:59 |
| 120 | ODBC | yyyy-mm-dd hh:mi:ss (24h) | 2023-10-27 14:30:59 |
| 21 | ODBC + ms | yyyy-mm-dd hh:mi:ss.mmm (24h) | 2023-10-27 14:30:59.123 |
| 121 | ODBC + ms | yyyy-mm-dd hh:mi:ss.mmm (24h) | 2023-10-27 14:30:59.123 |
| 126 | ISO8601 | yyyy-mm-ddThh:mi:ss.mmm (XMLで使用) | 2023-10-27T14:30:59.123 |
| 127 | ISO8601 + time zone | yyyy-mm-ddThh:mi:ss.nnnnnnn+ | -hh:mi |
| 130 | Hijri | dd mon yyyy hh:mi:ss:mmmAM (or PM) (Saudi Arabia) | 02 Rabi’ al-Thani 1445 2:30:59:123PM |
| 131 | Hijri | dd/mm/yyyy hh:mi:ss:mmmAM (or PM) (Islamic) | 02/04/1445 2:30:59:123PM |
注意点:
styleコードのうち、100未満のものは通常2桁の年 (yy) を使用し、100以上のものは4桁の年 (yyyy) を使用します。ただし、スタイル 9 と 109 など例外もあります。styleコードに 20 または 21 を指定すると、ODBC 正規の日時形式で出力されます。styleコード 126 は、ISO 8601 形式(秒の小数部は3桁)で、XML 変換に適しています。styleコード 127 は、ISO 8601 形式(秒の小数部は7桁)で、タイムゾーン情報も含まれます(DATETIMEOFFSET型の場合)。- スタイル 130 と 131 はイスラム暦(ヒジュラ暦)を使用します。
- 一部のスタイル(例: 0, 100, 9, 109, 130, 131)は、SQL Serverの言語設定に影響を受け、月の名前やAM/PM表記が変わる場合があります。言語依存を避けたい場合は、数値のみのスタイル(例: 112, 120, 121, 126)を使用するのが安全です。
CONVERT 関数の使用例:
“`sql
— 現在の日時を取得
DECLARE @CurrentDateTime DATETIME = GETDATE();
DECLARE @CurrentDateTime2 DATETIME2 = SYSDATETIME();
DECLARE @CurrentDate DATE = GETDATE();
DECLARE @CurrentTime TIME = SYSDATETIME();
DECLARE @CurrentDateTimeOffset DATETIMEOFFSET = SYSDATETIMEOFFSET();
— スタイル101 (US形式 mm/dd/yyyy)
SELECT ‘Style 101 (US):’, CONVERT(VARCHAR, @CurrentDateTime, 101); — 10/27/2023
— スタイル103 (英国/フランス形式 dd/mm/yyyy)
SELECT ‘Style 103 (British/French):’, CONVERT(VARCHAR, @CurrentDateTime, 103); — 27/10/2023
— スタイル112 (ISO形式 yyyymmdd) – 言語依存しない
SELECT ‘Style 112 (ISO):’, CONVERT(VARCHAR, @CurrentDateTime, 112); — 20231027
— スタイル120 (ODBC形式 yyyy-mm-dd hh:mi:ss) – 言語依存しない、24時間表示
SELECT ‘Style 120 (ODBC):’, CONVERT(VARCHAR, @CurrentDateTime, 120); — 2023-10-27 14:30:59
— スタイル121 (ODBC形式 yyyy-mm-dd hh:mi:ss.mmm) – 言語依存しない、ミリ秒含む
SELECT ‘Style 121 (ODBC+ms):’, CONVERT(VARCHAR, @CurrentDateTime, 121); — 2023-10-27 14:30:59.123
— DATETIME2で精度が高い場合、スタイル121でも精度は丸められる (DATETIMEの精度まで)
SELECT ‘Style 121 (DATETIME2):’, CONVERT(VARCHAR, @CurrentDateTime2, 121); — 2023-10-27 14:30:59.123
— スタイル126 (ISO 8601 yyyy-mm-ddThh:mi:ss.mmm)
SELECT ‘Style 126 (ISO 8601):’, CONVERT(VARCHAR, @CurrentDateTime, 126); — 2023-10-27T14:30:59.123
— DATETIME2の精度を維持しつつISO 8601形式 (秒の小数部7桁) で出力したい場合、スタイル126または127を使用
SELECT ‘Style 126 (DATETIME2 full precision):’, CONVERT(VARCHAR, @CurrentDateTime2, 126); — 2023-10-27T14:30:59.1234567 (SQL Server 2012以降)
— DATETIMEOFFSETをスタイル127で出力 (タイムゾーン情報含む)
SELECT ‘Style 127 (DATETIMEOFFSET):’, CONVERT(VARCHAR, @CurrentDateTimeOffset, 127); — 2023-10-27T14:30:59.1234567+09:00
— 日付のみの型 (DATE) を文字列に変換する場合
SELECT ‘DATE Style 101:’, CONVERT(VARCHAR, @CurrentDate, 101); — 10/27/2023
SELECT ‘DATE Style 112:’, CONVERT(VARCHAR, @CurrentDate, 112); — 20231027
— 時刻のみの型 (TIME) を文字列に変換する場合
SELECT ‘TIME Style 8:’, CONVERT(VARCHAR, @CurrentTime, 8); — 14:30:59
— スタイル8はデフォルトで秒の小数部を表示しない。精度を維持したい場合は他の方法が必要 (FORMAT関数など)
SELECT ‘TIME Style 108:’, CONVERT(VARCHAR, @CurrentTime, 108); — 14:30:59 (ミリ秒以下は表示されない)
— NVARCHARに変換する場合(日本語などの多言語対応が必要な場合)
SELECT ‘NVARCHAR Style 103:’, CONVERT(NVARCHAR, @CurrentDateTime, 103); — 27/10/2023
— 特定の長さを指定して変換する場合
SELECT ‘VARCHAR(10) Style 101:’, CONVERT(VARCHAR(10), @CurrentDateTime, 101); — 10/27/2023 (長さが足りていれば切り捨てなし)
SELECT ‘VARCHAR(5) Style 101:’, CONVERT(VARCHAR(5), @CurrentDateTime, 101); — 10/27 (長さが足りないので切り捨て)
— 注: 十分な長さを指定しないとデータが切り捨てられる可能性があります。VARCHAR/NVARCHARの長さを指定しないと、デフォルトの長さ (通常30) が使用されますが、明示的に指定するのが安全です。
“`
CONVERT 関数は多くの標準的な形式に対応しており、互換性が高いのが特徴です。しかし、特定の曜日名や、ミリ秒以下の秒の小数点以下の桁数を自由に指定したい、といったより柔軟なフォーマットには対応できません。そのような場合は次に紹介する FORMAT 関数が便利です。
3.2. FORMAT 関数によるフォーマット変換 (SQL Server 2012以降)
FORMAT 関数は、SQL Server 2012で導入された新しい変換関数です。これは .NET Framework の書式設定機能を利用しており、日付・時刻を含む様々な型の値を、カルチャ(言語/地域設定)に基づいた、より柔軟な形式で文字列に変換できます。
構文:
sql
FORMAT ( value, format [, culture ] )
value: 変換元の値。日付・時刻型、数値型など。format: 出力形式を指定する文字列。標準書式指定子またはカスタム書式指定子を使用します。culture: 使用するカルチャ名を指定する省略可能な文字列(例: ‘en-US’, ‘ja-JP’, ‘fr-FR’)。指定しない場合、現在のセッションのカルチャが使用されます。
書式指定子 (format)
FORMAT 関数の最大の利点は、この format 引数で非常に多様な形式を指定できることです。
a) 標準の日付および時刻書式指定子 (一文字)
これらの指定子は、指定された culture に基づいて、あらかじめ定義された形式で出力します。
| 指定子 | 説明 | ‘en-US’ の例 (2023-10-27 14:30:00) | ‘ja-JP’ の例 (2023-10-27 14:30:00) |
|---|---|---|---|
| “d” | 短い日付形式 | 10/27/2023 | 2023/10/27 |
| “D” | 長い日付形式 | Friday, October 27, 2023 | 2023年10月27日金曜日 |
| “t” | 短い時刻形式 | 2:30 PM | 14:30 |
| “T” | 長い時刻形式 | 2:30:00 PM | 14:30:00 |
| “f” | 完全な日付と時刻 (短い時刻) | Friday, October 27, 2023 2:30 PM | 2023年10月27日金曜日 14:30 |
| “F” | 完全な日付と時刻 (長い時刻) | Friday, October 27, 2023 2:30:00 PM | 2023年10月27日金曜日 14:30:00 |
| “g” | 標準の日付と時刻 (短い時刻) | 10/27/2023 2:30 PM | 2023/10/27 14:30 |
| “G” | 標準の日付と時刻 (長い時刻) | 10/27/2023 2:30:00 PM | 2023/10/27 14:30:00 |
| “o”, “O” | ラウンドトリップ形式 (ISO 8601) | 2023-10-27T14:30:00.0000000 | 2023-10-27T14:30:00.0000000 |
| “s” | 並べ替え可能な形式 (ISO 8601) | 2023-10-27T14:30:00 | 2023-10-27T14:30:00 |
| “u” | UTC 並べ替え可能な形式 (ISO 8601) | 2023-10-27 14:30:00Z | 2023-10-27 14:30:00Z |
| “U” | UTC の完全な日付と時刻 (長い時刻) | Friday, October 27, 2023 7:30:00 AM (UTC) | 2023年10月27日金曜日 7:30:00 (UTC) |
| “y”, “Y” | 年月形式 | October 2023 | 2023年10月 |
b) カスタム日付および時刻書式指定子 (複数文字)
これらの指定子を組み合わせて、任意の形式を作成できます。
| 指定子 | 説明 | 例 |
|---|---|---|
| d | 月の1桁または2桁の日 (1-31) | 1, 27 |
| dd | 月の2桁の日 (01-31) | 01, 27 |
| ddd | 曜日名の略称 (例: Sun, Mon) | Fri |
| dddd | 曜日名の完全名 (例: Sunday, Monday) | Friday |
| M | 年の1桁または2桁の月 (1-12) | 1, 10 |
| MM | 年の2桁の月 (01-12) | 01, 10 |
| MMM | 月名の略称 (例: Jan, Feb) | Oct |
| MMMM | 月名の完全名 (例: January, February) | October |
| y | 年の1桁または2桁 (0-99) | 23 |
| yy | 年の2桁 (00-99) | 23 |
| yyy | 年の3桁 | 023, 2023 |
| yyyy | 年の4桁 | 2023 |
| h | 1桁または2桁の時間 (1-12) (AM/PM表示) | 2, 10 |
| hh | 2桁の時間 (01-12) (AM/PM表示) | 02, 10 |
| H | 1桁または2桁の時間 (0-23) (24時間表示) | 14 |
| HH | 2桁の時間 (00-23) (24時間表示) | 14 |
| m | 1桁または2桁の分 (0-59) | 0, 30 |
| mm | 2桁の分 (00-59) | 00, 30 |
| s | 1桁または2桁の秒 (0-59) | 0, 59 |
| ss | 2桁の秒 (00-59) | 00, 59 |
| f | 秒の小数部の1桁 (例: .1, .12, .123 -> 1) | 1 |
| ff | 秒の小数部の2桁 (例: .1, .12, .123 -> 12) | 12 |
| fff | 秒の小数部の3桁 (例: .1, .12, .123 -> 123) | 123 |
| ffff | 秒の小数部の4桁 | 1234 |
| fffff | 秒の小数部の5桁 | 12345 |
| ffffff | 秒の小数部の6桁 | 123456 |
| fffffff | 秒の小数部の7桁 | 1234567 |
| t | AM/PMの最初の文字 (例: A, P) | P |
| tt | AM/PM (例: AM, PM) | PM |
| z | タイムゾーンオフセットの符号なし時間部分 (1桁または2桁) | 9 |
| zz | タイムゾーンオフセットの符号なし時間部分 (2桁) | 09 |
| zzz | タイムゾーンオフセット (-hh:mm または +hh:mm) | +09:00 |
| : | カルチャ定義の時刻区切り記号 (通常 ‘:’) | : |
| / | カルチャ定義の日付区切り記号 (通常 ‘/’) | / |
| “string” | リテラル文字列 (二重引用符で囲む) | “Literal” |
| ‘string’ | リテラル文字列 (単一引用符で囲む) | ‘Literal’ |
| \c | エスケープ文字 (c をそのまま出力) | \d -> d |
| , | カルチャ定義のリスト区切り記号 | , |
FORMAT 関数の使用例:
“`sql
— 現在の日時を取得 (DATETIME2を使用すると精度を維持しやすい)
DECLARE @CurrentDateTime2 DATETIME2 = SYSDATETIME();
DECLARE @CurrentDateTimeOffset DATETIMEOFFSET = SYSDATETIMEOFFSET();
— 標準書式指定子
SELECT ‘Standard “d” (en-US):’, FORMAT(@CurrentDateTime2, ‘d’, ‘en-US’); — 10/27/2023
SELECT ‘Standard “d” (ja-JP):’, FORMAT(@CurrentDateTime2, ‘d’, ‘ja-JP’); — 2023/10/27
SELECT ‘Standard “D” (en-US):’, FORMAT(@CurrentDateTime2, ‘D’, ‘en-US’); — Friday, October 27, 2023
SELECT ‘Standard “D” (ja-JP):’, FORMAT(@CurrentDateTime2, ‘D’, ‘ja-JP’); — 2023年10月27日金曜日
SELECT ‘Standard “T” (en-US):’, FORMAT(@CurrentDateTime2, ‘T’, ‘en-US’); — 2:30:59 PM
SELECT ‘Standard “T” (ja-JP):’, FORMAT(@CurrentDateTime2, ‘T’, ‘ja-JP’); — 14:30:59
SELECT ‘Standard “F” (en-US):’, FORMAT(@CurrentDateTime2, ‘F’, ‘en-US’); — Friday, October 27, 2023 2:30:59 PM
SELECT ‘Standard “F” (ja-JP):’, FORMAT(@CurrentDateTime2, ‘F’, ‘ja-JP’); — 2023年10月27日金曜日 14:30:59
SELECT ‘Standard “o” (Roundtrip):’, FORMAT(@CurrentDateTime2, ‘o’); — 2023-10-27T14:30:59.1234567
SELECT ‘Standard “s” (Sortable):’, FORMAT(@CurrentDateTime2, ‘s’); — 2023-10-27T14:30:59
— DATETIMEOFFSETの場合、タイムゾーン情報も含まれる (‘o’ または ‘O’)
SELECT ‘Standard “o” (DATETIMEOFFSET):’, FORMAT(@CurrentDateTimeOffset, ‘o’); — 2023-10-27T14:30:59.1234567+09:00
— カスタム書式指定子
— “yyyy/MM/dd HH:mm:ss.fff” 形式 (例: 2023/10/27 14:30:59.123)
SELECT ‘Custom “yyyy/MM/dd HH:mm:ss.fff”:’, FORMAT(@CurrentDateTime2, ‘yyyy/MM/dd HH:mm:ss.fff’); — 2023/10/27 14:30:59.123
— “dddd, MMMM dd, yyyy” 形式 (例: Friday, October 27, 2023)
SELECT ‘Custom “dddd, MMMM dd, yyyy” (en-US):’, FORMAT(@CurrentDateTime2, ‘dddd, MMMM dd, yyyy’, ‘en-US’); — Friday, October 27, 2023
— カルチャを変えると曜日や月名が変わる
SELECT ‘Custom “dddd, MMMM dd, yyyy” (ja-JP):’, FORMAT(@CurrentDateTime2, ‘dddd, MMMM dd, yyyy’, ‘ja-JP’); — 金曜日, 10月 27, 2023 (注: ja-JPのカスタムフォーマットは少し独特)
— 任意の区切り文字やリテラル文字列を含む形式
SELECT ‘Custom “yyyy年MM月dd日 (ddd曜日) HH時mm分ss秒”:’, FORMAT(@CurrentDateTime2, ‘yyyy年MM月dd日 (ddd曜日) HH時mm分ss秒’, ‘ja-JP’); — 2023年10月27日 (金曜日) 14時30分59秒
— AM/PM表示 (hhを使用し、ttを付ける)
SELECT ‘Custom “yyyy-MM-dd hh:mm:ss tt” (en-US):’, FORMAT(@CurrentDateTime2, ‘yyyy-MM-dd hh:mm:ss tt’, ‘en-US’); — 2023-10-27 02:30:59 PM
— 秒の小数部を7桁全て表示
SELECT ‘Custom “yyyy-MM-dd HH:mm:ss.fffffff”:’, FORMAT(@CurrentDateTime2, ‘yyyy-MM-dd HH:mm:ss.fffffff’); — 2023-10-27 14:30:59.1234567
— タイムゾーンオフセットを含む形式 (DATETIMEOFFSET型に対してのみ有効)
SELECT ‘Custom “yyyy-MM-dd HH:mm:ss zzz” (DATETIMEOFFSET):’, FORMAT(@CurrentDateTimeOffset, ‘yyyy-MM-dd HH:mm:ss zzz’); — 2023-10-27 14:30:59 +09:00
— DATE型に対して時刻書式を指定しても時刻部分は表示されない
DECLARE @CurrentDate DATE = GETDATE();
SELECT ‘Custom “yyyy-MM-dd HH:mm:ss” (DATE):’, FORMAT(@CurrentDate, ‘yyyy-MM-dd HH:mm:ss’); — 2023-10-27 00:00:00 (時刻部分はデフォルト値)
— TIME型に対して日付書式を指定しても日付部分は表示されない
DECLARE @CurrentTime TIME = SYSDATETIME();
SELECT ‘Custom “yyyy-MM-dd HH:mm:ss” (TIME):’, FORMAT(@CurrentTime, ‘yyyy-MM-dd HH:mm:ss’); — 1900-01-01 14:30:59.1234567 (日付部分はデフォルト値)
“`
FORMAT 関数は CONVERT 関数よりもはるかに柔軟なフォーマット指定が可能で、特にカルチャに合わせた表示や、特定のカスタム形式での出力が必要な場合に非常に強力です。ただし、FORMAT 関数は CONVERT 関数に比べてパフォーマンスのオーバーヘッドが大きいことが知られています。大量のデータを変換する場合や、パフォーマンスがクリティカルな場面では、CONVERT 関数(特に言語/地域設定に依存しないスタイル)の使用を検討するか、アプリケーション側でフォーマットを行う方が良い場合もあります。
3.3. CAST 関数による変換
CAST 関数もデータ型変換に用いられますが、日付・時刻を文字列に変換する際に CONVERT のようなスタイル引数を持ちません。
構文:
sql
CAST ( expression AS data_type [ ( length ) ] )
日付・時刻型を文字列型 (VARCHAR, NVARCHAR) に CAST すると、SQL Server のデフォルト形式(SET LANGUAGE, SET DATEFORMAT に依存)で出力されます。これは CONVERT(VARCHAR, expression, 0) または CONVERT(VARCHAR, expression, 100) と同等になることが多いですが、明示的にスタイルを指定しないため、移植性や一貫性の観点からは推奨されません。
“`sql
— CASTを使用した場合 (デフォルト形式)
SELECT ‘CAST to VARCHAR:’, CAST(GETDATE() AS VARCHAR); — Oct 27 2023 2:30PM (デフォルト言語やDATEFORMATによる)
SELECT ‘CAST to VARCHAR (DATETIME2):’, CAST(SYSDATETIME() AS VARCHAR); — Oct 27 2023 2:30PM (DATETIME2でもデフォルトはDATETIME形式に似る)
— DATE型をCASTした場合
SELECT ‘CAST DATE to VARCHAR:’, CAST(CAST(‘2023-10-27’ AS DATE) AS VARCHAR); — Oct 27 2023
— TIME型をCASTした場合
SELECT ‘CAST TIME to VARCHAR:’, CAST(CAST(’14:30:59.123′ AS TIME) AS VARCHAR); — 14:30:59.123 (TIME型の場合は精度が維持されやすい)
“`
日付・時刻データを文字列に変換する目的で CAST を使うのは、特定のデフォルト形式で十分な場合や、単純な型変換のみが必要な場合に限るべきです。特定のフォーマットが必要な場合は、CONVERT または FORMAT を使用してください。
3.4. CONVERT vs FORMAT の比較と選択
- 互換性:
CONVERTは古いバージョンから存在するため互換性が高い。FORMATは SQL Server 2012以降で利用可能。 - 柔軟性:
FORMATは .NET Framework の書式設定に基づいているため、はるかに柔軟なカスタムフォーマットが可能。曜日名、月名、任意のリテラル文字列の挿入、カルチャに合わせた表示など、CONVERTでは難しい表現も容易。 - カルチャ対応:
FORMATはculture引数により、明示的に特定の言語/地域設定に基づいたフォーマットを指定できる。CONVERTの一部スタイルはシステム設定に依存する。 - パフォーマンス: 一般的に
CONVERTの方がFORMATよりも高速。特に大量のデータ変換を行う場合、FORMATはパフォーマンス上のボトルネックになりうる。 - 用途:
- 標準的で固定的な形式(YYYYMMDD, YYYY-MM-DD HH:MI:SS など)、特に言語非依存な形式が必要な場合は
CONVERT(スタイル 112, 120, 121, 126など) が適している。パフォーマンスが重要な場合もCONVERTが有利。 - ユーザーインターフェースやレポート向けに、地域や言語に合わせた、あるいは複雑なカスタム形式での表示が必要な場合は
FORMATが適している。
- 標準的で固定的な形式(YYYYMMDD, YYYY-MM-DD HH:MI:SS など)、特に言語非依存な形式が必要な場合は
どちらの関数を使用するかは、必要なフォーマットの複雑さ、SQL Serverのバージョン、そしてパフォーマンス要件を考慮して決定する必要があります。
4. 日付・時刻の構成要素を取得する
日付や時刻全体ではなく、その一部(年、月、日、時間など)を取得したい場合があります。例えば、特定の月のデータを抽出したり、年ごとの集計を行ったりする際に必要になります。SQL Serverでは、このような目的のためにいくつかの組み込み関数が用意されています。
YEAR(date): 指定された日付の年を表す整数を返します。MONTH(date): 指定された日付の月を表す整数 (1-12) を返します。DAY(date): 指定された日付の日を表す整数 (1-31) を返します。HOUR(time): 指定された時刻の時間部分を表す整数 (0-23) を返します。MINUTE(time): 指定された時刻の分部分を表す整数 (0-59) を返します。SECOND(time): 指定された時刻の秒部分を表す整数 (0-59) を返します。MILLISECOND(time): 指定された時刻のミリ秒部分を表す整数 (0-999) を返します。MICROSECOND(time): 指定された時刻のマイクロ秒部分を表す整数 (0-999) を返します。(SQL Server 2012以降)NANOSECOND(time): 指定された時刻のナノ秒部分を表す整数 (0-999) を返します。(SQL Server 2012以降)
これらの関数は、対応する部分が存在しないデータ型 (DATE に対して HOUR など) に適用すると、デフォルト値(通常0または1)を返します。
より汎用的な関数として、DATEPART(datepart, date) があります。これは指定した日付/時刻の指定した部分(datepart)を整数で返します。
datepart 引数に指定できる主な値:
year(yy, yyyy)quarter(qq, q)month(mm, m)dayofyear(dy, y)day(dd, d)week(wk, ww)weekday(dw)hour(hh)minute(mi, n)second(ss, s)millisecond(ms)microsecond(mcs)nanosecond(ns)TZoffset(tz) (DATETIMEOFFSET型に対して)iso_week(isowk, isoww) (ISO 8601 週番号)
使用例:
“`sql
DECLARE @SampleDateTime DATETIME2 = ‘2023-10-27 14:30:59.1234567’;
DECLARE @SampleDate DATE = ‘2023-10-27’;
SELECT
YEAR(@SampleDateTime) AS SampleYear, — 2023
MONTH(@SampleDateTime) AS SampleMonth, — 10
DAY(@SampleDateTime) AS SampleDay, — 27
HOUR(@SampleDateTime) AS SampleHour, — 14
MINUTE(@SampleDateTime) AS SampleMinute, — 30
SECOND(@SampleDateTime) AS SampleSecond, — 59
MILLISECOND(@SampleDateTime) AS SampleMillisecond; — 123
SELECT
MICROSECOND(@SampleDateTime) AS SampleMicrosecond, — 123456
NANOSECOND(@SampleDateTime) AS SampleNanosecond; — 123456700 (注: DATETIME2の精度は100ナノ秒なので、末尾2桁は常に00)
SELECT
DATEPART(year, @SampleDateTime) AS DP_Year, — 2023
DATEPART(month, @SampleDateTime) AS DP_Month, — 10
DATEPART(day, @SampleDateTime) AS DP_Day, — 27
DATEPART(weekday, @SampleDateTime) AS DP_Weekday, — 6 (金曜日。SET DATEFIRSTの設定による)
DATEPART(week, @SampleDateTime) AS DP_Week, — 43 (SET DATEFIRSTによる週番号)
DATEPART(iso_week, @SampleDateTime) AS DP_ISOWeek, — 43 (ISO 8601 週番号)
DATEPART(hour, @SampleDateTime) AS DP_Hour, — 14
DATEPART(minute, @SampleDateTime) AS DP_Minute, — 30
DATEPART(second, @SampleDateTime) AS DP_Second, — 59
DATEPART(millisecond, @SampleDateTime) AS DP_Millisecond, — 123
DATEPART(microsecond, @SampleDateTime) AS DP_Microsecond, — 123456
DATEPART(nanosecond, @SampleDateTime) AS DP_Nanosecond; — 123456700
— DATE型に対して時刻部分を取得しようとするとデフォルト値
SELECT
HOUR(@SampleDate) AS HourFromDate, — 0
DATEPART(minute, @SampleDate) AS MinuteFromDate; — 0
— TIME型に対して日付部分を取得しようとするとデフォルト値 (1900-01-01)
DECLARE @SampleTime TIME = ’14:30:59′;
SELECT
YEAR(@SampleTime) AS YearFromTime, — 1900
DATEPART(month, @SampleTime) AS MonthFromTime; — 1
“`
YEAR, MONTH, DAY はそれぞれ DATEPART(year, date), DATEPART(month, date), DATEPART(day, date) の省略形です。同様に HOUR, MINUTE, SECOND, MILLISECOND も DATEPART の省略形です。
DATEPART は曜日番号 (weekday) や週番号 (week, iso_week)、年の通算日 (dayofyear) など、より多様な構成要素を取得できるため、非常に便利です。
5. 日付・時刻の計算を行う
日付や時刻に対して一定の間隔を加えたり、2つの日付/時刻間の差を求めたりすることもよく行われます。SQL Serverでは、これらの操作のために DATEADD と DATEDIFF 関数が提供されています。
-
DATEADD(datepart, number, date): 指定された日付の指定された部分 (datepart) に、指定された数値 (number) を加算した結果の日付/時刻を返します。datepart:DATEPART関数と同じく、加算する単位 (year, month, day, hour, minute, secondなど) を指定します。number: 加算する値 (整数)。減算したい場合は負の数を指定します。date: 計算の基準となる日付/時刻。
-
DATEDIFF(datepart, startdate, enddate): 2つの日付/時刻 (startdate,enddate) の間の、指定された部分 (datepart) における差を整数で返します。計算はenddate - startdateのようになります。datepart: 差を計算する単位 (year, month, day, hour, minute, secondなど) を指定します。startdate: 計算開始の日付/時刻。enddate: 計算終了の日付/時刻。
-
DATEDIFF_BIG(datepart, startdate, enddate):DATEDIFFと同じですが、返す値がBIGINT型になります。非常に長い期間の差を計算する場合に、DATEDIFFのINT型の上限を超えないようにするために使用します。(SQL Server 2012以降)
使用例:
“`sql
DECLARE @BaseDate DATETIME2 = ‘2023-10-27 14:30:00’;
— 5日後
SELECT ‘5 days later:’, DATEADD(day, 5, @BaseDate); — 2023-11-01 14:30:00
— 3ヶ月前
SELECT ‘3 months ago:’, DATEADD(month, -3, @BaseDate); — 2023-07-27 14:30:00
— 2年後
SELECT ‘2 years later:’, DATEADD(year, 2, @BaseDate); — 2025-10-27 14:30:00
— 10時間後
SELECT ’10 hours later:’, DATEADD(hour, 10, @BaseDate); — 2023-10-28 00:30:00
— 30分前
SELECT ’30 minutes ago:’, DATEADD(minute, -30, @BaseDate); — 2023-10-27 14:00:00
— 2つの日付の間の日数
DECLARE @StartDate DATE = ‘2023-10-01’;
DECLARE @EndDate DATE = ‘2023-10-27’;
SELECT ‘Days between:’, DATEDIFF(day, @StartDate, @EndDate); — 26
— 2つの日時の間の時間数 (開始日時より終了日時が後の場合、正の値)
DECLARE @StartTime DATETIME = ‘2023-10-27 10:00:00’;
DECLARE @EndTime DATETIME = ‘2023-10-27 14:30:00’;
SELECT ‘Hours between:’, DATEDIFF(hour, @StartTime, @EndTime); — 4 (注: 4時間30分だが、datepart=hourなので時間単位で切り捨てられる)
— 2つの日時の間の分数を正確に計算 (より細かいdatepartで差を求め、必要なら変換)
SELECT ‘Minutes between:’, DATEDIFF(minute, @StartTime, @EndTime); — 270 (4*60 + 30)
— 2つの日付の間の月数 (差の計算方法に注意)
— DATEDIFF(month, ‘2023-10-31’, ‘2023-11-01’) は 1 を返します。これは月の境界を跨いだ回数を数えるためです。
— 厳密な月齢を計算したい場合は別の方法が必要です。
SELECT ‘Months between:’, DATEDIFF(month, ‘2023-10-01’, ‘2023-10-31’); — 0
SELECT ‘Months between:’, DATEDIFF(month, ‘2023-10-31’, ‘2023-11-01’); — 1
SELECT ‘Months between:’, DATEDIFF(month, ‘2023-01-31’, ‘2023-03-01’); — 2
— DATEDIFF_BIG (非常に大きな差を計算する場合)
— 例: 1800年から2023年までの日数 (INTの上限を超える可能性がある)
SELECT DATEDIFF_BIG(day, ‘1800-01-01’, GETDATE()); — 日数がBIGINTで返される
“`
DATEADD と DATEDIFF は日付・時刻計算の基本です。これらの関数を組み合わせることで、様々な期間計算や日付操作が可能になります。ただし、DATEDIFF の計算方法、特に月や年の単位での計算は直感的でない場合があるため注意が必要です(期間の終わりが期間の開始よりも後の場合、境界を跨いだ回数が計算されます)。
6. 現在の日付・時刻を取得する関数
SQL Serverには、現在のシステム日付、データベースサーバーの日付、またはUTC(協定世界時)の日付を取得するためのいくつかの関数があります。
GETDATE(): 現在のデータベースセッションの日付と時刻をDATETIME型で返します。この値はセッションの開始時刻に固定される場合があり、ミリ秒の精度もDATETIME型に依存します。SYSDATETIME(): 現在のシステムの日付と時刻をDATETIME2(7)型で返します。GETDATE()よりも精度が高く、常に現在のシステム時刻を反映します。推奨される関数です。SYSUTCDATETIME(): 現在のシステムの日付と時刻を UTC でDATETIME2(7)型で返します。GETUTCDATE(): 現在のデータベースセッションの UTC 日付と時刻をDATETIME型で返します。SYSDATETIME()に対するSYSUTCDATETIME()の関係と同様に、GETDATE()のUTC版であり精度は低いです。SYSDATETIMEOFFSET(): 現在のシステムの日付と時刻、およびタイムゾーンオフセットをDATETIMEOFFSET(7)型で返します。タイムゾーン情報を必要とする場合に最も適しています。
使用例:
sql
SELECT
GETDATE() AS GetDateValue, -- DATETIME型
SYSDATETIME() AS SysDateTimeValue, -- DATETIME2(7)型
SYSUTCDATETIME() AS SysUtcDateTimeValue, -- DATETIME2(7)型 (UTC)
GETUTCDATE() AS GetUtcDateValue, -- DATETIME型 (UTC)
SYSDATETIMEOFFSET() AS SysDateTimeOffsetValue; -- DATETIMEOFFSET(7)型 (ローカル + オフセット)
これらの関数は、データの登録時刻を記録したり、現在時刻に基づいたクエリを実行したりする際などに使用されます。新規開発においては、高精度な SYSDATETIME() や SYSDATETIMEOFFSET() を使用することが推奨されます。
7. タイムゾーンの扱い (DATETIMEOFFSET)
DATETIMEOFFSET 型は、日付・時刻情報に加えてタイムゾーンのオフセット情報 (+hh:mm または -hh:mm) を格納できるデータ型です。これにより、世界中の異なるタイムゾーンで発生したイベントの時刻を正確に記録・比較・変換することが可能になります。
タイムゾーン関連の主な関数:
SWITCHOFFSET(datetimeoffset, time_zone): 指定されたDATETIMEOFFSET値を、指定されたタイムゾーンオフセットに変換します。元の UTC 時刻は維持されます。time_zone: 変換先のタイムゾーンオフセットを表す文字列 (‘+09:00’など) または整数 (分単位)。
TODATETIMEOFFSET(expression, time_zone):DATETIMEまたはDATETIME2値に、指定されたタイムゾーンオフセットを関連付けてDATETIMEOFFSET値を作成します。元の時刻がそのオフセットにおけるローカル時刻として扱われます。
使用例:
“`sql
— 現在のシステム時刻とタイムゾーンオフセットを取得 (例: 日本標準時 +09:00)
DECLARE @LocalTimeOffset DATETIMEOFFSET = SYSDATETIMEOFFSET();
SELECT ‘Local Time (with offset):’, @LocalTimeOffset; — 例: 2023-10-27 14:30:59.1234567 +09:00
— この時刻を UTC (オフセット +00:00) に変換
SELECT ‘Converted to UTC:’, SWITCHOFFSET(@LocalTimeOffset, ‘+00:00’); — 例: 2023-10-27 05:30:59.1234567 +00:00 (元の時刻から9時間引かれる)
— この時刻を太平洋標準時 (PST, オフセット -08:00) に変換
SELECT ‘Converted to PST:’, SWITCHOFFSET(@LocalTimeOffset, ‘-08:00’); — 例: 2023-10-27 21:30:59.1234567 -08:00 (元の時刻から17時間引かれる = UTCから8時間引かれる)
— UTC 時刻を取得
DECLARE @UtcTime DATETIME2 = SYSUTCDATETIME();
SELECT ‘UTC Time (no offset):’, @UtcTime; — 例: 2023-10-27 05:30:59.1234567
— UTC 時刻に特定のオフセットを付けて DATETIMEOFFSET にする (この例では、UTC 時刻をローカル時刻として扱うことになり、意図と異なる場合がある)
SELECT ‘UTC Time with +09:00 offset (incorrect):’, TODATETIMEOFFSET(@UtcTime, ‘+09:00’); — 例: 2023-10-27 05:30:59.1234567 +09:00 (時刻自体はUTCのまま、オフセットだけ付く)
— SYSDATETIME (ローカル時刻、オフセットなし) に特定のオフセットを付けて DATETIMEOFFSET にする
DECLARE @LocalTimeNoOffset DATETIME2 = SYSDATETIME();
SELECT ‘Local Time (no offset):’, @LocalTimeNoOffset; — 例: 2023-10-27 14:30:59.1234567
SELECT ‘Local Time with +09:00 offset:’, TODATETIMEOFFSET(@LocalTimeNoOffset, ‘+09:00’); — 例: 2023-10-27 14:30:59.1234567 +09:00 (SYSDATETIMEの時刻を+09:00のローカル時刻として扱う)
“`
タイムゾーンを意識した正確な時刻処理が必要な場合は、DATETIMEOFFSET 型と関連関数を積極的に使用することが重要です。特に、複数の地域からのログデータを収集する場合や、国際的なユーザーを持つアプリケーションでは必須となります。
8. よくある問題とトラブルシューティング
SQL Serverで日付・時刻を扱う際に遭遇しやすい問題とその対処法をいくつか紹介します。
-
暗黙的な型変換によるエラーや意図しない結果:
- 文字列から日付・時刻型への変換時、文字列の形式がシステムの設定(
SET DATEFORMATや言語設定)に依存する場合、予期しない日付になったり、変換エラーが発生したりします。 - 対処法: 常に言語/地域設定に依存しない形式 (
YYYYMMDD,YYYY-MM-DDTHH:MI:SS) で文字列リテラルを入力するか、CONVERTやFORMAT関数で明示的に形式を指定して変換を行うようにします。
- 文字列から日付・時刻型への変換時、文字列の形式がシステムの設定(
-
CONVERTのスタイル選択ミス:- 意図しない区切り文字が使われたり、年の桁数が違ったり、AM/PM表示になったりするなど、期待するフォーマットと異なる結果になることがあります。
- 対処法: 必要な出力形式に合った
styleコードを正確に選択します。言語依存を避けたい場合は、数値のみのスタイル(112, 120, 121など)を使用します。
-
FORMAT関数のパフォーマンス問題:- 特に大量の行に対して
FORMAT関数を使用すると、CONVERTに比べて処理が遅くなることがあります。 - 対処法: パフォーマンスがクリティカルな場面では、まず
CONVERT関数で実現できないか検討します。難しい場合は、アプリケーション側で取得した日付・時刻データをフォーマットするか、バッチ処理やインデックスの活用などを検討します。
- 特に大量の行に対して
-
DATEDIFFの計算方法の理解不足:DATEDIFF(month, '2023-10-31', '2023-11-01')が 1 を返すなど、境界を跨いだ回数で計算される点に注意が必要です。- 対処法:
DATEDIFFの挙動をよく理解し、必要に応じてより細かい単位で差を計算してから変換するか、他の計算方法(例:YEAR(end) * 12 + MONTH(end) - (YEAR(start) * 12 + MONTH(start)))を使用します。
-
DATETIMEの精度不足:- ミリ秒以下の情報が重要なのに
DATETIME型を使用していると、精度が失われます。 - 対処法: より高精度な
DATETIME2型を使用します。
- ミリ秒以下の情報が重要なのに
-
タイムゾーンの考慮漏れ:
- 異なるタイムゾーンのデータを単純に比較・格納すると、時刻のずれが発生します。
- 対処法: タイムゾーン情報を扱う必要がある場合は、
DATETIMEOFFSET型を使用し、SWITCHOFFSET関数などを用いて適切に変換・比較を行います。可能であれば、データベースには UTC 時刻を格納し、表示時にローカルタイムに変換するのが良いプラクティスとされています。
-
セッション設定 (
SET LANGUAGE,SET DATEFORMAT) の影響:- スクリプトやアプリケーションの実行環境によって、セッションの設定が異なり、日付リテラルの解釈やデフォルトの表示形式が変わることがあります。
- 対処法: スクリプトの先頭で
SET LANGUAGEやSET DATEFORMATを明示的に設定するか、常に言語/地域設定に依存しない形式を使用します。特に重要な処理では、依存しない形式での入力・出力形式の指定を徹底します。
9. まとめ
SQL Serverにおける日付・時刻データの扱いは多岐にわたります。適切なデータ型の選択、言語/地域設定に依存しないリテラル形式の利用、そして目的に合わせたフォーマット変換関数の使い分けが、正確で安定したシステムを構築する上で不可欠です。
- データ型:
DATETIME2とDATETIMEOFFSETは、現代のアプリケーション要件の多くを満たす高精度かつ広範囲をサポートする推奨されるデータ型です。 - 入力:
YYYYMMDDやYYYY-MM-DDTHH:MI:SSのような、言語/地域設定に依存しない標準的な形式でのリテラル入力を心がけましょう。 - 変換・表示:
- 標準的な形式や言語非依存な形式への変換、およびパフォーマンス重視の場合は
CONVERT関数(スタイル番号を指定)を使用します。 - 柔軟なカスタム形式、特にカルチャに合わせた表示や曜日名・月名などの詳細な制御が必要な場合は
FORMAT関数(SQL Server 2012以降)を使用します。ただしパフォーマンスに注意が必要です。
- 標準的な形式や言語非依存な形式への変換、およびパフォーマンス重視の場合は
- 構成要素の取得・計算:
DATEPART,YEAR,MONTH,DAY,HOURなどで構成要素を取得し、DATEADD,DATEDIFFで日付・時刻計算を行います。 - 現在時刻: 高精度なシステム時刻を取得するには
SYSDATETIME()やSYSDATETIMEOFFSET()を使用します。 - タイムゾーン: 国際化されたシステムや複数の地域からのデータ収集には
DATETIMEOFFSET型とSWITCHOFFSETなどの関数が不可欠です。
日付・時刻処理は複雑な側面もありますが、この記事で解説した基本的な概念と関数を理解すれば、多くのケースに対応できるようになります。実践を通じて、これらの知識を深めていくことをお勧めします。正確な日付・時刻の管理は、データベースシステムの信頼性を高める上で非常に重要な要素です。