apeescape2.com
  • メイン
  • Kpiと分析
  • アジャイル
  • 革新
  • モバイルデザイン
バックエンド

DateTime操作の決定的なガイド

ソフトウェア開発者として、日付操作から逃げることはできません。開発者が作成するほとんどすべてのアプリには、ユーザーから日付/時刻を取得し、データベースに保存して、ユーザーに表示する必要があるコンポーネントがあります。

日付とタイムゾーンを処理した経験についてプログラマーに尋ねると、おそらくいくつかの戦争の話を共有するでしょう。日付と時刻のフィールドの処理は確かにロケット科学ではありませんが、退屈でエラーが発生しやすいことがよくあります。

このトピックに関する記事は何百もありますが、そのほとんどは学術的すぎて本質的な詳細に焦点を当てているか、パッチが多すぎて説明があまりない短いコードスニペットを提供しています。このDateTime操作の詳細なガイドは、このトピックに関する大量の情報を閲覧しなくても、時間と日付に関連するプログラミングの概念とベストプラクティスを理解するのに役立ちます。



この記事では、日付と時刻のフィールドについて明確に考えるのに役立ち、日付と時刻の地獄を回避するのに役立ついくつかのベストプラクティスを提案します。ここでは、日付と時刻の値を正しく操作するために必要ないくつかの重要な概念、DateTime値を格納してAPIを介して転送するのに便利な形式などについて説明します。

手始めに、本番コードの正しい答えは、ほとんどの場合、独自のライブラリを作成するのではなく、適切なライブラリを使用することです。この記事で説明するDateTime計算の潜在的な問題は氷山の一角に過ぎませんが、ライブラリの有無にかかわらず、それでも知っておくと役立ちます。

DateTimeライブラリは、それらを正しく理解している場合に役立ちます

日付ライブラリは、あなたの生活を楽にするために多くの点で役立ちます。これらは、日付の解析、日付の算術演算と論理演算、および日付のフォーマットを大幅に簡素化します。フロントエンドとバックエンドの両方で信頼できる日付ライブラリを見つけて、手間のかかる作業のほとんどを実行できます。

ただし、日付/時刻が実際にどのように機能するかを考えずに、日付ライブラリを使用することがよくあります。日付/時刻は複雑な概念です。誤った理解のために発生するバグは、日付ライブラリの助けを借りても、理解して修正するのが非常に難しい場合があります。プログラマーは、基本を理解し、日付ライブラリがそれらを最大限に活用するために解決する問題を理解できる必要があります。

また、日付/時刻ライブラリはこれまでのところしか取得できません。すべての日付ライブラリは、DateTimeを表す便利なデータ構造にアクセスできるようにすることで機能します。 REST APIを介してデータを送受信する場合、JSONにはDateTimeを表すネイティブデータ構造がないため、最終的に日付を文字列に変換する必要があります。ここで概説した概念は、これらの日付から文字列および文字列から日付への変換を行うときに発生する可能性のある一般的な問題のいくつかを回避するのに役立ちます。

注意: 使ったのに JavaScript この記事で説明するプログラミング言語として、これらは、事実上すべてのプログラミング言語とその日付ライブラリに大部分が適用される一般的な概念です。したがって、これまでにJavaScriptの行を書いたことがない場合でも、この記事でJavaScriptについての予備知識はほとんどないと思いますので、お気軽に読み続けてください。

時間の標準化

DateTimeは、非常に特定の時点です。これについて考えてみましょう。この記事を落書きすると、ラップトップの時計は7月21日午後1時29分を示しています。これは私たちが「現地時間」と呼んでいるもので、私の周りの掛け時計や腕時計に見られる時間です。

数分待ってください。午後3時に近くのカフェで友達に会うように頼むと、ほぼその時間に彼女に会うことが期待できます。同様に、たとえば「1時間半で会いましょう」と言っても、混乱はありません。私たちは日常的に、同じ都市やタイムゾーンに住む人々とこのように時間について話します。

別のシナリオを考えてみましょう。スウェーデンのウプサラに住む友人に、午後5時に話したいことを伝えたいと思います。私は彼にメッセージを送ります。「ねえアントン、午後5時に話しましょう。」 「あなたの時間ですか、それとも私の時間ですか?」という応答がすぐに届きます。

アントンは、UTC + 01:00である中央ヨーロッパのタイムゾーンに住んでいると私に言います。私はUTC + 05:45に住んでいます。これは、私が住んでいる午後5時の場合、午後5時-05:45 = 11:15 AM UTCであり、これは、ウプサラでは11:15 AM UTC + 01:00 = 12:15 PMに相当し、両方に最適です。私たちの。

