Sailfish OSの開発:日付とタイムゾーンを操作する機能

こんにちは この記事は、Sailfish OSモバイルプラットフォーム向けのアプリケーション開発に関する一連の記事の続きです。 今回は、QMLで日付とタイムゾーンを操作する機能について説明します。 問題自体の説明から記事を開始し、次にそれを解決する方法に進みます。



問題の説明



Sailfish OSアプリケーションを開発する場合、多くの場合、何らかの形式で日付と時刻を操作する必要があります(ただし、他のプラットフォーム用に開発する場合)。 Sailfish OSアプリケーションは、 DatePickerDialogTimePickerDialogなどのコンポーネントを使用して日付と時刻を指定します。 内部的には、日付と時刻を制御するために、標準のJavaScript Dateオブジェクトから継承されたDate QMLオブジェクトを使用します。これは、UTCまたはローカル以外のタイムゾーンで日付と時刻を作成する機能をサポートしません。 Dateオブジェクトには、このためのコンストラクターとメソッドがありません。



new Date(); new Date(value); new Date(dateString); new Date(year, month[, day[, hour[, minute[, second[, millisecond]]]]]);
      
      





UTCからの日付、時刻、オフセットを含む文字列を渡すと、リストの3番目のコンストラクタが役立つはずです。 オブジェクトのタイムゾーンは依然としてローカルであり、オフセットで示されるタイムゾーンではありません。



 new Date('Jan 30 2017 10:00:00 GMT+0700') // Jan 30 2017 06:00:00 GMT+0300
      
      





「タイムゾーンを使用する理由は何ですか?」 UTCの時間でできないのはなぜですか?」と答えます:はい、タイムゾーンが意味をなさない場合があります。 日付と時刻のみを使用すれば十分です。 たとえば、勤務時間が9:00に始まる場合、カムチャッカの同僚が18:00に働くことを期待することはほとんどありません。 ただし、異なるタイムゾーンで同時に発生する定期的なイベントの場合は、タイムゾーンが依然として必要です。 たとえば、プロジェクトの進行中の作業に関する毎日の議論は、カムチャツカの同僚の場合は10:00から、同僚の場合は19:00から始まります。



タイムゾーンを設定して日付と時刻を作成する問題の解決策の1つは、サードパーティライブラリのいずれかを使用することでした: timezone-jsおよびmoment.js 。 しかし、 DatePickerDialogTimePickerDialogはこれらのライブラリについて何も知らないため、不適切であることが判明しましたが、内部では標準のDateを積極的に使用しています。これはtimezone-jsおよびmoment.jsを使用して作成されたオブジェクトと互換性がありません その結果、他の2つのソリューションが開発されました。



ソリューションNo. 1



思いついた最初の決定は、日付と時刻を制御する独自のJavaScriptオブジェクトを作成することでした。 そのようなオブジェクトは、日付、時刻、およびタイムゾーン情報の保存を許可する必要があり、最も重要なことは、タイムゾーンに影響を与えることなく、Sailfish OSコンポーネントDatePickerDialogおよびTimePickerDialogを使用して日付と時刻を変更することです。



独自のJavaScriptオブジェクトを作成するには、別個のJavaScriptファイルでコンストラクター関数を定義する必要があります。



 // CustomDateTime.js function CustomDateTime(dateTimeString) { this.dateTime = Date.fromLocaleString(Qt.locale(), dateTimeString.substring(0, dateTimeString.length - 6), "yyyy-MM-ddTHH:mm:ss"); this.utcOffset = dateTimeString.substring(dateTimeString.length - 6); }
      
      





コンストラクター関数は、「yyyy-MM-ddTHH:mm:ssZ」という形式の文字列を受け入れます。Zは、「[+-] HH:mm」という標準ISO 8601形式のUTCに対するオフセットです。Dateオブジェクトは、文字列の一部から作成され、 dateTimeプロパティに割り当てられます。 このプロパティには、タイムゾーンを除く日付と時刻に関する情報が含まれます。 UTCからのオフセットを含む残りの行は、別のutcOffsetプロパティに保存されます。 これで、日付、時刻、タイムゾーンに関する情報を含むオブジェクトを作成できます。



 var myDateTime = new CustomDateTime("2016-12-22T13:40:00+05:00"); print(myDateTime.dateTime); // Dec 22 2016 13:40:00 GMT+03:00 print(myDateTime.utcOffset); // "+05:00" myDateTime.dateTime = new Date(2016, 11, 23, 13, 00, 00); print(myDateTime.dateTime); // Dec 23 2016 13:00:00 GMT+03:00 print(myDateTime.utcOffset); // "+05:00"
      
      





