データベースから文字列として日付を返さないのはなぜですか?


41

典型的なWebアプリケーションでは、日付は強く型付けされたデータベースレイヤーから取得されます(たとえば、c#ではSystem.StringではなくSystem.DateTimeとして)。

日付を文字列として表現する必要がある場合(ページに表示するなど)、DateTimeから文字列への変換はプレゼンテーション層で行われます。

どうしてこれなの?DateTimeをデータベース層の文字列に変換するのはなぜ悪いことですか?

チャットでの激しい議論や、これを始め最初の質問も見てください。


73
これを聞いてみましょう。すべての型を文字列に変換しますか?Dateの違いは何ですか?
ガーデンヘッド

7
良い質問!進行中白熱した議論をご覧ください。
ジョン・ウー

8
さて、他の人が間違っていることは明らかで、他の人はすべて正しいです。ここでは本当に質問ではありません
-gardenhead

7
データベースの外で日付の計算を行う必要がある場合があります。持っているのが文字列だけである場合は、かなり難しい。
エリックキング

14
別の問題-どのような文字列が必要ですか?日時を文字列として表現する方法はたくさんあります。文字列としてエポックからの秒数として表される現在の時刻のみを返すデータベースがあった場合(たとえば、現在の時刻は "1474496980")。それは便利でしょうか?そのようなデータベースを使用しますか?
riwalk

回答:


168

日付、DateTimes、および実際に他の型付きオブジェクトは、一般に、他の型にする必要がある瞬間まで、特にその型が人間が読める形式である場合、特に非可逆/一方向の変換。

どうして?このタイプは、適切な等価性テスト、加算と減算、比較(より大きい、より小さい)、タイムゾーンおよびロケール機能(特に時間関連の場合に重要)など、多くの便利な組み込み機能を提供すると想定されているため、など。アメリカ人と「Month Day [th]、Year」フォーマット、および一般的な英国スタイルの「Day Month Year」、またはISO標準の「Year-Month-Day」をサポートする場合は、それが文字列であり、その変更を行う必要がある場合はどうしますか?それを解析して日付に戻しますか?ええと、感謝しません-そのように多くの悪と卑劣なバグがありますが、それらは完全に回避するのが最善です。

より具体的には、後でデータとは別のプレゼンテーション層を持つ階層型アーキテクチャについて言及しました。これは実際に、日付を文字列ではなく日付として渡すもう1つの大きな理由です。日付を入力する必要があるのは、どのタイプの文字列フォーマットですか。英語、中国語、秒/ミリ秒の有無にかかわらず、完全な月名または数字、日付フィールドで後で並べ替えますか(文字列で並べ替えるには、適切に機能させるために特定の文字列形式が必要です)。これはすべてプレゼンテーションの問題であり、ユーザーがデータをどのように表示する必要があるかということです。また、そのロジックを他の場所に配置すると、最初から階層アーキテクチャを使用する利点が制限されます。データベースは、将来の日付をどのように表示するかを知っている必要はありません。

最後に、時間を重視するほぼすべての複雑なアプリケーション(階層型アーキテクチャの目的)は、多くのさまざまな方法で、多くの場合アーキテクチャのすべてのレベルで時刻/日付を使用することを避けられません。時刻と日付に関連する型付きオブジェクトは、本当に正当な理由で存在します。時刻自体、特に人間のカレンダーシステムは奇妙で難しいものです。最終的に、時刻と日付は、整数と浮動小数点が文字列ではないのと同じ理由で文字列ではありません。実際には文字の配列であると偽装しようとすると、人生が難しくなります。


26
+1という言葉を卑劣に使用するためだけに。説得力のある議論と包括的な説明には同意しますが、だからログインして投票しなければなりませんでした。
エイドリアンラーソン

1
過去の定義された時刻からの日付時刻を秒として表すことも、さまざまなカレンダー間で堅牢です。たとえば、イスラム暦および中国暦では、グレオリオ暦の月、年などは使用されません。これをデータベースレベルで処理するのは悪い習慣と考えています。
rexkogitans

日付は、多くの場合「X日前」と表示されます。解析して元の値に戻してください。
Agent_L

5
また、DSTの変更(およびその他の同様の)問題も忘れないでください。ウィル「2016年11月6日午前一時30分26秒AMが」この日付と時刻が起きているということを初めてまたは二度目になりますか?UTC DateTimeは少なくとも一意であり、その時間のローカル表現にいつでも変換できます-他の方法に戻ることは常に可能ではありません。
J ...

3
Why? Because it is assumed that the type provides you with lots of handy built in functionality私の意見では、これは二次的なものです。本当の理由は、タイプが何かを教えてくれるからです。日付は文字列ではなく、たまたま人間が読める文字列に簡単に変換できます。
ドーバル

53

彼は、Webサーバーを使用してデータ時間を文字列に変換することを言っています。Webサーバーではなく、データベースサーバーで行うと言っています。なぜそれが良いと思いますか?- MTヘッド

タイプを知りたい。

データベースが文字列、一部の整数、またはバイトのいずれに情報を保存するかは、実際には気にしません。データベースで必要とされるよりも多くのスペースを占める文字列は、私を悩ませません。私が気になるのは、このような日付に遭遇しています:

2016年11月10日

そして、それが11か月目か10か月目か分からない。

しかし、あなたが言うことは検証済みです。検証プロセスを通過してください。日付は完全に正しいです。しかし、ここで私はこのことを維持しており、私が知っているのは日付が文字列であることだけです。私はこれが何日であるかさえあなたに話すことができません。

「主君の二千十六年目の十一月十日。」

それは文字列です。プレゼンテーションの1つでは、その形式でそれを必要とします。データベースはすべての日付を文字列に変換すると言いましたね?それを楽しんでください。

データベースの仕事は、存在しないデータを保存することです。もちろん、文字列でそれを行うこともできますが、それを解析して、他の形式で表示するのに役立つようにする必要があります。DBが提供するあらゆるタイプの標準の解析済みフォームに保存することで、プレゼンテーションを決定することなく、できる限りプレゼンテーションの準備が整います。DBがそのタイプを文字列、整数、またはバイトでバッキングするかどうかは、私にとって実際には関係ありません。それが何をしているかを知っている限り。

ただし、日付を処理していることをDBに通知せず、日付を文字列として保存すると、他のすべてのプレゼンテーションよりも早めに1つのプレゼンテーションを提示することになります。これにより、変換する前に他のすべてのプレゼンターが解析されます。いいえ、データベースはプレゼンテーション層の一部ではありません。あるように頼まないでください。

同様に、プレゼンテーション層はデータベースの一部ではないため、レポートをデータベースの詳細に結合することは賢明ではありません。型を操作する方がはるかに堅牢です。


この回答は、ストレージを文字列として扱います。ただし、ネイティブの日付型に日付を保存する一般的なパターンは扱いませんが、CONVERT(T-SQL)などの関数を使用してSQLクエリの文字列フォーマットするか、DBMSは通常その日付をシリアル化しますクエリに関係なく、構成可能な形式の文字列に変換します。たとえば、次のようにpostgresql.org/docs/9.5/static/...
dcorking

それはレポートです。保管後に発生します。生年月日を私の年齢に変換するようなものです。
candied_orange

2
OPのトピックは「データベースレイヤーから日付を取得する方法」であるため、答えを拡張することをお勧めします。レポートは、書式設定されローカライズされた日付文字列をデータベースに照会する、確立された、ほぼ間違いなく廃止されたパターンがあります。OPはこれらの非推奨の議論を聞きたいと思います。私はそうすることを知っています。
12

@dcorking noteの更新。
candied_orange

工場に水を追加する+1:絶対的な瞬間が最重要である複数のタイムゾーンにまたがる設置ベースでシステムを作成し、文字列<-> timestamp変換がどこでうまくいくかを確認します。最悪の場合、人々が独自のプラグインを作成し、文字列がこれらのタイムスタンプの一貫性を確認するときにタイムスタンプを与えるために、拡張ポイントを作成します!
ニュートピア

19

ロケール

プレゼンテーション目的で日付を文字列に変換するには、ユーザー設定を知る必要があります。これは、通常、まったく同じ日付が異なるロケールのユーザーに対して異なる方法で表示されるためです。アプリケーションで単一のロケールを使用する場合でも、適切な動作では、データベースサーバーの代わりにアプリケーションのロケールを使用する必要があります。現時点で偶然一致したとしても、同一であるとは限りません。

ユニバーサル日付データ型からロケール固有の文字列への変換は、プレゼンテーション層で行われる必要があります。これは、変換がどのように実行されるべきを知っているのは層だからです。


3
ロケールの不一致の実際の例として、米国メイン州のユーザー向けにアプリを作成し、それをAmazonの西海岸サーバーファームでホストすることを想像してください。;)これは、実際にはそれほどありそうもない状況ではありません。
jpmc26