また、タイムゾーン(中央ヨーロッパ時間)とタイムゾーンオフセット(UTC + 05:45)の違いに注意してください。国は、政治的な理由から、夏時間のタイムゾーンオフセットを変更することもできます。ほぼ毎年、少なくとも1つの国でルールが変更されています。つまり、これらのルールが組み込まれているコードはすべて最新の状態に保つ必要があります。アプリの各層で、コードベースがこれにどのように依存しているかを検討する価値があります。

これは、ほとんどの場合、フロントエンドのみがタイムゾーンを処理することをお勧めするもう1つの理由です。そうでない場合、データベースエンジンが使用するルールがフロントエンドまたはバックエンドのルールと一致しないとどうなりますか?

ユーザーと広く受け入れられている標準との2つの異なるバージョンの時間を管理するというこの問題は困難であり、精度が重要で1秒でも大きな違いを生むプログラミングの世界ではさらに困難です。これらの問題を解決するための最初のステップは、DateTimeをUTCで保存することです。

フォーマットの標準化

UTC時刻を保存するだけでよく、ユーザーのタイムゾーンを知っている限り、いつでもユーザーの時刻に変換できるため、時刻の標準化はすばらしいことです。逆に、ユーザーの現地時間を知っていて、そのタイムゾーンを知っている場合は、それをUTCに変換できます。

ただし、日付と時刻はさまざまな形式で指定できます。日付には、「7月30日」、「7月30日」、「7/30」(または住んでいる場所によっては30/7)と書くことができます。とりあえず、「午後9時30分」または「2130」と書くことができます。

世界中の科学者が集まってこの問題に取り組み、短くて正確であるためにプログラマーが本当に好きな時間を表す形式を決定しました。これを「ISO日付形式」と呼びます。これは、ISO-8601拡張形式の簡略版であり、次のようになります。

ISO日付形式と呼ばれるISO-8601拡張形式の簡略版を示す画像。

00:00またはUTCの場合、代わりに「Z」を使用します。これは、UTCの別名であるズールー時間を意味します。

JavaScriptでの日付操作と算術

ベストプラクティスを開始する前に、JavaScriptを使用した日付操作について学習し、構文と一般的な概念を理解します。 JavaScriptを使用していますが、この情報をお気に入りのプログラミング言語に簡単に適合させることができます。

日付演算を使用して、ほとんどの開発者が遭遇する一般的な日付関連の問題を解決します。

私の目標は、文字列から日付オブジェクトを作成し、文字列からコンポーネントを抽出することを快適にすることです。これは日付ライブラリが役立つものですが、舞台裏でどのように行われるかを理解することをお勧めします。

日付/時刻で手を汚すと、直面している問題について考え、ベストプラクティスを抽出し、先に進むことが容易になります。ベストプラクティスにスキップしたい場合は、気軽に行ってください。ただし、少なくとも以下の日付演算のセクションをざっと読むことを強くお勧めします。

JavaScriptの日付オブジェクト

プログラミング言語には、私たちの生活を楽にするための便利な構造が含まれています。 JavaScript Dateオブジェクトはそのようなものの1つです。現在の日付と時刻を取得し、変数に日付を格納し、日付演算を実行し、ユーザーのロケールに基づいて日付をフォーマットするための便利な方法を提供します。

ブラウザの実装の違いと夏時間(DST)の不適切な処理のため、ミッションクリティカルなアプリケーションのDateオブジェクトに依存することはお勧めできません。おそらく、次のようなDateTimeライブラリを使用する必要があります。 Luxon、date-fns、またはdayjs 。 (使用するものは何でも、かつて人気のあったMoment.js(コードに表示されるように単にmomentと呼ばれることが多い)は廃止されたため、避けてください。)

ただし、教育目的では、Date()オブジェクトが提供するメソッドを使用して、JavaScriptがDateTimeを処理する方法を学習します。

現在の日付を取得する

const currentDate = new Date();

Dateコンストラクターに何も渡さない場合、返される日付オブジェクトには現在の日付と時刻が含まれます。

次に、次のようにフォーマットして、日付部分のみを抽出できます。

const currentDate = new Date(); const currentDayOfMonth = currentDate.getDate(); const currentMonth = currentDate.getMonth(); // Be careful! January is 0, not 1 const currentYear = currentDate.getFullYear(); const dateString = currentDayOfMonth + '-' + (currentMonth + 1) + '-' + currentYear; // '27-11-2020'

注:「1月は0」の落とし穴は一般的ですが、普遍的ではありません。使用を開始する前に、任意の言語(または構成形式:たとえば、cronは特に1ベース)のドキュメントを再確認することをお勧めします。

現在のタイムスタンプを取得する

代わりに現在のタイムスタンプを取得する場合は、新しいDateオブジェクトを作成し、getTime()メソッドを使用できます。

const currentDate = new Date(); const timestamp = currentDate.getTime();

JavaScriptでは、タイムスタンプは1970年1月1日から経過したミリ秒数です。