日付と時刻を同じ形式「yyyy-MM-ddTHH:mm:ssZ」で返すオブジェクトにメソッドを追加します。



 // CustomDateTime.js CustomDateTime.prototype.toISO8601String = function() { return this.dateTime.toLocaleString(Qt.locale(), "yyyy-MM-ddTHH:mm:ss").concat(this.utcOffset); }
      
      





多くの場合、日付と時刻を扱うアプリケーションでは、対応する値を表示する必要があります。 開発者として、すべてのユーザーが現在のロケールに従って日付と時刻が正しく表示されるようにする必要があります。 これを行うために、日付と時刻の言語依存表現で文字列を返すJavaScriptオブジェクトメソッドに追加します。



 // CustomDateTime.js CustomDateTime.prototype.toLocaleDateString = function() { return Qt.formatDate(this.dateTime, Qt.SystemLocaleShortDate); } CustomDateTime.prototype.toLocaleTimeString = function() { return Qt.formatTime(this.dateTime, "HH:mm"); } CustomDateTime.prototype.toLocaleDateTimeString = function() { return this.toLocaleDateString() + " " + this.toLocaleTimeString(); }
      
      





したがって、特定の形式の文字列を使用して作成され、同じ形式の文字列と現在のロケールの形式設定された文字列を返すことができる、日付、時刻、およびタイムゾーンに関する情報を保存および編集できるオブジェクトがあります。 このようなオブジェクトを使用すると、必要なタイムゾーンで日付と時刻を簡単に操作できます。



CustomDateTimeオブジェクトの使用例を考えてみましょう。



 //... import "../model/CustomDateTime.js" as CustomDateTime Page { property var ustomDateTime: new CustomDateTime.CustomDateTime("2017-01-15T13:45:00+05:00") SilicaFlickable { anchors.fill: parent contentHeight: column.height Column { id: column //... ValueButton { label: qsTr("Date").concat(":") value: ustomDateTime.toLocaleDateString() //... } ValueButton { width: parent.width label: qsTr("Time").concat(":") value: ustomDateTime.toLocaleTimeString() onClicked: { var dialog = pageStack.push("Sailfish.Silica.TimePickerDialog", { hour: ustomDateTime.dateTime.getHours(), minute: ustomDateTime.dateTime.getMinutes()}); dialog.accepted.connect(function() { ustomDateTime.dateTime = new Date(ustomDateTime.dateTime.getFullYear(), ustomDateTime.dateTime.getMonth(), ustomDateTime t.dateTime.getDate(), dialog.hour, dialog.minute); }); } } } } }
      
      





この例には、日付と時刻を編集するためのValueButtonコンポーネントが含まれています。 1つのコンポーネントをクリックすると、2番目のTimePickerDialogをクリックしてDatePickerDialogが開きます。 時間を編集するためのValueButtonコンポーネントについて詳しく説明します。 CustomDateTimeオブジェクトはPageコンポーネントのプロパティとして作成され、 valueプロパティを使用してValueButtonに日付と時刻を表示するために使用されます。また、 onClickedイベントハンドラで説明されているように、 DatePickerDialogおよびTimePickerDialogに値を渡します。 DatePickerDialogおよびTimePickerDialogからデータを取得し、 CustomDateTimeオブジェクトのdateTimeプロパティを更新する方法について説明しています。



そのため、日付、時刻、タイムゾーンに関する情報を保存できるCustomDateTime JavaScriptオブジェクトが作成され、 DatePickerDialogTimePickerDialogを使用して日付と時刻を編集することもできます。



このソリューションの欠点は、JavaScriptオブジェクトがプロパティバインディングをサポートしないことです。 この例では、日付または時刻を変更( CustomDateTimeオブジェクトのdateTimeプロパティを変更)した後、 ValueButtonオブジェクトのvalueプロパティは更新されません。 視覚的には、 CustomDateTimeオブジェクトが実際に変更されているもかかわらず、画面に変更は発生しません。 これは、 CustomDateTimeオブジェクトのdateTimeプロパティをValueButtonオブジェクトのvalueプロパティに関連付けることができないためです。