@ jpmc26違いがわからない-メイン州は他の米国とは異なる日付形式を使用していますか?
ピートカーカム

2
@PeteKirkham Maineと米国西海岸では、3時間離れたタイムゾーンが使用されます。
jpmc26

1
または別の現実のシナリオ:異なるロケール(およびわずかに異なるフォーマットルール)を持つ4つの言語(ドイツ語、フランス語、イタリア語、英語)のクライアントにサービスを提供するサーバーをスイスで実行することを想像してください。このような状況で、サーバーに適切なロケールを選択してください。
Voo

1
@ jpmc26タイムゾーンとロケールは同じものではありません。たとえば、米国アトランタのグラスゴースコットランドとインドのプネにオフィスがあります。これらのオフィスのコンサルタントは、世界中のサイト(キャンパス、病院、ホテルなど)を24時間監視しています。アプリケーションデータベースはUTCで機能しますが、監視対象サイトの現地時間で時刻を表示します。米国のコンサルタントの日付はMM / DD / YYYYにローカライズされていますが、英国とインドのロケールはDD / MM / YYYYです。これは、サイトまたはユーザーのタイムゾーンではなくロケールに依存します。
ピートカーカム

9

これは、アプリケーション層に到達するとすぐに任意の型を文字列に盲目的に変換するのと同じ理由で望ましくありません。ユーザーにオブジェクトを提示する前に、何らかの方法でそのオブジェクトを使用する可能性が高くなります(ユーザーに提示する場合でも)。この特定の例では、オブジェクトに対して何らかの日付計算を行う必要があると想像してください。オブジェクトを表示する前に正確に文字列に変換するだけの欠点はありません。


