コントロールの使用 > CollectionView > CollectionViewの使用 > DateTime処理 |
このトピックでは、FlexGridとAjax連結またはAjax編集を使用する場合に、サーバーとクライアントの両方でUTC形式のDateTimeプロパティを維持する方法を示します。それには、まずクライアント側とサーバー側でDateTime値がどのように処理されるかを理解する必要があります。
サーバー側では、DateTimeクラスを使用するたびに、Kindプロパティを指定する必要があります。このプロパティは、そのインスタンスで表される時刻がローカル時間か、協定世界時(UTC)か、またはそのどちらでもないかを示します。一方、DateTimeオブジェクトをクライアント側で使用する場合は、日付がNumberからDateオブジェクトに解析されるときに、ブラウザによってすべての日付が暗黙にローカル時間に変換されます。
たとえば、サーバー側でnew DateTime(2017, 0, 25, 7, 0, 0, DateTimeKind.Utc);のようにDateTimeインスタンスを作成したとします。この値をサーバーからクライアントに転送すると、異なるTimeZoneシステム設定を使用するさまざまなマシンのブラウザごとに、異なる文字列表現が表示されます。
UTC形式の時刻を維持するには、クライアントとサーバーの両方で日付に明示的な変換を適用する必要があります。
サーバーでは、すべてのDateTimeオブジェクトをUnspecifiedに変換し、必要に応じてCREATE、UPDATE、またはDELETE操作を使用してこれを元に戻します。次の2つの手順を実装する必要があります。
この変換を理解するために、Utc、Local、Unspecifiedなどの形式のDateTimeフィールドを含むFlexGridコントロールを例にして、このグリッドをデータ値と連結します。
DatesData.cs
)。新しいモデルを追加する方法の詳細については、「コントロールの追加」を参照してください。DatesData.cs |
コードのコピー
|
---|---|
using System; using System.Collections.Generic; using System.Linq; namespace DateTimeFields.Models { public class DatesData { /// 主キー。 public int Id { get; set; } /// KindがUtcのDateTimeフィールド。 public DateTime UtcDateTime { get; set; } /// KindがUnspecifiedのDateTimeフィールド。 public DateTime UnspecifiedDateTime { get; set; } /// KindがLocalのDateTimeフィールド。 public DateTime LocalDateTime { get; set; } /// データを取得します。 /// <param name="total"></param> /// <returns></returns> public static IEnumerable<DatesData> GetData(int total) { var rand = new Random(0); var dt = DateTime.Now; var list = Enumerable.Range(0, total).Select(i => { return new DatesData { Id = i + 1, UtcDateTime = new DateTime(dt.Year, i % 12 + 1, 25, 7, 0, 0, DateTimeKind.Utc), UnspecifiedDateTime = new DateTime(dt.Year, i % 12 + 1, 25, 7, 0, 0, DateTimeKind.Unspecified), LocalDateTime = new DateTime(dt.Year, i % 12 + 1, 25, 7, 0, 0, DateTimeKind.Local) }; }); return list; } } } |
コード内 - HomeController.cs
C# |
コードのコピー
|
---|---|
using C1.Web.Mvc; using C1.Web.Mvc.Serialization; using <ApplicationName>.Models; using System; using System.Collections.Generic; using System.Linq; using System.Web.Mvc; namespace DateTimeFields.Controllers { public class HomeController : Controller { public ActionResult Index() { return View(); } private static List<DatesData> convertedData = DatesData.GetData(3).ToList(); private static List<DatesData> ConvertToUnspecifiedData(IEnumerable<DatesData> sourceData) { return sourceData.Select(item => new DatesData { Id = item.Id, UnspecifiedDateTime = item.UnspecifiedDateTime, UtcDateTime = new DateTime(item.UtcDateTime.Ticks), LocalDateTime = new DateTime(item.LocalDateTime.Ticks) }).ToList(); } private static void ConvertUpspecifiedBack(CollectionViewEditRequest<DatesData> requestData) { // UnspecifiedのDateTimeを元に戻します。 foreach (var item in requestData.OperatingItems) { item.LocalDateTime = new DateTime(item.LocalDateTime.Ticks, DateTimeKind.Local); item.UtcDateTime = new DateTime(item.UtcDateTime.Ticks, DateTimeKind.Utc); } } public ActionResult Converted_ReadDatesData([C1JsonRequest] CollectionViewRequest<DatesData> requestData) { return this.C1Json(CollectionViewHelper.Read(requestData, ConvertToUnspecifiedData(convertedData))); } public ActionResult Converted_UpdateDatesData([C1JsonRequest]CollectionViewEditRequest<DatesData> requestData) { ConvertUpspecifiedBack(requestData); return Update(requestData, convertedData, ConvertToUnspecifiedData); } public ActionResult Converted_CreateDatesData([C1JsonRequest]CollectionViewEditRequest<DatesData> requestData) { ConvertUpspecifiedBack(requestData); return Create(requestData, convertedData, ConvertToUnspecifiedData); } public ActionResult Converted_DeleteDatesData([C1JsonRequest]CollectionViewEditRequest<DatesData> requestData) { ConvertUpspecifiedBack(requestData); return Delete(requestData, convertedData, ConvertToUnspecifiedData); } public ActionResult Update(CollectionViewEditRequest<DatesData> requestData, List<DatesData> sourceData, Func<IEnumerable<DatesData>, List<DatesData>> converter = null) { return this.C1Json(CollectionViewHelper.Edit(requestData, item => { var error = string.Empty; var success = true; try { var index = sourceData.FindIndex(u => u.Id == item.Id); sourceData.RemoveAt(index); sourceData.Insert(index, item); } catch (Exception e) { error = e.Message; success = false; } return new CollectionViewItemResult<DatesData> { Error = error, Success = success, Data = item }; }, () => converter != null ? converter(sourceData) : sourceData)); } public ActionResult Create(CollectionViewEditRequest<DatesData> requestData, List<DatesData> sourceData, Func<IEnumerable<DatesData>, List<DatesData>> converter = null) { return this.C1Json(CollectionViewHelper.Edit(requestData, item => { var error = string.Empty; var success = true; try { sourceData.Add(item); item.Id = sourceData.Max(u => u.Id) + 1; } catch (Exception e) { error = e.Message; success = false; } return new CollectionViewItemResult<DatesData> { Error = error, Success = success, Data = item }; }, () => converter != null ? converter(sourceData) : sourceData)); } public ActionResult Delete(CollectionViewEditRequest<DatesData> requestData, List<DatesData> sourceData, Func<IEnumerable<DatesData>, List<DatesData>> converter = null) { return this.C1Json(CollectionViewHelper.Edit(requestData, item => { var error = string.Empty; var success = true; try { var index = sourceData.FindIndex(u => u.Id == item.Id); sourceData.RemoveAt(index); } catch (Exception e) { error = e.Message; success = false; } return new CollectionViewItemResult<DatesData> { Error = error, Success = success, Data = item }; }, () => converter != null ? converter(sourceData) : sourceData)); } } } |
コード内 - Index.cshtml
DatesData.cs |
コードのコピー
|
---|---|
@(Html.C1().FlexGrid() .Id("convertedGrid") .AllowAddNew(true) .AllowDelete(true) .AutoGenerateColumns(false) .Bind(cvb => cvb.Bind(Url.Action("Converted_ReadDatesData")) .Create(Url.Action("Converted_CreateDatesData")) .Update(Url.Action("Converted_UpdateDatesData")) .Delete(Url.Action("Converted_DeleteDatesData"))) .Columns(columns => { columns.Add(column => column.Binding("Id").IsReadOnly(true).Visible(false)); columns.Add(column => column.Binding("UtcDateTime").Format("dd/MM/yyyy HH:mm:ss").Width("*")); columns.Add(column => column.Binding("LocalDateTime").Format("dd/MM/yyyy HH:mm:ss").Width("*")); columns.Add(column => column.Binding("UnspecifiedDateTime").Format("dd/MM/yyyy HH:mm:ss").Width("*")); }) .Filterable(f => f.DefaultFilterType(FilterType.Both))) |
この変換を理解するために、Utc、Local、Unspecifiedなどの形式のDateTimeフィールドを含むFlexGridコントロールを例にして、このグリッドをデータ値と連結します。
コード内 - HomeController.cs
C# |
コードのコピー
|
---|---|
using C1.Web.Mvc; using C1.Web.Mvc.Serialization; using <ApplicationName>.Models; using System; using System.Collections.Generic; using System.Linq; using System.Web.Mvc; namespace DateTimeFields.Controllers { public class HomeController: Controller { public ActionResult Index() { return View(); } private static List <DatesData> customData = DatesData.GetData(3).ToList(); public ActionResult Custom_ReadDatesData([C1JsonRequest] CollectionViewRequest <DatesData> requestData) { return this.C1Json(CollectionViewHelper.Read(requestData, customData)); } public ActionResult Custom_UpdateDatesData([C1JsonRequest] CollectionViewEditRequest <DatesData> requestData) { return Update(requestData, customData); } public ActionResult Custom_CreateDatesData([C1JsonRequest] CollectionViewEditRequest <DatesData> requestData) { return Create(requestData, customData); } public ActionResult Custom_DeleteDatesData([C1JsonRequest] CollectionViewEditRequest <DatesData> requestData) { return Delete(requestData, customData); } public ActionResult Update(CollectionViewEditRequest <DatesData> requestData, List <DatesData> sourceData, Func <IEnumerable <DatesData> , List <DatesData>> converter = null) { return this.C1Json(CollectionViewHelper.Edit(requestData, item => { var error = string.Empty; var success = true; try { var index = sourceData.FindIndex(u => u.Id == item.Id); sourceData.RemoveAt(index); sourceData.Insert(index, item); } catch (Exception e) { error = e.Message; success = false; } return new CollectionViewItemResult <DatesData> { Error = error, Success = success, Data = item }; }, () => converter != null ? converter(sourceData) : sourceData)); } public ActionResult Create(CollectionViewEditRequest <DatesData> requestData, List <DatesData> sourceData, Func <IEnumerable <DatesData> , List <DatesData>> converter = null) { return this.C1Json(CollectionViewHelper.Edit(requestData, item => { var error = string.Empty; var success = true; try { sourceData.Add(item); item.Id = sourceData.Max(u => u.Id) + 1; } catch (Exception e) { error = e.Message; success = false; } return new CollectionViewItemResult <DatesData> { Error = error, Success = success, Data = item }; }, () => converter != null ? converter(sourceData) : sourceData)); } public ActionResult Delete(CollectionViewEditRequest <DatesData> requestData, List <DatesData> sourceData, Func <IEnumerable <DatesData> , List <DatesData>> converter = null) { return this.C1Json(CollectionViewHelper.Edit(requestData, item => { var error = string.Empty; var success = true; try { var index = sourceData.FindIndex(u => u.Id == item.Id); sourceData.RemoveAt(index); } catch (Exception e) { error = e.Message; success = false; } return new CollectionViewItemResult <DatesData> { Error = error, Success = success, Data = item }; }, () => converter != null ? converter(sourceData) : sourceData)); } } } |
responseTextParsing関数とrequestDataStringfying関数を定義するJavaScriptファイル(例:app.js)を追加する必要があります。
app.js |
コードのコピー
|
---|---|
// DateTimeテキストの判別に使用されるRegExpオブジェクト。 var dateJsonRegx = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d*)?(Z|[\+\-]\d{2}:\d{2}|)$/; function reponseTextParsing(sender, args) { var dateText = args.value; // これが有効なDateTimeテキストかどうかをチェックします。 var matched = dateJsonRegx.exec(dateText); if (!matched) { return; } var timeZoneText = matched[2]; var dateKind = getDateKind(timeZoneText); // UtcまたはLocal形式のDateオブジェクトの解析のみをカスタマイズします。 if (dateKind == c1.mvc.DateKind.Unspecified) { return; } if (typeof dateText === 'string' && matched) { var index = dateText.indexOf(timeZoneText); // タイムゾーンのテキストを削除し、Dateオブジェクトを作成します。 var date = new Date(dateText.substr(0, index)); // 解析されたDateオブジェクトのdateKindを忘れずに設定します。 // これがOnClientRequestDataStringifyingで使用されます。 date.dateKind = dateKind; args.result = date; args.cancel = true; } } function getDateKind(timeZoneText) { if (!timeZoneText) { return c1.mvc.DateKind.Unspecified; } if (timeZoneText.toLowerCase() === 'z') { return c1.mvc.DateKind.Utc; } return c1.mvc.DateKind.Local; } function requestDataStringifying(sender, args) { if (args.value instanceof Date || args.parent[args.key] instanceof Date) { var date = args.value instanceof Date ? args.value : args.parent[args.key]; // Utc形式のDateオブジェクトのシリアライズのみをカスタマイズします。 if (!date.dateKind || date.dateKind == c1.mvc.DateKind.Unspecified) { return; } args.result = c1.mvc.Utils.formatNumber(date.getFullYear(), 4) + '-' + c1.mvc.Utils.formatNumber(date.getMonth() + 1, 2) + '-' + c1.mvc.Utils.formatNumber(date.getDate(), 2) + 'T' + c1.mvc.Utils.formatNumber(date.getHours(), 2) + ':' + c1.mvc.Utils.formatNumber(date.getMinutes(), 2) + ':' + c1.mvc.Utils.formatNumber(date.getSeconds(), 2) + '.' + c1.mvc.Utils.formatNumber(date.getMilliseconds(), 3) + (date.dateKind == c1.mvc.DateKind.Utc ? 'Z' : getLocalTimeZoneText()); args.cancel = true; } } function getLocalTimeZoneText() { var date = new Date(); var timeoffset = date.getTimezoneOffset(); var result = ''; if (timeoffset > 0) { result += '-'; } else { result += '+'; timeoffset *= -1; } var hour = Math.floor(timeoffset / 60); result += formatNumber(hour, 2); result += ":"; result += formatNumber(timeoffset - hour * 60, 2); return result; } function formatNumber(n, k) { // 少なくともk桁になるように整数を書式設定します。 var text = n.toString(); while (text.length < k) { text = '0' + text; } return text; } |
コード内 - Index.cshtml
DatesData.cs |
コードのコピー
|
---|---|
@(Html.C1().FlexGrid() .Id("customGrid") .AllowAddNew(true) .AllowDelete(true) .AutoGenerateColumns(false) .Bind(cvb => cvb.Bind(Url.Action("Custom_ReadDatesData")) .Create(Url.Action("Custom_CreateDatesData")) .Update(Url.Action("Custom_UpdateDatesData")) .Delete(Url.Action("Custom_DeleteDatesData")) .OnClientReponseTextParsing("reponseTextParsing") .OnClientRequestDataStringifying("requestDataStringifying")) .Columns(columns => { columns.Add(column => column.Binding("Id").IsReadOnly(true).Visible(false)); columns.Add(column => column.Binding("UtcDateTime").Format("dd/MM/yyyy HH:mm:ss").Width("*")); columns.Add(column => column.Binding("LocalDateTime").Format("dd/MM/yyyy HH:mm:ss").Width("*")); columns.Add(column => column.Binding("UnspecifiedDateTime").Format("dd/MM/yyyy HH:mm:ss").Width("*")); }) .Filterable(f => f.DefaultFilterType(FilterType.Both))) |