プロパティのバインドが重要でない場合は、上記のソリューションを使用できますが、他の場合は、ソリューション番号2を参照する必要があります。



決定番号2



2番目の解決策は、独自のQMLコンポーネント、特にQtObject型のコンポーネントを作成することですQtObjectは最も「軽量」な標準QMLタイプであり、視覚的なコンポーネントがなく、モデルオブジェクトを作成するときに役立ちます。 最も重要なことは、QMLコンポーネントがプロパティバインディングをサポートしていることです。 QMLコンポーネントで上記で定義したJavaScriptオブジェクトを書き換えます。



 // CustomDateTime.qml import QtQuick 2.0 QtObject { property string dateTimeStringToSet property date dateTime: Date.fromLocaleString(Qt.locale(), dateTimeStringToSet.substring(0, dateTimeStringToSet.length - 6), "yyyy-MM-ddTHH:mm:ss") property string utcOffset: dateTimeStringToSet.substring(dateTimeStringToSet.length - 6) property string localeDateString: Qt.formatDate(dateTime, Qt.SystemLocaleShortDate) property string localeTimeString: Qt.formatTime(dateTime, "HH:mm") property string localeDateTimeString: localeDateString.concat(" ").concat(localeTimeString) property string iso8601String: dateTime.toLocaleString(Qt.locale(), "yyyy-MM-ddTHH:mm:ss") .concat(utcOffset) }
      
      





コードがより簡潔になり、JavaScriptオブジェクトのコンストラクター関数とメソッドがQtObject内のプロパティに置き換えられました 。 ここで、新しいオブジェクトを作成するには、標準のQML構文を使用してdateTimeStringToSetプロパティを1つだけ定義する必要があります。他のすべてのプロパティは自動的に計算されます。 プロパティバインディングが機能します。



 CustomDateTime { dateTimeStringToSet: "2017-01-15T13:45:00+05:00" }
      
      





CustomMLateTime QMLオブジェクトを使用して、上記の例を書き換えます。



 //... Page { CustomDateTime { id: customDateTime dateTimeStringToSet: "2017-01-15T13:45:00+05:00" } SilicaFlickable { anchors.fill: parent contentHeight: column.height Column { id: column //... ValueButton { label: qsTr("Date").concat(":") value: customDateTime.localeDateString //... } ValueButton { width: parent.width label: qsTr("Time").concat(":") value: customDateTime.localeTimeString onClicked: { var dialog = pageStack.push("Sailfish.Silica.TimePickerDialog", { hour: customDateTime.dateTime.getHours(), minute: customDateTime.dateTime.getMinutes()}); dialog.accepted.connect(function() { customDateTime.dateTime = new Date(customDateTime.dateTime.getFullYear(), customDateTime.dateTime.getMonth(), customDateTime.dateTime.getDate(), dialog.hour, dialog.minute); }); } } } } }
      
      





それほど多くの変更がないことは簡単にわかります。 プロパティ宣言はCustomMLateTime QMLコンポーネントの宣言に置き換えられ、 toLocaleDateString()およびtoLocaleTimeString() 関数の代わりにlocaleDateStringおよびlocaleTimeStringプロパティが使用されます 。 他のすべての点では、コードはまったく変更されていませんが、プロパティバインディングは機能します。 CustomDateTimeオブジェクトのdateTimeプロパティを変更すると、すべてのオブジェクトプロパティ、特にlocaleTimeStringプロパティが更新され、 ValueButtonオブジェクトの外観が更新されます。



おわりに



その結果、Sailfish OSで日付と時刻を編集するコンポーネントによってサポートされる、日付、時刻、およびタイムゾーン情報を管理するためのソリューションが開発されました。 解決策は、独自のQMLコンポーネントを作成し、モデルとして使用することです。 このようなオブジェクトを使用すると、日付、時間、およびタイムゾーンを保存できます。また、プロパティバインドメカニズムをサポートし、Sailfish OSのDatePickerDialogおよびTimePickerDailogコンポーネント内で使用して編集できます。 この例のソースコードはGitHubで入手できます



著者:イヴァン・シトフ



All Articles