サポートするつもりがない場合

日付の解析

文字列をJavaScriptの日付オブジェクトに変換するには、さまざまな方法があります。

Dateオブジェクトのコンストラクターは、さまざまな日付形式を受け入れます。

Date.now()

JSは任意の日付の曜日を決定できるため、曜日を含める必要はないことに注意してください。

年、月、日、時、分、秒を個別の引数として渡すこともできます。

const date1 = new Date('Wed, 27 July 2016 13:30:00'); const date2 = new Date('Wed, 27 July 2016 07:45:00 UTC'); const date3 = new Date('27 July 2016 13:30:00 UTC+05:45');

もちろん、いつでもISO日付形式を使用できます。

const date = new Date(2016, 6, 27, 13, 30, 0);

ただし、タイムゾーンを明示的に指定しないと、問題が発生する可能性があります。

const date = new Date('2016-07-27T07:45:00Z');

これらのいずれかにより、2016年7月25日00:00:00現地時間が表示されます。

ISO形式を使用する場合、時間とタイムゾーンではなく日付のみを指定しても、タイムゾーンはUTCとして自動的に受け入れられます。

この意味は:

const date1 = new Date('25 July 2016'); const date2 = new Date('July 25, 2016');

日付のフォーマット

幸い、最新のJavaScriptには、標準に組み込まれた便利な国際化関数がいくつかありますnew Date('25 July 2016').getTime() !== new Date('2016-07-25').getTime() new Date('2016-07-25').getTime() === new Date('2016-07-25T00:00:00Z').getTime() 日付の書式設定を簡単な操作にする名前空間。

このためには、2つのオブジェクトが必要です:IntlおよびDateは、出力設定で初期化されます。アメリカ(M / D / YYYY)形式を使用するとすると、次のようになります。

Intl.DateTimeFormat

代わりにオランダ語(D / M / YYYY)形式が必要な場合は、異なるカルチャコードをconst firstValentineOfTheDecade = new Date(2020, 1, 14); // 1 for February const enUSFormatter = new Intl.DateTimeFormat('en-US'); console.log(enUSFormatter.format(firstValentineOfTheDecade)); // 2/14/2020 に渡すだけです。コンストラクタ:

DateTimeFormat

または、月の名前が綴られた、より長い形式のアメリカ形式:

const nlBEFormatter = new Intl.DateTimeFormat('nl-BE'); console.log(nlBEFormatter.format(firstValentineOfTheDecade)); // 14/2/2020

さて、月の日に適切な序数形式、つまり「14」ではなく「14日」が必要な場合、const longEnUSFormatter = new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'long', day: 'numeric', }); console.log(longEnUSFormatter.format(firstValentineOfTheDecade)); // February 14, 2020 の唯一の有効な値は次のようになるため、残念ながらこれには少し回避策が必要です。この記事の内容はdayです。または'numeric'。借りる フラビオコープスのバージョン の MathiasBynensのコード '2-digit'の別の部分を活用するこのために、Intlを介して曜日の出力をカスタマイズできます。

formatToParts()

残念ながら、const pluralRules = new Intl.PluralRules('en-US', { type: 'ordinal' }) const suffixes = { 'one': 'st', 'two': 'nd', 'few': 'rd', 'other': 'th' } const convertToOrdinal = (number) => `${number}${suffixes[pluralRules.select(number)]}` // At this point: // convertToOrdinal('1') === '1st' // convertToOrdinal('2') === '2nd' // etc. const extractValueAndCustomizeDayOfMonth = (part) => { if (part.type === 'day') { return convertToOrdinal(part.value); } return part.value; }; console.log( longEnUSFormatter.formatToParts(firstValentineOfTheDecade) .map(extractValueAndCustomizeDayOfMonth) .join('') ); // February 14th, 2020 この記事の執筆時点では、Internet Explorer(IE)ではまったくサポートされていませんが、他のすべてのデスクトップ、モバイル、およびバックエンド(Node.js)テクノロジーはサポートされています。 サポートがあります 。 IEをサポートする必要があり、序数が絶対に必要な場合は、以下の補足(またはより適切な日付ライブラリ)が答えを提供します。

バージョン11より前のIEのような古いブラウザをサポートする必要がある場合、formatToPartsのような標準の日付フォーマット関数がなかったため、JavaScriptでの日付フォーマットはより困難です。 PythonまたはPHPで。

たとえばPHPでは、関数strftime strftime('Today is %b %d %Y %X', mktime(5,10,0,12,30,99))を提供します。

あなたは使用することができます 文字の異なる組み合わせ 前にToday is Dec 30 1999 05:10:00さまざまな形式で日付を取得します。 (注意してください。すべての言語が各文字に同じ意味を割り当てるわけではありません。特に、「M」と「m」は数分と数か月間交換される場合があります。)

