private void DrawRouteMap() { // 初期化してあげます _mapView.clearPoint(); // パス情報を追加していきます bykIFv1.Point pm = _trackItem.Items[0]; string markerText = string.Empty; _mapView.addPoint(pm.Latitude, pm.Longitude, string.Format(Properties.Resources.MSG7, pm.Time.ToLocalTime())); foreach (bykIFv1.Point p in _trackItem.Items) { if (p.Interest || (pm.Time.AddSeconds(6) < p.Time)) { pm = p; if (pm == _trackItem.Items[_trackItem.Items.Count - 1]) { markerText = string.Format(Properties.Resources.MSG8, pm.Time.ToLocalTime()); } else { markerText = (pm.Interest) ? pm.Time.ToLocalTime().ToString() : string.Empty; } _mapView.addPoint(pm.Latitude, pm.Longitude, markerText); } } if (pm != _trackItem.Items[_trackItem.Items.Count - 1]) { pm = _trackItem.Items[_trackItem.Items.Count - 1]; _mapView.addPoint(pm.Latitude, pm.Longitude, string.Format(Properties.Resources.MSG8, pm.Time.ToLocalTime())); } // 描画を実行します。 _mapView.drawPolyline(); }
private void _mapView_OnMakerDrag(double lat, double lon) { if (1 != _targets.SelectedItems.Count) { return; } ListViewItem item = _targets.SelectedItems[0]; JPEGFileItem jpegItem = item.Tag as JPEGFileItem; if (null == jpegItem) { return; } System.Diagnostics.Debug.Print("new pos {0},{1}", lat, lon); bykIFv1.Point point = jpegItem.NewLocation; bykIFv1.Point pnew; if (null != point) { pnew = new bykIFv1.Point(point.Time, lat, lon, double.NaN, 0, false); } else { pnew = new bykIFv1.Point(jpegItem.DateTimeOriginal, lat, lon, double.NaN, 0, false); } jpegItem.NewLocation = pnew; item.ForeColor = Color.Black; item.Checked = true; }
private bykIFv1.Point FindPointForeach(DateTime localTime) { // 複数の位置情報元で一致したら、近いデータを採用する // 比較用にUTCにする DateTime utcdt = localTime.Subtract(System.TimeZoneInfo.Local.GetUtcOffset(localTime)); bykIFv1.Point result = null; double diff = 0; double diffOld = double.MaxValue; foreach (TrackItemSummary summary in _locations) { if (summary.IsContein(localTime, MAX_TIMEDIFF)) { bykIFv1.Point point = summary.GetPoint(localTime, MAX_TIMEDIFF, MAX_DISTDIFF); if (null != point) { TimeSpan s = point.Time - utcdt; diff = Math.Abs(s.TotalSeconds); if (diffOld > diff) { result = point; diffOld = diff; } } } } return(result); }
public JPEGFileItem(string filePath, Size thumNailSize, Color transColor) { _filePath = filePath; AnalyzeExif(_filePath, thumNailSize, transColor); _newLocation = null; _remove = false; }
public static double Distance(IEnumerable <bykIFv1.Point> points) { double result = 0; bykIFv1.Point from = null; foreach (var to in points) { if (null != from) { result += Distance(from, to); } from = to; } return(result); }
private double GetSpeed(bykIFv1.Point current, bykIFv1.Point prev) { if (0 < current.Speed) { return(current.Speed); } // 10分以上差があるなら、時速算出しない TimeSpan ts = current.Time - prev.Time; if (ts.TotalMinutes >= 10) { return(current.Speed); } double dis = PointDistance.Distance(current, prev); double result = dis / ts.TotalSeconds; return(result); }
private bykIFv1.Point ECEF2LonLat(DataLogFixFull local) { bykIFv1.Point result = null; double x = (double)local.X; double y = (double)local.Y; double z = (double)local.Z; double lat = 0; double lon = 0; double alt = 0; ECEF2LLA(x, y, z, out lat, out lon, out alt); DateTime dt = GPSTIME2diffUTC(local.WN, local.TOW); double spd = (local.V * 1000); spd /= 3600; result = new bykIFv1.Point(dt, lat, lon, alt, spd, (DataLogFixFull.TYPE.FULL_POI == local.type)); return(result); }
/// <summary> /// 二点間の距離を求める(ヒュベニの公式) /// ※ /// </summary> /// <param name="pt1"></param> /// <param name="pt2"></param> /// <returns>m</returns> public static double Distance(bykIFv1.Point pt1, bykIFv1.Point pt2) { const double PI = 3.1415926535898; // a = 6,378,137 const double a = 6378137; // f = 1 / 298.257 223 563 const double f = 1 / 298.257223563; // b = a - ( a * f) const double b = a - (a * f); double x1 = (pt1.Longitude * PI) / 180; double x2 = (pt2.Longitude * PI) / 180; double y1 = (pt1.Latitude * PI) / 180; double y2 = (pt2.Latitude * PI) / 180; // e = √((a^2 - b^2) / a^2) //double e = Math.Sqrt((Math.Pow(a, 2) + Math.Pow(b, 2)) / Math.Pow(a, 2)); const double e = 1.4118447577583941; // μy = (y1 + y2) / 2 double uy = (y1 + y2) / 2; // W = √(1-(e^2 * sin(μy)^2)) double W = Math.Sqrt(1 - (Math.Pow(e, 2) * Math.Pow(Math.Sin((uy * PI) / 180), 2))); // N = a / W double N = a / W; // M = a * (1 - e^2) / W^3 double M = (a * (1 - Math.Pow(e, 2))) / Math.Pow(W, 3); // dy = y1 - y2 double dy = y1 - y2; // dx = x1 - x2 double dx = x1 - x2; // d = √((dy*M)^2 + (dx*N*cos μy)^2) double d = Math.Sqrt(Math.Pow(dy * M, 2) + Math.Pow(dx * N * Math.Cos(uy), 2)); return(d); }
public PointConvertor(bykIFv1.Point point) { _point = point; }
public bykIFv1.Point GetPoint(DateTime targetDate, double margineSeconds, double margineDstaince) { // 含まれない場合NULLを返すよ if (!IsContein(targetDate, margineSeconds)) { return(null); } // 指定された時間をUTCに変換する TimeSpan diff = System.TimeZoneInfo.Local.GetUtcOffset(targetDate); DateTime utcTime = targetDate.Subtract(diff); bykIFv1.Point orless = null; bykIFv1.TrackItem trackItem = _trackItemProxy.GetTrackItem(out _trackItemProxy); foreach (bykIFv1.Point pnt in trackItem.Items) { if (utcTime == pnt.Time) { return(pnt); } if (utcTime > pnt.Time) { orless = pnt; } // ソートされているから省略する if (utcTime < pnt.Time) { if (null != orless) { TimeSpan s1 = utcTime - orless.Time; TimeSpan s2 = pnt.Time - utcTime; if (s1 < s2) { if (s1.TotalSeconds <= margineSeconds) { return(orless); } } else { if (s2.TotalSeconds <= margineSeconds) { return(pnt); } } // 前回値の二点間の距離をみるよ double d = PointDistance.Distance(orless, pnt); if (d < margineDstaince) { // 前後の距離が近いので、時間のブレは大きいが、位置情報として採用する // 近い方 if (s1 < s2) { return(orless); } else { return(pnt); } } } else { TimeSpan s2 = pnt.Time - utcTime; if (s2.TotalSeconds <= margineSeconds) { return(pnt); } } break; } } // 最終の点よりも少しあとを再処理する if (2 < trackItem.Items.Count) { bykIFv1.Point ormore = trackItem.Items[trackItem.Items.Count - 1]; TimeSpan s3 = utcTime - ormore.Time; if (0 <= s3.TotalSeconds) { if (s3.TotalSeconds <= margineSeconds) { return(ormore); } } } return(null); }
public bykIFv1.TrackItem Read() { bykIFv1.Point olditem = null; bykIFv1.TrackItem result = new bykIFv1.TrackItem("KML data", DateTime.Now); List <DateTime> wayPoints = new List <DateTime>(); while (_xmlReader.Read()) { switch (_xmlReader.NodeType) { case System.Xml.XmlNodeType.Element: if (0 == string.Compare(_xmlReader.Name, "Placemark", true)) { if (!_xmlReader.IsEmptyElement) { string datetime = string.Empty; string coord = string.Empty; while (_xmlReader.Read()) { switch (_xmlReader.NodeType) { case System.Xml.XmlNodeType.Element: if (0 == string.Compare(_xmlReader.Name, "name", true)) { result.Name = _xmlReader.ReadString(); } else if (0 == string.Compare(_xmlReader.Name, "description", true)) { result.Description = _xmlReader.ReadString(); } else if (0 == string.Compare(_xmlReader.Name, "gx:Track", true)) { if (!_xmlReader.IsEmptyElement) { while (_xmlReader.Read()) { switch (_xmlReader.NodeType) { case System.Xml.XmlNodeType.Element: if (0 == string.Compare(_xmlReader.Name, "when", true)) { datetime = _xmlReader.ReadString(); } else if (0 == string.Compare(_xmlReader.Name, "gx:coord", true)) { coord = _xmlReader.ReadString(); string[] coords = coord.Split(' '); DateTime dt; if (DateTime.TryParse(datetime, out dt)) { double lon = double.Parse(coords[1]); double lat = double.Parse(coords[0]); double ele = (coords.Length > 2) ? double.Parse(coords[2]) : double.NaN; bykIFv1.Point item = new bykIFv1.Point(dt.ToUniversalTime(), lon, lat, ele, 0, false); bool skip = false; if (null != olditem) { TimeSpan s = item.Time - olditem.Time; double maxDistance = Math.Abs(_maxSpeed * s.TotalSeconds); // 音速を超える移動は破棄する skip = (maxDistance < item.Location.GetDistanceTo(olditem.Location)); } if (false == skip) { result.Items.Add(item); } olditem = item; } datetime = string.Empty; } else { if (!_xmlReader.IsEmptyElement) { while (_xmlReader.Read()) { if (_xmlReader.NodeType == System.Xml.XmlNodeType.EndElement) { break; } } } } continue; } } } } else { if (!_xmlReader.IsEmptyElement) { while (_xmlReader.Read()) { if (_xmlReader.NodeType == System.Xml.XmlNodeType.EndElement) { break; } } } } continue; case System.Xml.XmlNodeType.EndElement: break; default: continue; } break; } } } break; } } return(result); }
private void SetGraphData() { bykIFv1.Point start = _trackItem.Items[0]; bykIFv1.Point end = _trackItem.Items[_trackItem.Items.Count - 1]; List <GraphControlLibrary.PointData> speedList = new List <GraphControlLibrary.PointData>(); { double range = 60; { TimeSpan ts = _trackItem.Items[_trackItem.Items.Count - 1].Time - _trackItem.Items[0].Time; if (1 >= ts.TotalMinutes) { range = 1; } } // 1分平均(データが1分以下なら平均しないよ) for (DateTime time = start.Time; time <= end.Time; time = time.AddSeconds(60)) { DateTime work = time.AddSeconds(60); // 60分いないのデータ一覧を取得 var q = _trackItem.Items.Where(x => time <= x.Time && work > x.Time).OrderBy(x => x.Time); // 取得したデータ一覧で速度を求める bykIFv1.Point p1 = null; double speed = 0; int itemCount = 0; foreach (bykIFv1.Point p in q) { if (null == p1) { // 最初の一湖なので、データを取り出すだけね。 speed = p.Speed; itemCount = 1; } else { // 前回値との差分から速度をみるよ double speedSrc = GetSpeed(p, p1); if (0 < speedSrc) { speed += speedSrc; ++itemCount; } } p1 = p; } TimeSpan s2 = time - start.Time; // 速度を平均とkm/hへ変換する if (0 < itemCount) { speed /= itemCount; // m/sからkm/hへ speed *= 3600; speed /= 1000; } else { speed = 0; } // 登録 speedList.Add(new GraphControlLibrary.PointData((Single)s2.TotalSeconds, (Single)speed)); } } TimeSpan s = end.Time - start.Time; Single TotalSeconds = (Single)s.TotalSeconds; GraphControlLibrary.ScaleData xMin = new GraphControlLibrary.ScaleData(start.Time.ToString(), 0); GraphControlLibrary.ScaleData xMax = new GraphControlLibrary.ScaleData(end.Time.ToString(), TotalSeconds); GraphControlLibrary.ScaleSet ss = new GraphControlLibrary.ScaleSet("時間", "s", xMin, xMax, new HogeX(start.Time)); if (1 <= s.TotalDays) { // 一日以上の差があるので、0:00にだけ線を引く DateTime scale = new DateTime(start.Time.Year, start.Time.Month, start.Time.Day, 0, 0, 0); while (end.Time > scale) { scale = scale.AddDays(1); TimeSpan s2 = scale - start.Time; if (end.Time > scale) { ss.Items.Add(new GraphControlLibrary.ScaleData(scale.ToLocalTime().ToString("yyyy/MM/dd"), (Single)s2.TotalSeconds)); } else { break; } } } else { if (1 <= s.TotalHours) { // 一時間以上差があるので、x:00に線を引く DateTime scale = new DateTime(start.Time.Year, start.Time.Month, start.Time.Day, start.Time.Hour, 0, 0); while (end.Time > scale) { scale = scale.AddHours(1); TimeSpan s2 = scale - start.Time; if (end.Time > scale) { if (0 >= ss.Items.Count) { ss.Items.Add(new GraphControlLibrary.ScaleData(scale.ToLocalTime().ToString("yyyy/MM/dd HH:mm"), (Single)s2.TotalSeconds)); } else { ss.Items.Add(new GraphControlLibrary.ScaleData(scale.ToLocalTime().ToString("HH:mm"), (Single)s2.TotalSeconds)); } } else { break; } } } else { if (1 <= s.TotalMinutes) { // 1分以上差があるので、5分ごとに線を引く DateTime scale = new DateTime(start.Time.Year, start.Time.Month, start.Time.Day, start.Time.Hour, start.Time.Minute, 0); while (end.Time > scale) { scale = scale.AddMinutes(5); TimeSpan s2 = scale - start.Time; if (end.Time > scale) { if (0 >= ss.Items.Count) { ss.Items.Add(new GraphControlLibrary.ScaleData(scale.ToLocalTime().ToString("yyyy/MM/dd HH:mm"), (Single)s2.TotalSeconds)); } else { ss.Items.Add(new GraphControlLibrary.ScaleData(scale.ToLocalTime().ToString("HH:mm"), (Single)s2.TotalSeconds)); } } else { break; } } } } } GraphControlLibrary.ScaleSet ss2 = new GraphControlLibrary.ScaleSet("時速", "km/h", new GraphControlLibrary.ScaleData("0 km", 0), new GraphControlLibrary.ScaleData(string.Format("{0:F2}", maxSpeed), (float)maxSpeed), new HogeY()); ss2.Items.Add(new GraphControlLibrary.ScaleData(string.Format("{0:F0}", maxSpeed / 2), (Single)(maxSpeed / 2))); ss2.Items.Add(new GraphControlLibrary.ScaleData(string.Format("{0:F0}", maxSpeed), (Single)(maxSpeed))); GraphControlLibrary.GraphSet gset = new GraphControlLibrary.GraphSet(ss, ss2, true); gset.Items.AddRange(speedList); _graphView.BegineUpdate(); _graphView.Items.Add(gset); _graphView.EndUpdate(); }
public bykIFv1.TrackItem Read() { bykIFv1.TrackItem result = null; List <bykIFv1.Point> points = new List <bykIFv1.Point>(); DateTime createTime = DateTime.Now; string name = string.Empty; List <DateTime> wayPoints = new List <DateTime>(); while (_xmlReader.Read()) { switch (_xmlReader.NodeType) { case System.Xml.XmlNodeType.Element: if (0 == string.Compare(_xmlReader.Name, "time", true)) { string sTime = _xmlReader.ReadString(); DateTime dt; if (DateTime.TryParse(sTime, out dt)) { createTime = dt; } } else if (0 == string.Compare(_xmlReader.Name, "name", true)) { name = _xmlReader.ReadString(); } else if (0 == string.Compare(_xmlReader.Name, "wpt", true)) { if (!_xmlReader.IsEmptyElement) { string lon = _xmlReader.GetAttribute("lon"); string lat = _xmlReader.GetAttribute("lat"); string sEle = string.Empty; string sTime = string.Empty; string sSpeed = string.Empty; while (_xmlReader.Read()) { switch (_xmlReader.NodeType) { case System.Xml.XmlNodeType.Element: if (0 == string.Compare(_xmlReader.Name, "ele", true)) { sEle = _xmlReader.ReadString(); } else if (0 == string.Compare(_xmlReader.Name, "time", true)) { sTime = _xmlReader.ReadString(); } else if (0 == string.Compare(_xmlReader.Name, "speed", true)) { sSpeed = _xmlReader.ReadString(); } else { if (!_xmlReader.IsEmptyElement) { while (_xmlReader.Read()) { if (_xmlReader.NodeType == System.Xml.XmlNodeType.EndElement) { break; } } } } continue; case System.Xml.XmlNodeType.EndElement: break; default: continue; } break; } DateTime dt; if (DateTime.TryParse(sTime, out dt)) { wayPoints.Add(dt); } } } else if (0 == string.Compare(_xmlReader.Name, "trkpt", true)) { if (!_xmlReader.IsEmptyElement) { string lon = _xmlReader.GetAttribute("lon"); string lat = _xmlReader.GetAttribute("lat"); string sEle = string.Empty; string sTime = string.Empty; string sSpeed = string.Empty; while (_xmlReader.Read()) { switch (_xmlReader.NodeType) { case System.Xml.XmlNodeType.Element: if (0 == string.Compare(_xmlReader.Name, "ele", true)) { sEle = _xmlReader.ReadString(); } else if (0 == string.Compare(_xmlReader.Name, "time", true)) { sTime = _xmlReader.ReadString(); } else if (0 == string.Compare(_xmlReader.Name, "speed", true)) { sSpeed = _xmlReader.ReadString(); } else { if (!_xmlReader.IsEmptyElement) { while (_xmlReader.Read()) { if (_xmlReader.NodeType == System.Xml.XmlNodeType.EndElement) { break; } } } } continue; case System.Xml.XmlNodeType.EndElement: break; default: continue; } break; } DateTime dt; if (DateTime.TryParse(sTime, out dt)) { bool wayPoint = (0 <= wayPoints.IndexOf(dt)); bykIFv1.Point item = new bykIFv1.Point(dt.ToUniversalTime(), double.Parse(lat), double.Parse(lon), double.Parse(sEle), double.Parse(sSpeed), wayPoint); points.Add(item); } } } break; } } if (0 >= name.Length) { name = "location data"; } // 応答を作成しますよ result = new bykIFv1.TrackItem(name, createTime); result.Items = points; return(result); }
private void AnalyzeExif(string filePath, Size thumNailSize, Color transColor) { DateTime dt = DateTime.MinValue; string sNS = string.Empty; string sEW = string.Empty; UInt32[] uLon = null; UInt32[] uLat = null; using (Bitmap bmp = new Bitmap(filePath)) { // 0x0001-北緯(N) or 南緯(S)(Ascii) // 0x0002-緯度(数値)(Rational) // 0x0003-東経(E) or 西経(W)(Ascii) // 0x0004-経度(数値)(Rational) // 0x0005-高度の基準(Byte) // 0x0006-高度(数値)(Rational) // 0x0007-GPS時間(原子時計の時間)(Rational) // 0x0008-測位に使った衛星信号(Ascii) // 0x0009-GPS受信機の状態(Ascii) // 0x000A-GPSの測位方法(Ascii) // 0x000B-測位の信頼性(Rational) // 0x000C-速度の単位(Ascii) // 0x000D-速度(数値)(Rational) foreach (System.Drawing.Imaging.PropertyItem item in bmp.PropertyItems) { switch (item.Id) { // 0x0112 - 回転情報(Orientation) case 0x0112: switch (item.Value[0]) { case 3: // 時計回りに180度回転しているので、180度回転して戻す _orientation = Orientation.Orientation_180; break; case 6: // 時計回りに270度回転しているので、90度回転して戻す _orientation = Orientation.Orientation_90; break; case 8: // 時計回りに90度回転しているので、270度回転して戻す _orientation = Orientation.Orientation_270; break; } break; // 0x9004 - デジタルデータの作成日時 case 0x9004: if (0 == dt.CompareTo(DateTime.MinValue)) { string s = System.Text.Encoding.ASCII.GetString(item.Value); s = s.Trim(new char[] { '\0' }); { s = System.Text.RegularExpressions.Regex.Replace(s, @"^(?<year>(?:\d\d)?\d\d):(?<month>\d\d?):(?<day>\d\d?)", "${year}/${month}/${day}"); } dt = DateTime.Parse(s); } break; // 0x9003 - 原画像データの生成日時 case 0x9003: { string s = System.Text.Encoding.ASCII.GetString(item.Value); s = s.Trim(new char[] { '\0' }); { s = System.Text.RegularExpressions.Regex.Replace(s, @"^(?<year>(?:\d\d)?\d\d):(?<month>\d\d?):(?<day>\d\d?)", "${year}/${month}/${day}"); } dt = DateTime.Parse(s); } break; // 0x0001-北緯(N) or 南緯(S)(Ascii) case 0x0001: sNS = System.Text.Encoding.ASCII.GetString(item.Value); sNS = sNS.Trim(new char[] { '\0' }); break; // 0x0002-緯度(数値)(Rational):latitude - 緯度 case 0x0002: { if (4 <= item.Len) { uLat = new UInt32[item.Len / 4]; System.Buffer.BlockCopy(item.Value, 0, uLat, 0, item.Len); } } break; // 0x0003-東経(E) or 西経(W)(Ascii) case 0x0003: sEW = System.Text.Encoding.ASCII.GetString(item.Value); sEW = sEW.Trim(new char[] { '\0' }); break; // 0x0004-経度(数値)(Rational):longitude - 経度 case 0x0004: { if (4 <= item.Len) { uLon = new UInt32[item.Len / 4]; System.Buffer.BlockCopy(item.Value, 0, uLon, 0, item.Len); } } break; } } // ついでにサムネイルを作る _thumNail = stretchImage(bmp, thumNailSize, transColor); } // Exifに撮影日時がないならファイルの作成時を利用する if (0 == dt.CompareTo(DateTime.MinValue)) { System.IO.FileInfo fi = new System.IO.FileInfo(FilePath); _targetdate = fi.CreationTime; } else { _targetdate = dt; } if (null != uLon && null != uLat) { // 経度 double lon = ToDegree(uLon); if (0 == string.Compare(sEW, "W", true)) { lon *= -1; } // 緯度 double lat = ToDegree(uLat); if (0 == string.Compare(sNS, "S", true)) { lat *= -1; } _currentLocation = new bykIFv1.Point(dt, lat, lon, 0, 0, true); } else { _currentLocation = null; } }
public void RemoveLocation() { _remove = true; _newLocation = null; }
private void preview_Click(object sender, EventArgs e) { _items.Clear(); if (byDateTime.Checked) { int splitCount = 0; bykIFv1.TrackItem newItem = null; DateTime prevValue = DateTime.MinValue; TimeSpan ts; foreach (bykIFv1.Point p in _track.Items) { ts = p.Time - prevValue; if ((double)timeValue.Value <= ts.TotalHours) { ++splitCount; // 名前は元のデータを利用する newItem = new bykIFv1.TrackItem(string.Format("{0}({1})", _track.Name, splitCount), _track.CreateTime); // 情報があれば利用する if (0 < _track.Description.Length) { newItem.Description = string.Format("{0}({1})", _track.Description, splitCount); } _items.Add(newItem); } newItem.Items.Add(p); prevValue = p.Time; } } else if (byDistance.Checked) { int splitCount = 0; bykIFv1.TrackItem newItem = null; // KMをMにしますよ double distanceValueMeter = (double)distanceValue.Value * 1000; bykIFv1.Point from = null; double distance = 0; foreach (bykIFv1.Point p in _track.Items) { distance = (null == from) ? distanceValueMeter : PointDistance.Distance(from, p); if (distanceValueMeter <= distance) { ++splitCount; // 名前は元のデータを利用する newItem = new bykIFv1.TrackItem(string.Format("{0}({1})", _track.Name, splitCount), _track.CreateTime); // 情報があれば利用する if (0 < _track.Description.Length) { newItem.Description = string.Format("{0}({1})", _track.Description, splitCount); } _items.Add(newItem); } newItem.Items.Add(p); from = p; } } _splitItems.BeginUpdate(); try { _splitItems.Items.Clear(); foreach (var v in _items) { ListViewItem item = new ListViewItem(v.Name); DateTime dtFrom = v.Items[0].Time; TimeSpan span = System.TimeZoneInfo.Local.GetUtcOffset(dtFrom); dtFrom = dtFrom.Add(span); item.SubItems.Add(dtFrom.ToString()); DateTime dtTo = v.Items[v.Items.Count - 1].Time; span = System.TimeZoneInfo.Local.GetUtcOffset(dtTo); dtTo = dtTo.Add(span); item.SubItems.Add(dtTo.ToString()); item.SubItems.Add(v.Items.Count.ToString()); item.Tag = v; _splitItems.Items.Add(item); } _splitItems.Enabled = true; _OK.Enabled = true; } finally { _splitItems.EndUpdate(); } }