4

型には理由があります。利点が追加されない場合、それらは使用されず、使用されず、「型」のみが存在し、すべてがそのようになります。彼らは便利であるだけでなく、安全性と効率性も追加します。以下は、文字列ではなく、常にネイティブ形式で型を保持する必要がある理由のリストです。DateTimeほとんどの場合、例として使用しましたが、整数、小数、バイナリなどのプリミティブ型にも同じ原理が適用されます。


データストア

制約

型の制約

ほとんどすべてのデータストアでは、データの制約を指定できます。これには型の制約が含まれます。DateTimeインスタンスを指定する主な利点の1つは、保存されたデータがそのタイプに制限されることです。データがストアに挿入された方法に関係なく、日時以外は入力できません。後者は、ストアと直接対話する複数のプロセスがある大規模なシステムにとって重要です。これには、2月はうるう年で29日、うるう年でない場合は28日しか持てないため、2月30日(任意の年)のような誤った日付を追加しようとすることも含まれます。

検証の制約

また、挿入された日付が現在の日付を超えないようにする、または開始日が終了日より前に発生するようにするなど、データストアに実装できる検証制約もあります。

オペレーション

ほとんどのデータ・ストアにも同様の操作/機能に組み込まれているDateAddか、DatePartMS SQL Serverのインチ これにより、データがまだストアにある(まだアプリケーションに取得されていない)間に特定のデータのフィルタリングまたは選択を開始できます。

広く受け入れられている形式

ネイティブタイプを使用することにより、ストアと対話する他の開発者またはシステムは、そのプリミティブタイプがどのように格納されるかについての詳細を知る必要がありません。その型が文字列として格納されている場合は、そうではありません。その場合、すべての人がそのDateTime文字列表現の形式を理解していることを確認する必要があります。このシステムは、データ発信元のロケール、地域、文化にまたがるデータ、アプリケーションの物理的な場所、そのデータとやり取りするエンドユーザー/システムの属性を扱う場合に脆弱になります。例:ある国の日付形式はMM / dd / yyyy(米国のように)かもしれませんが、別の国ではdd / MM / yyyyである可能性があり、違いがほとんど不可能になることを検出します。