使用する形式が確実な場合は、上記で説明したJavaScript関数を使用して個々のビットを抽出し、自分で文字列を作成することをお勧めします。

%

日付はMM / DD / YYYY形式で次のように取得できます。

var currentDate = new Date(); var date = currentDate.getDate(); var month = currentDate.getMonth(); var year = currentDate.getFullYear();

このソリューションの問題は、月と日が1桁である場合と、2桁である場合があるため、日付の長さが一貫しない可能性があることです。これは、たとえば、日付が整列していないためにテーブルの列に日付を表​​示している場合に問題になる可能性があります。

これに対処するには、先頭に0を追加する「パッド」機能を使用します。

var monthDateYear = (month+1) + '/' + date + '/' + year;

これで、次を使用してMM / DD / YYYY形式で正しい日付を取得できます。

function pad(n) { return n<10 ? '0'+n : n; }

代わりにDD-MM-YYYYが必要な場合、プロセスは次のようになります。

var mmddyyyy = pad(month + 1) + '/' + pad(date) + '/' + year;

アンティを上げて、日付を「月日、年」形式で印刷してみましょう。月のインデックスを名前にマッピングする必要があります。

var ddmmyyyy = pad(date) + '-' + pad(month + 1) + '-' + year;

2013年1月1日として日付を表示するのが好きな人もいます。問題ありません。必要なのはヘルパー関数var monthNames = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ]; var dateWithFullMonthName = monthNames[month] + ' ' + pad(date) + ', ' + year; だけです。これは、1の場合は1番目、12の場合は12番目、103の場合は103番目などを返し、残りは単純です。

ordinal

日付オブジェクトから曜日を簡単に判別できるので、次のように追加しましょう。

var ordinalDate = ordinal(date) + ' ' + monthNames[month] + ', ' + year;

ここでの大きなポイントは、日付から数値を抽出すると、フォーマットは主に文字列に関連するということです。

日付形式の変更

日付を解析してフォーマットする方法がわかれば、日付をあるフォーマットから別のフォーマットに変更するには、2つを組み合わせるだけです。

たとえば、2013年7月21日の形式の日付があり、形式を2013年7月21日に変更したい場合は、次のように実行できます。

var daysOfWeek = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; ordinalDateWithDayOfWeek = daysOfWeek[currentDate.getDay()] + ', ' + ordinalDate;

JavaScriptDateオブジェクトのローカリゼーション関数の使用

上で説明した日付の書式設定方法はほとんどのアプリケーションで機能するはずですが、本当に日付の書式設定をローカライズしたい場合は、const myDate = new Date('Jul 21, 2013'); const dayOfMonth = myDate.getDate(); const month = myDate.getMonth(); const year = myDate.getFullYear(); function pad(n) { return n<10 ? '0'+n : n } const ddmmyyyy = pad(dayOfMonth) + '-' + pad(month + 1) + '-' + year; // '21-07-2013' を使用することをお勧めします。オブジェクトのDate方法:

toLocaleDateString()

…const today = new Date().toLocaleDateString('en-GB', { day: 'numeric', month: 'short', year: 'numeric', }); のようなものを提供します。

ロケールを「en-US」に変更すると、代わりに「2016年7月26日」になります。フォーマットがどのように変更されたかに注意してください。ただし、表示オプションは同じままです。これは非常に便利な機能です。前のセクションで示したように、新しい26 Jul 2016ベースの手法はこれと非常によく似ていますが、フォーマッタオブジェクトを再利用できるため、オプションを1回設定するだけで済みます。

Intl.DateTimeFormatを使用すると、コンピューターで出力が正常に見える場合でも、常にフォーマットオプションを渡すことをお勧めします。これにより、月の名前が非常に長い予期しないロケールでの破損や、月の名前が短いために見苦しい場所からUIを保護できます。

代わりに1か月全体を「7月」にしたい場合は、オプションの月パラメーターを「long」に変更するだけです。 JavaScriptがすべてを処理してくれます。 en-USの場合、2016年7月26日を取得します。

注:ブラウザでユーザーのロケールを自動的に使用する場合は、最初のパラメータとして「undefined」を渡すことができます。

日付の数値バージョンを表示したいが、異なるロケールのMM / DD / YYYYとDD / MM / YYYYに煩わされたくない場合は、次の簡単な解決策をお勧めします。

toLocaleDateString()

私のコンピューターでは、これはconst today = new Date().toLocaleDateString(undefined, { day: 'numeric', month: 'numeric', year: 'numeric', }); を出力します。月と日付が2桁であることを確認する場合は、オプションを変更するだけです。

7/26/2016

これはconst today = new Date().toLocaleDateString(undefined, { day: '2-digit', month: '2-digit', year: 'numeric', }); を出力します。まさに私たちが欲しかったもの!

他のいくつかの関連関数を使用して、時刻と日付の両方の表示方法をローカライズすることもできます。

コード出力説明
07/26/2016 '4:21:38 AM' 時間のみのローカライズ版を表示
now.toLocaleTimeString() '04:21:38 AM ' 提供されたオプションに基づいてローカライズされた時間を表示する
now.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit', }); 「2016年7月22日、午前4時21分38秒」 ユーザーのロケールの日付と時刻を表示する
now.toLocaleString() 「2016年7月22日、午前4時21分」 提供されたオプションに基づいてローカライズされた日付と時刻を表示する

相対的な日付と時刻の計算

JavaScriptの日付に20日を追加する例を次に示します(つまり、既知の日付の20日後の日付を計算します)。

now.toLocaleString(undefined, { day: 'numeric', month: 'numeric', year: 'numeric', hour: '2-digit', minute: '2-digit', });

元の日付オブジェクトは、7月20日から20日後の日付を表しますconst myDate = new Date('July 20, 2016 15:00:00'); const nextDayOfMonth = myDate.getDate() + 20; myDate.setDate(nextDayOfMonth); const newDate = myDate.toLocaleString(); その日付を表すローカライズされた文字列が含まれます。私のブラウザでは、newDate 「2016年8月9日午後3時00分00秒」が含まれています。

1日よりも正確な差のある相対タイムスタンプを計算するには、newDateを使用できます。およびDate.getTime()特定のエポック(つまり、1970年1月1日)からのミリ秒数を表す整数を処理します。たとえば、今から17時間後の時刻を知りたい場合は、次のようにします。

Date.setTime()

日付の比較

日付に関連する他のすべてと同様に、日付の比較には独自の落とし穴があります。

まず、日付オブジェクトを作成する必要があります。幸いなことに、、 =すべてが機能します。したがって、2014年7月19日と2014年7月18日を比較するのは次のように簡単です。

const msSinceEpoch = (new Date()).getTime(); const seventeenHoursLater = new Date(msSinceEpoch + 17 * 60 * 60 * 1000);

同じ日付を表す2つの日付オブジェクトは2つの異なる日付オブジェクトであり、等しくないため、等しいかどうかを確認するのは難しいです。たとえば、「2014年7月20日」と「2014年7月20日」は同じ日付を表しますが、文字列の表現が異なるため、日付文字列を比較することはお勧めできません。以下のスニペットは、最初のポイントを示しています。

const date1 = new Date('July 19, 2014'); const date2 = new Date('July 28, 2014'); if(date1 > date2) { console.log('First date is more recent'); } else { console.log('Second date is more recent'); }

これにより、const date1 = new Date('June 10, 2003'); const date2 = new Date(date1); const equalOrNot = date1 == date2 ? 'equal' : 'not equal'; console.log(equalOrNot); が出力されます。

この特定のケースは、次のように日付(タイムスタンプ)に相当する整数を比較することで修正できます。

not equal

この例は多くの場所で見ましたが、通常は別の日付オブジェクトから日付オブジェクトを作成しないため、気に入らないです。ですから、この例は学術的な観点からのみ重要だと思います。また、これには、両方のDateオブジェクトがまったく同じ秒を参照している必要がありますが、同じ日、時間、または分を参照しているかどうかだけを知りたい場合があります。

より実用的な例を見てみましょう。ユーザーが入力した誕生日が、APIから取得した幸運な日付と同じであるかどうかを比較しようとしています。

date1.getTime() == date2.getTime()

両方とも同じ日付を表していますが、残念ながら、ユーザーは数百万ドルを受け取ることはできません。

問題は次のとおりです。JavaScriptは、明示的に指定されていない限り、常にブラウザが提供するタイムゾーンであると想定します。

これは、私にとって、const userEnteredString = '12/20/1989'; // MM/DD/YYYY format const dateStringFromAPI = '1989-12-20T00:00:00Z'; const dateFromUserEnteredString = new Date(userEnteredString) const dateFromAPIString = new Date(dateStringFromAPI); if (dateFromUserEnteredString.getTime() == dateFromAPIString.getTime()) { transferOneMillionDollarsToUserAccount(); } else { doNothing(); } を意味しますタイムスタンプの点で1989-12-20T00:00:00Zと同じではない日付1989-12-20T00:00:00 + 5:45または1989-12-19T18:15:00Zを作成します。

既存の日付オブジェクトのタイムゾーンだけを変更することはできないため、ターゲットは新しい日付オブジェクトを作成することですが、ローカルタイムゾーンではなくUTCを使用します。

ユーザーのタイムゾーンを無視し、日付オブジェクトの作成時にUTCを使用します。それを行うには2つの方法があります。

  1. ユーザー入力の日付からISO形式の日付文字列を作成し、それを使用してDateオブジェクトを作成します。有効なISO日付形式を使用して、UTCとローカルの意図を非常に明確にしながらDateオブジェクトを作成します。