速度

取得の速度、検証の速度、操作の速度、ストレージ効率もすべて重要な要素です。取得速度の例:データストアは列のインデックスを許可し、型がネイティブ形式で格納されている場合、これらのインデックスは一般的により効率的に使用できます。

応用

データアクセス

開発者は再びストレージ形式を推測する必要がないため、ネイティブタイプシステムを使用すると、ストアに対するクエリの実行がより簡単になります。ほとんどすべてのデータストアアプリケーションプロバイダー(例:ado.net)は、渡されたネイティブ型に基づいて適切なパラメーター化されたクエリを作成するためのメカニズムを提供します。文字列で同じことを行うと、非常に面倒で壊れやすく/エラーが発生しやすくなります。

command.Parameters.Add(new SqlParameter("@startDate", SqlDbType.Date) {Value = myDateInstance.Date});

オペレーション

コード内のネイティブタイプは、.netタイプなどの標準操作も提供しSystem.Dateます。操作は通常、日付の追加、日付の違いの検出など、数学的な性質を持っています。繰り返しますが、これは文字列型に対して簡単に行うことはできません。

プレゼンテーション層

ロケール

プリミティブ型が最終的にプレゼンテーション層で文字列に変換されるとき(そうするためのプログラムスタック内の正しい場所)、プログラマーには、提示されたコンテキストに従って正しく表示するためのさまざまなオプションがあります。このコンテキストは通常​​、データの実際の意味とユーザーのロケールで構成されます。

例1

日時インスタンスは、ユーザーのロケールに基づいて自動的にフォーマットできます。

DateTime.Now.ToString("D", CultureInfo.GetCultureInfo(userContext.Culture))
例2

10進数のインスタンスは金額(通貨)を表している可能性があり、ユーザーのロケールも好みに応じて金額を表示する必要があります。C#アプリケーションは、次を使用して値を表示します。

amount.ToString("C", CultureInfo.GetCultureInfo(userContext.Culture))

これは、文化が異なると数字が異なるため、重要になる可能性があります。米国では、ピリオド(。)とコンマ(、)は、オランダとまったく逆の意味を持ちます。

ロケーション

これはDateTimeインスタンスに非常に固有です。日付と時刻は、特定の瞬間の発生を表しますが、通常、ユーザー自身のタイムゾーンに応じて、これをユーザーに伝達/提示する必要があります。例:米国の東部時間帯のユーザーのようにDateTimeインスタンス2016-09-21T23:38:21.399Zを表示できます9/21/2016 5:21 PM。これを実現するには多くの方法がありますが、日時インスタンスが文字列型としてメモリに保持されている場合、またはデータストアに文字列型として保持されている場合、ほとんど不可能になります。


原則

プリミティブ型を文字列表現に変換する場合、アプリケーションの一般的な2つの規則は次のとおりです。

  • 入力を受け入れる場合、プログラムスタックのできるだけ早い段階で(通常はプレゼンテーション層で)、その入力を正しいプリミティブ型に変換します。
  • 表示するデータを取得するとき、そのデータをプログラムスタック内のできるだけ遅い文字列表現に変換します(再び、通常はプレゼンテーション層で)

0

日付にあいまいでない形式を使用している限り、これを実行しても問題はありません(サービスで常に実行されます)。明確であるということは、日付が明確である(たとえば、MM / DD対DD / MM)だけでなく、そのタイムゾーンも含まれていることを意味します。 。UTCベースの時間文字列を強く好みます。

長所:

  • 標準ベースの日付/時刻文字列は移植可能であり、理解しやすい
  • 多くの場合、DBの日付には時刻コンポーネントが含まれます。これがデータにとって意味がない場合、これは実際に物事を単純化できます。

短所:

  • データサイズ。DBの日付の内部形式は、通常、その日付の文字列レンダリングよりもはるかに少ないスペースを使用します。
  • 通常は、クライアントで実際の日付または時刻構造に変換するため、解析に余分な時間がかかる場合があります。

誰かがこれをやりたいと言ったら、「なぜ?」あまり意味がないからです 誰かが日付を文字列として返したい理由が、それを直接表示するためである場合、これはDBの文字列を使用する正当な理由ではありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.