new Date ('12/20/1989')

これは、時刻がデフォルトで深夜(00:00:00Z)になるため、時刻を指定しない場合にも機能します。

const userEnteredDate = '12/20/1989'; const parts = userEnteredDate.split('/'); const userEnteredDateISO = parts[2] + '-' + parts[0] + '-' + parts[1]; const userEnteredDateObj = new Date(userEnteredDateISO + 'T00:00:00Z'); const dateFromAPI = new Date('1989-12-20T00:00:00Z'); const result = userEnteredDateObj.getTime() == dateFromAPI.getTime(); // true

注意:日付コンストラクターにYYYY-MM-DDの正しいISO日付形式の文字列が渡されると、UTCが自動的に想定されます。

  1. JavaScriptは、日付のUTCタイムスタンプを取得するために使用できる適切なDate.UTC()関数を提供します。日付からコンポーネントを抽出し、それらを関数に渡します。
const userEnteredDate = new Date('1989-12-20'); const dateFromAPI = new Date('1989-12-20T00:00:00Z'); const result = userEnteredDate.getTime() == dateFromAPI.getTime(); // true

2つの日付の違いを見つける

遭遇する一般的なシナリオは、2つの日付の違いを見つけることです。

2つのユースケースについて説明します。

2つの日付の間の日数を見つける

両方の日付をUTCタイムスタンプに変換し、ミリ秒単位で差を見つけ、同等の日を見つけます。

const userEnteredDate = new Date('12/20/1989'); const userEnteredDateTimeStamp = Date.UTC(userEnteredDate.getFullYear(), userEnteredDate.getMonth(), userEnteredDate.getDate(), 0, 0, 0); const dateFromAPI = new Date('1989-12-20T00:00:00Z'); const result = userEnteredDateTimeStamp == dateFromAPI.getTime(); // true ...

生年月日からユーザーの年齢を見つける

const dateFromAPI = '2016-02-10T00:00:00Z'; const now = new Date(); const datefromAPITimeStamp = (new Date(dateFromAPI)).getTime(); const nowTimeStamp = now.getTime(); const microSecondsDiff = Math.abs(datefromAPITimeStamp - nowTimeStamp); // Math.round is used instead of Math.floor to account for certain DST cases // Number of milliseconds per day = // 24 hrs/day * 60 minutes/hour * 60 seconds/minute * 1000 ms/second const daysDiff = Math.round(microSecondsDiff / (1000 * 60 * 60 * 24)); console.log(daysDiff);

注:非標準の形式があります。 APIドキュメントを読んで、これが10月12日を意味するのか12月10日を意味するのかを判断します。それに応じてISO形式に変更します。

const birthDateFromAPI = '12/10/1989';

このコードを書くにはもっと簡潔な方法があることを私は知っていますが、ロジックが非常に明確であるため、この方法で書くのが好きです。

日付地獄を避けるための提案

日付の計算に慣れてきたので、従うべきベストプラクティスとそれに従う理由を理解することができます。

ユーザーからDateTimeを取得する

ユーザーから日付と時刻を取得している場合は、おそらくローカルのDateTimeを探しています。日付演算のセクションで、const parts = birthDateFromAPI.split('/'); const birthDateISO = parts[2] + '-' + parts[0] + '-' + parts[1]; const birthDate = new Date(birthDateISO); const today = new Date(); let age = today.getFullYear() - birthDate.getFullYear(); if(today.getMonth() がコンストラクターは、さまざまな方法で日付を受け入れることができます。

混乱を避けるために、Dateを使用して日付を作成することを常にお勧めします有効な解析可能な形式の日付がすでにある場合でも、形式を設定します。チーム内のすべてのプログラマーがこの単純なルールに従うと、new Date(year, month, day, hours, minutes, seconds, milliseconds)を使用できる限り明示的であるため、コードを長期的に維持するのは非常に簡単になります。コンストラクタ。

クールな部分は、最後の4つのパラメーターがゼロの場合にそれらのパラメーターを省略できるバリエーションを使用できることです。つまり、Date new Date(2012, 10, 12)と同じです指定されていないパラメータはデフォルトでゼロになるためです。

たとえば、日付2012-10-12と時刻12:30を提供する日付と時刻のピッカーを使用している場合、次のようにパーツを抽出して新しいDateオブジェクトを作成できます。

Cコーディングを学ぶ方法
new Date(2012, 10, 12, 0, 0, 0, 0)

ISO日付形式でない限り、文字列から日付を作成しないようにしてください。代わりに、Date(年、月、日付、時間、分、秒、マイクロ秒)メソッドを使用してください。

日付のみを取得する

日付(たとえば、ユーザーの生年月日)のみを取得する場合は、形式を有効なISO日付形式に変換して、UTCに変換したときに日付が前後にシフトする可能性のあるタイムゾーン情報を削除することをお勧めします。例えば:

const dateFromPicker = '2012-10-12'; const timeFromPicker = '12:30'; const dateParts = dateFromPicker.split('-'); const timeParts = timeFromPicker.split(':'); const localDate = new Date(dateParts[0], dateParts[1]-1, dateParts[2], timeParts[0], timeParts[1]);

忘れた場合、const dateFromPicker = '12/20/2012'; const dateParts = dateFromPicker.split('/'); const ISODate = dateParts[2] + '-' + dateParts[0] + '-' + dateParts[1]; const birthDate = new Date(ISODate).toISOString(); を作成すると有効なISO日付形式(YYYY-MM-DD)で入力されたオブジェクトの場合、ブラウザのタイムゾーンではなく、デフォルトでUTCになります。

日付の保存

DateTimeは常にUTCで保存してください。常にISO日付文字列またはタイムスタンプをバックエンドに送信します。

何世代にもわたるコンピュータープログラマーは、ユーザーに正しい現地時間を見せようとする苦い経験の後で、この単純な真実に気づきました。バックエンドに現地時間を保存することは悪い考えです。フロントエンドで現地時間への変換をブラウザに処理させることをお勧めします。

また、「1989年7月20日12:10 PM」のようなDateTime文字列をバックエンドに送信してはならないことは明らかです。タイムゾーンも送信する場合でも、他のプログラマーが自分の意図を理解し、日付を正しく解析して保存するための労力が増えています。

Dateを使用しますまたはtoISOString()ローカルのDateTimeをUTCに変換するDateオブジェクトのメソッド。

toJSON()

日付と時刻の表示

  1. RESTAPIからタイムスタンプまたはISO形式の日付を取得します。
  2. const dateFromUI = '12-13-2012'; const timeFromUI = '10:20'; const dateParts = dateFromUI.split('-'); const timeParts = timeFromUI.split(':'); const date = new Date(dateParts[2], dateParts[0]-1, dateParts[1], timeParts[0], timeParts[1]); const dateISO = date.toISOString(); $.post('http://example.com/', {date: dateISO}, ...) を作成しますオブジェクト。
  3. Dateを使用しますまたはtoLocaleString()およびtoLocaleDateString()現地時間を表示するメソッドまたは日付ライブラリ。
toLocaleTimeString()

いつ現地時間を保存する必要がありますか?

「時々それは タイムゾーンを知ることは重要です イベントが発生し、単一のタイムゾーンに変換すると、その情報が取り返しのつかないほど消去されます。

「マーケティングプロモーションを行っていて、ランチタイムにどの顧客が注文したかを知りたい場合、GMT正午に行われたように見える注文は、実際にニューヨークで朝食をとって行われたときはあまり役に立ちません。」

このような状況に遭遇した場合は、現地時間も節約する方が賢明です。いつものように、ISO形式で日付を作成したいのですが、最初にタイムゾーンオフセットを見つける必要があります。

Dateオブジェクトのconst dateFromAPI = '2016-01-02T12:30:00Z'; const localDate = new Date(dateFromAPI); const localDateString = localDate.toLocaleDateString(undefined, { day: 'numeric', month: 'short', year: 'numeric', }); const localTimeString = localDate.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit', }); 関数は、特定の現地時間に追加されたときに同等のUTC時間を与える分数を示します。タイムゾーンオフセットであることがより明確になるため、(+-)hh:mm形式に変換することをお勧めします。

getTimeZoneOffset()

私のタイムゾーン+05:45の場合、-345が返されます。これは反対の符号であるだけでなく、-345のような数値はバックエンド開発者にとって完全に当惑する可能性があります。したがって、これを+05:45に変換します。

const now = new Date(); const tz = now.gettime zoneOffset();

次に、残りの値を取得し、ローカルのDateTimeを表す有効なISO文字列を作成します。

const sign = tz > 0 ? '-' : '+'; const hours = pad(Math.floor(Math.abs(tz)/60)); const minutes = pad(Math.abs(tz)%60); const tzOffset = sign + hours + ':' + minutes;

必要に応じて、UTCとローカルの日付をオブジェクトでラップできます。

const localDateTime = now.getFullYear() + '-' + pad(now.getMonth()+1) + '-' + pad(now.getDate()) + 'T' + pad(now.getHours()) + ':' + pad(now.getMinutes()) + ':' + pad(now.getSeconds());

これで、バックエンドで、イベントが現地時間の正午より前に発生したかどうかを確認したい場合は、日付を解析してconst eventDate = { utc: now.toISOString(), local: localDateTime, tzOffset: tzOffset, } を使用できます。関数。

getHours()

const localDateString = eventDate.local; const localDate = new Date(localDateString); if(localDate.getHours() <12) { console.log('Event happened before noon local time'); } は使用しませんでしたここにありますが、将来デバッグの目的で必要になる可能性があるため、引き続き保存します。実際には、タイムゾーンオフセットとUTC時間のみを送信できます。ただし、最終的にはデータベースに日付を保存する必要があり、現地時間を個別に保存すると、計算を実行して現地日付を取得するのではなく、フィールドに基づいて直接クエリを実行できるため、現地時間も保存するのが好きです。

ローカルタイムゾーンが保存されている場合でも、特定のタイムゾーンの日付を表示したい場合があります。たとえば、イベントの時間は、仮想の場合は現在のユーザーのタイムゾーンで、そうでない場合は物理的に発生するタイムゾーンでより意味がある場合があります。いずれにせよ、事前に確認する価値があります 確立されたソリューション 明示的なタイムゾーン名でフォーマットする場合。

サーバーとデータベースの構成

UTCタイムゾーンを使用するようにサーバーとデータベースを常に構成します。 (UTCとGMTは 同じことではない -たとえば、GMTは夏の間にBSTに切り替えることを意味する場合がありますが、UTCは決してそうしません。)

特に意図しない場合に、タイムゾーンの変換がどれほど苦痛になるかはすでに見てきました。常にUTCDateTimeを送信し、サーバーをUTCタイムゾーンに設定すると、作業が楽になります。バックエンドコードは、タイムゾーンの変換を行う必要がないため、はるかにシンプルでクリーンになります。世界中のサーバーから受信するDateTimeデータは、簡単に比較およびソートできます。

バックエンドのコードは、サーバーのタイムゾーンがUTCであると想定できる必要があります(ただし、確実にチェックする必要があります)。単純な構成チェックにより、新しいDateTimeコードが書き込まれるたびに、変換について考えたりコードを記述したりする必要がなくなります。

日付処理を改善する時が来ました

日付操作は難しい問題です。この記事の実際の例の背後にある概念はJavaScriptを超えて適用され、DateTimeデータと計算を適切に処理することに関してはほんの始まりにすぎません。さらに、すべてのヘルパーライブラリには付属しています 独自のセット ニュアンスの。

つまり、バックエンドでISOを使用し、フロントエンドをそのままにして、ユーザーが適切にフォーマットできるようにします。プロのプログラマーはいくつかの微妙な違いを認識し、バックエンドとフロントエンドの両方で十分にサポートされているDateTimeライブラリーを(さらに明確に)使用します。データベース側の組み込み関数は別の話ですが、この記事がそのコンテキストでも賢明な決定を下すのに十分な背景を提供することを願っています。

関連: バギーJavaScriptコード:JavaScript開発者が犯す最も一般的な10の間違い

ビッグデータ:医薬品のR&D窮状の処方箋

革新

ビッグデータ:医薬品のR&D窮状の処方箋
バックエンドアーキテクト

バックエンドアーキテクト

その他

人気の投稿
ApeeScapeは、世界中の開発者の上位3%を提供し、企業がエリート技術人材の不足に対処できるよう支援します
ApeeScapeは、世界中の開発者の上位3%を提供し、企業がエリート技術人材の不足に対処できるよう支援します
リモートブランド戦略ワークショップ:究極のステップバイステップガイド
リモートブランド戦略ワークショップ:究極のステップバイステップガイド
宣言型プログラミングは本当に存在しますか?
宣言型プログラミングは本当に存在しますか?
Facebookを再設計しましょう:あなたが始めるのを刺激し、助けるための10の例
Facebookを再設計しましょう:あなたが始めるのを刺激し、助けるための10の例
タッチの力–ボタンデザインの進化(インフォグラフィック付き)
タッチの力–ボタンデザインの進化(インフォグラフィック付き)
 
暗号を超えて:ブロックチェーンアプリケーションがエンタープライズソリューションを提供
暗号を超えて:ブロックチェーンアプリケーションがエンタープライズソリューションを提供
設計作業の提示:正しい方法
設計作業の提示:正しい方法
Salesforceバックエンドエンジニア
Salesforceバックエンドエンジニア
プレゼンテーションデザインとビジュアルストーリーテリングの芸術
プレゼンテーションデザインとビジュアルストーリーテリングの芸術
VR / ARデザインへの飛躍
VR / ARデザインへの飛躍
人気の投稿
  • C +を学ぶ方法
  • ソフトウェア技術設計ドキュメントテンプレート
  • ファンドオブファンズの不動産ファンド
  • 新しいプログラミング言語を作成する
  • scorpとccorpとは
  • マイクロソフト紺碧の機械学習チュートリアル
カテゴリー
データサイエンスとデータベース トレンド Uiデザイン プロセスとツール デザイナーライフ 人とチーム 財務プロセス Kpiと分析 収益と成長 プロジェクト管理

© 2021 | 全著作権所有

apeescape2.com