OSDN Git Service

ApiLimitで扱う日時の型をDateTimeUtcに変更
authorKimura Youichi <kim.upsilon@bucyou.net>
Mon, 7 May 2018 03:36:47 +0000 (12:36 +0900)
committerKimura Youichi <kim.upsilon@bucyou.net>
Wed, 9 May 2018 01:23:53 +0000 (10:23 +0900)
OpenTween.Tests/Api/ApiLimitTest.cs
OpenTween.Tests/Api/TwitterApiStatusTest.cs
OpenTween.Tests/Connection/TwitterApiConnectionTest.cs
OpenTween.Tests/DateTimeUtcTest.cs
OpenTween.Tests/ToolStripAPIGaugeTest.cs
OpenTween/Api/ApiLimit.cs
OpenTween/Api/TwitterApiStatus.cs
OpenTween/ApiInfoDialog.cs
OpenTween/DateTimeUtc.cs
OpenTween/ToolStripAPIGauge.cs

index 40a92a0..1e008e0 100644 (file)
@@ -34,10 +34,10 @@ namespace OpenTween.Api
         {
             get
             {
-                yield return new object[] { new ApiLimit(150, 100, new DateTime(2013, 1, 1, 0, 0, 0)), true };
-                yield return new object[] { new ApiLimit(350, 100, new DateTime(2013, 1, 1, 0, 0, 0)), false };
-                yield return new object[] { new ApiLimit(150, 150, new DateTime(2013, 1, 1, 0, 0, 0)), false };
-                yield return new object[] { new ApiLimit(150, 100, new DateTime(2012, 12, 31, 0, 0, 0)), false };
+                yield return new object[] { new ApiLimit(150, 100, new DateTimeUtc(2013, 1, 1, 0, 0, 0)), true };
+                yield return new object[] { new ApiLimit(350, 100, new DateTimeUtc(2013, 1, 1, 0, 0, 0)), false };
+                yield return new object[] { new ApiLimit(150, 150, new DateTimeUtc(2013, 1, 1, 0, 0, 0)), false };
+                yield return new object[] { new ApiLimit(150, 100, new DateTimeUtc(2012, 12, 31, 0, 0, 0)), false };
                 yield return new object[] { null, false };
                 yield return new object[] { new object(), false };
             }
@@ -47,7 +47,7 @@ namespace OpenTween.Api
         [MemberData(nameof(Equals_TestCase))]
         public void EqualsTest(object obj2, bool expected)
         {
-            var obj1 = new ApiLimit(150, 100, new DateTime(2013, 1, 1, 0, 0, 0));
+            var obj1 = new ApiLimit(150, 100, new DateTimeUtc(2013, 1, 1, 0, 0, 0));
 
             Assert.Equal(expected, obj1.Equals(obj2));
         }
index 24477fb..310651c 100644 (file)
@@ -38,8 +38,8 @@ namespace OpenTween.Api
         {
             var apiStatus = new TwitterApiStatus();
 
-            apiStatus.AccessLimit["/statuses/home_timeline"] = new ApiLimit(150, 100, new DateTime(2013, 1, 1, 0, 0, 0));
-            apiStatus.MediaUploadLimit = new ApiLimit(150, 100, new DateTime(2013, 1, 1, 0, 0, 0));
+            apiStatus.AccessLimit["/statuses/home_timeline"] = new ApiLimit(150, 100, new DateTimeUtc(2013, 1, 1, 0, 0, 0));
+            apiStatus.MediaUploadLimit = new ApiLimit(150, 100, new DateTimeUtc(2013, 1, 1, 0, 0, 0));
             apiStatus.AccessLevel = TwitterApiAccessLevel.ReadWriteAndDirectMessage;
 
             apiStatus.Reset();
@@ -59,7 +59,7 @@ namespace OpenTween.Api
                         ["X-RateLimit-Remaining"] = "100",
                         ["X-RateLimit-Reset"] = "1356998400",
                     },
-                    new ApiLimit(150, 100, new DateTime(2013, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime()),
+                    new ApiLimit(150, 100, new DateTimeUtc(2013, 1, 1, 0, 0, 0)),
                 };
                 yield return new object[] {
                     new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) {
@@ -67,7 +67,7 @@ namespace OpenTween.Api
                         ["x-ratelimit-remaining"] = "100",
                         ["x-ratelimit-reset"] = "1356998400",
                     },
-                    new ApiLimit(150, 100, new DateTime(2013, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime()),
+                    new ApiLimit(150, 100, new DateTimeUtc(2013, 1, 1, 0, 0, 0)),
                 };
                 yield return new object[] {
                     new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) {
@@ -105,7 +105,7 @@ namespace OpenTween.Api
                         ["X-MediaRateLimit-Remaining"] = "20",
                         ["X-MediaRateLimit-Reset"] = "1234567890",
                     },
-                    new ApiLimit(30, 20, new DateTime(2009, 2, 13, 23, 31, 30, DateTimeKind.Utc).ToLocalTime()),
+                    new ApiLimit(30, 20, new DateTimeUtc(2009, 2, 13, 23, 31, 30)),
                 };
                 yield return new object[] {
                     new Dictionary<string, string> {
@@ -193,12 +193,12 @@ namespace OpenTween.Api
             var rateLimit = status.AccessLimit["/statuses/home_timeline"];
             Assert.Equal(150, rateLimit.AccessLimitCount);
             Assert.Equal(100, rateLimit.AccessLimitRemain);
-            Assert.Equal(new DateTime(2013, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime(), rateLimit.AccessLimitResetDate);
+            Assert.Equal(new DateTimeUtc(2013, 1, 1, 0, 0, 0), rateLimit.AccessLimitResetDate);
 
             var mediaLimit = status.MediaUploadLimit;
             Assert.Equal(30, mediaLimit.AccessLimitCount);
             Assert.Equal(20, mediaLimit.AccessLimitRemain);
-            Assert.Equal(new DateTime(2013, 1, 2, 0, 0, 0, DateTimeKind.Utc).ToLocalTime(), mediaLimit.AccessLimitResetDate);
+            Assert.Equal(new DateTimeUtc(2013, 1, 2, 0, 0, 0), mediaLimit.AccessLimitResetDate);
 
             Assert.Equal(TwitterApiAccessLevel.ReadWriteAndDirectMessage, status.AccessLevel);
         }
@@ -231,12 +231,12 @@ namespace OpenTween.Api
             var rateLimit = status.AccessLimit["/statuses/home_timeline"];
             Assert.Equal(150, rateLimit.AccessLimitCount);
             Assert.Equal(100, rateLimit.AccessLimitRemain);
-            Assert.Equal(new DateTime(2013, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime(), rateLimit.AccessLimitResetDate);
+            Assert.Equal(new DateTimeUtc(2013, 1, 1, 0, 0, 0), rateLimit.AccessLimitResetDate);
 
             var mediaLimit = status.MediaUploadLimit;
             Assert.Equal(30, mediaLimit.AccessLimitCount);
             Assert.Equal(20, mediaLimit.AccessLimitRemain);
-            Assert.Equal(new DateTime(2013, 1, 2, 0, 0, 0, DateTimeKind.Utc).ToLocalTime(), mediaLimit.AccessLimitResetDate);
+            Assert.Equal(new DateTimeUtc(2013, 1, 2, 0, 0, 0), mediaLimit.AccessLimitResetDate);
 
             Assert.Equal(TwitterApiAccessLevel.ReadWriteAndDirectMessage, status.AccessLevel);
         }
@@ -257,7 +257,7 @@ namespace OpenTween.Api
             var rateLimit = status.AccessLimit["/statuses/home_timeline"];
             Assert.Equal(150, rateLimit.AccessLimitCount);
             Assert.Equal(100, rateLimit.AccessLimitRemain);
-            Assert.Equal(new DateTime(2013, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime(), rateLimit.AccessLimitResetDate);
+            Assert.Equal(new DateTimeUtc(2013, 1, 1, 0, 0, 0), rateLimit.AccessLimitResetDate);
         }
 
         [Fact]
@@ -268,7 +268,7 @@ namespace OpenTween.Api
             Assert.Raises<TwitterApiStatus.AccessLimitUpdatedEventArgs>(
                 x => apiStatus.AccessLimitUpdated += x,
                 x => apiStatus.AccessLimitUpdated -= x,
-                () => apiStatus.AccessLimit["/statuses/home_timeline"] = new ApiLimit(150, 100, new DateTime(2013, 1, 1, 0, 0, 0))
+                () => apiStatus.AccessLimit["/statuses/home_timeline"] = new ApiLimit(150, 100, new DateTimeUtc(2013, 1, 1, 0, 0, 0))
             );
 
             Assert.Raises<TwitterApiStatus.AccessLimitUpdatedEventArgs>(
index 56a99b2..0f20f7e 100644 (file)
@@ -171,7 +171,7 @@ namespace OpenTween.Connection
                     .ConfigureAwait(false);
 
                 Assert.Equal(TwitterApiAccessLevel.ReadWriteAndDirectMessage, apiStatus.AccessLevel);
-                Assert.Equal(new ApiLimit(150, 100, new DateTime(2013, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime()), apiStatus.AccessLimit["/hoge/tetete"]);
+                Assert.Equal(new ApiLimit(150, 100, new DateTimeUtc(2013, 1, 1, 0, 0, 0)), apiStatus.AccessLimit["/hoge/tetete"]);
 
                 Assert.Equal(0, mockHandler.QueueCount);
             }
index 2666da6..4f39aec 100644 (file)
@@ -198,5 +198,22 @@ namespace OpenTween
             Assert.True(utc2 >= utc1);
 #pragma warning restore CS1718
         }
+
+        [Fact]
+        public void MinValue_Test()
+            => Assert.Equal(DateTime.MinValue.Ticks, DateTimeUtc.MinValue.ToDateTimeUnsafe().Ticks);
+
+        [Fact]
+        public void MaxValue_Test()
+            => Assert.Equal(DateTime.MaxValue.Ticks, DateTimeUtc.MaxValue.ToDateTimeUnsafe().Ticks);
+
+        [Fact]
+        public void FromUnixTime_Test()
+        {
+            var utc = DateTimeUtc.FromUnixTime(1234567890);
+
+            Assert.Equal(new DateTime(2009, 2, 13, 23, 31, 30, 0, DateTimeKind.Utc),
+                utc.ToDateTimeUnsafe());
+        }
     }
 }
index b3223c4..90aa99b 100644 (file)
@@ -37,11 +37,11 @@ namespace OpenTween
         {
             using (var toolStrip = new TestToolStripAPIGauge())
             {
-                var now = DateTime.Now;
+                var now = DateTimeUtc.Now;
                 toolStrip.DateTimeNow = now;
 
-                MyCommon.TwitterApiInfo.AccessLimit["endpoint1"] = new ApiLimit(15, 15, now.AddMinutes(15));
-                MyCommon.TwitterApiInfo.AccessLimit["endpoint2"] = new ApiLimit(180, 18, now.AddMinutes(5));
+                MyCommon.TwitterApiInfo.AccessLimit["endpoint1"] = new ApiLimit(15, 15, now + TimeSpan.FromMinutes(15));
+                MyCommon.TwitterApiInfo.AccessLimit["endpoint2"] = new ApiLimit(180, 18, now + TimeSpan.FromMinutes(5));
 
                 // toolStrip.ApiEndpoint の初期値は null
 
@@ -51,18 +51,18 @@ namespace OpenTween
                 toolStrip.ApiEndpoint = "endpoint1";
 
                 Assert.Equal("endpoint1", toolStrip.ApiEndpoint);
-                Assert.Equal(new ApiLimit(15, 15, now.AddMinutes(15)), toolStrip.ApiLimit);
+                Assert.Equal(new ApiLimit(15, 15, now + TimeSpan.FromMinutes(15)), toolStrip.ApiLimit);
 
                 toolStrip.ApiEndpoint = "endpoint2";
 
                 Assert.Equal("endpoint2", toolStrip.ApiEndpoint);
-                Assert.Equal(new ApiLimit(180, 18, now.AddMinutes(5)), toolStrip.ApiLimit);
+                Assert.Equal(new ApiLimit(180, 18, now + TimeSpan.FromMinutes(5)), toolStrip.ApiLimit);
 
-                MyCommon.TwitterApiInfo.AccessLimit["endpoint2"] = new ApiLimit(180, 17, now.AddMinutes(5));
+                MyCommon.TwitterApiInfo.AccessLimit["endpoint2"] = new ApiLimit(180, 17, now + TimeSpan.FromMinutes(5));
                 toolStrip.ApiEndpoint = "endpoint2";
 
                 Assert.Equal("endpoint2", toolStrip.ApiEndpoint);
-                Assert.Equal(new ApiLimit(180, 17, now.AddMinutes(5)), toolStrip.ApiLimit);
+                Assert.Equal(new ApiLimit(180, 17, now + TimeSpan.FromMinutes(5)), toolStrip.ApiLimit);
 
                 toolStrip.ApiEndpoint = "hoge";
 
@@ -86,7 +86,7 @@ namespace OpenTween
                 toolStrip.AutoSize = false;
                 toolStrip.Size = new Size(100, 10);
 
-                MyCommon.TwitterApiInfo.AccessLimit["endpoint"] = new ApiLimit(15, 15, DateTime.MaxValue);
+                MyCommon.TwitterApiInfo.AccessLimit["endpoint"] = new ApiLimit(15, 15, DateTimeUtc.MaxValue);
                 toolStrip.ApiEndpoint = "endpoint";
 
                 toolStrip.GaugeHeight = 5;
@@ -113,9 +113,9 @@ namespace OpenTween
         {
             using (var toolStrip = new ToolStripAPIGauge())
             {
-                MyCommon.TwitterApiInfo.AccessLimit["/statuses/home_timeline"] = new ApiLimit(15, 15, DateTime.Now.AddMinutes(15));
-                MyCommon.TwitterApiInfo.AccessLimit["/statuses/user_timeline"] = new ApiLimit(180, 18, DateTime.Now.AddMinutes(-2));
-                MyCommon.TwitterApiInfo.AccessLimit["/search/tweets"] = new ApiLimit(180, 90, DateTime.Now.AddMinutes(5));
+                MyCommon.TwitterApiInfo.AccessLimit["/statuses/home_timeline"] = new ApiLimit(15, 15, DateTimeUtc.Now + TimeSpan.FromMinutes(15));
+                MyCommon.TwitterApiInfo.AccessLimit["/statuses/user_timeline"] = new ApiLimit(180, 18, DateTimeUtc.Now + TimeSpan.FromMinutes(-2));
+                MyCommon.TwitterApiInfo.AccessLimit["/search/tweets"] = new ApiLimit(180, 90, DateTimeUtc.Now + TimeSpan.FromMinutes(5));
 
                 // toolStrip.ApiEndpoint の初期値は null
 
@@ -132,13 +132,13 @@ namespace OpenTween
                 Assert.Equal("API ???/???", toolStrip.Text);
                 Assert.Equal("API rest /statuses/user_timeline ???/???" + Environment.NewLine + "(reset after ??? minutes)", toolStrip.ToolTipText);
 
-                MyCommon.TwitterApiInfo.AccessLimit["/statuses/user_timeline"] = new ApiLimit(180, 180, DateTime.Now.AddMinutes(15));
+                MyCommon.TwitterApiInfo.AccessLimit["/statuses/user_timeline"] = new ApiLimit(180, 180, DateTimeUtc.Now + TimeSpan.FromMinutes(15));
                 toolStrip.ApiEndpoint = "/statuses/user_timeline";
 
                 Assert.Equal("API 180/180", toolStrip.Text);
                 Assert.Equal("API rest /statuses/user_timeline 180/180" + Environment.NewLine + "(reset after 15 minutes)", toolStrip.ToolTipText);
 
-                MyCommon.TwitterApiInfo.AccessLimit["/statuses/user_timeline"] = new ApiLimit(180, 179, DateTime.Now.AddMinutes(15));
+                MyCommon.TwitterApiInfo.AccessLimit["/statuses/user_timeline"] = new ApiLimit(180, 179, DateTimeUtc.Now + TimeSpan.FromMinutes(15));
                 toolStrip.ApiEndpoint = "/statuses/user_timeline";
 
                 Assert.Equal("API 179/180", toolStrip.Text);
@@ -160,7 +160,7 @@ namespace OpenTween
 
         class TestToolStripAPIGauge : ToolStripAPIGauge
         {
-            public DateTime DateTimeNow = DateTime.Now;
+            public DateTimeUtc DateTimeNow = DateTimeUtc.Now;
 
             protected override void UpdateRemainMinutes()
             {
@@ -177,7 +177,7 @@ namespace OpenTween
         {
             using (var toolStrip = new TestToolStripAPIGauge())
             {
-                var now = DateTime.Now;
+                var now = DateTimeUtc.Now;
                 toolStrip.DateTimeNow = now;
 
                 toolStrip.AutoSize = false;
@@ -189,7 +189,7 @@ namespace OpenTween
                 Assert.Equal(Rectangle.Empty, toolStrip.apiGaugeBounds);
                 Assert.Equal(Rectangle.Empty, toolStrip.timeGaugeBounds);
 
-                MyCommon.TwitterApiInfo.AccessLimit["endpoint"] = new ApiLimit(150, 60, now.AddMinutes(3));
+                MyCommon.TwitterApiInfo.AccessLimit["endpoint"] = new ApiLimit(150, 60, now + TimeSpan.FromMinutes(3));
                 toolStrip.ApiEndpoint = "endpoint";
 
                 Assert.Equal(new Rectangle(0, 0, 40, 5), toolStrip.apiGaugeBounds); // 40% (60/150)
index f3ce24a..d4d2663 100644 (file)
@@ -41,19 +41,19 @@ namespace OpenTween.Api
         /// <summary>
         /// API 実行回数制限がリセットされる日時
         /// </summary>
-        public DateTime AccessLimitResetDate { get; }
+        public DateTimeUtc AccessLimitResetDate { get; }
 
         /// <summary>
         /// API 実行回数制限値を取得した日時
         /// </summary>
-        public DateTime UpdatedAt { get; }
+        public DateTimeUtc UpdatedAt { get; }
 
-        public ApiLimit(int limitCount, int limitRemain, DateTime resetDate)
-            : this(limitCount, limitRemain, resetDate, DateTime.Now)
+        public ApiLimit(int limitCount, int limitRemain, DateTimeUtc resetDate)
+            : this(limitCount, limitRemain, resetDate, DateTimeUtc.Now)
         {
         }
 
-        public ApiLimit(int limitCount, int limitRemain, DateTime resetDate, DateTime updatedAt)
+        public ApiLimit(int limitCount, int limitRemain, DateTimeUtc resetDate, DateTimeUtc updatedAt)
         {
             this.AccessLimitCount = limitCount;
             this.AccessLimitRemain = limitRemain;
index f135e06..3b27d55 100644 (file)
@@ -72,7 +72,7 @@ namespace OpenTween.Api
             if (limitCount == null || limitRemain == null || limitReset == null)
                 return null;
 
-            var limitResetDate = UnixEpoch.AddSeconds(limitReset.Value).ToLocalTime();
+            var limitResetDate = DateTimeUtc.FromUnixTime(limitReset.Value);
             return new ApiLimit(limitCount.Value, limitRemain.Value, limitResetDate);
         }
 
@@ -133,8 +133,6 @@ namespace OpenTween.Api
                 this.AccessLevel = accessLevel.Value;
         }
 
-        private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
-
         public void UpdateFromJson(TwitterRateLimits json)
         {
             var rateLimits =
@@ -145,7 +143,7 @@ namespace OpenTween.Api
                     Limit: new ApiLimit(
                         item.Value.Limit,
                         item.Value.Remaining,
-                        UnixEpoch.AddSeconds(item.Value.Reset).ToLocalTime()
+                        DateTimeUtc.FromUnixTime(item.Value.Reset)
                     )
                 );
 
index 0ea4c18..b858f67 100644 (file)
@@ -79,7 +79,7 @@ namespace OpenTween
                 new string[] {
                     endpoint,
                     apiLimit.AccessLimitRemain + "/" + apiLimit.AccessLimitCount,
-                    apiLimit.AccessLimitResetDate.ToString()
+                    apiLimit.AccessLimitResetDate.ToLocalTimeString()
                 });
             item.Group = group;
             this.ListViewApi.Items.Add(item);
@@ -92,7 +92,7 @@ namespace OpenTween
             {
                 var apiLimit = MyCommon.TwitterApiInfo.AccessLimit[endpoint];
                 item.SubItems[1].Text = apiLimit.AccessLimitRemain + "/" + apiLimit.AccessLimitCount;
-                item.SubItems[2].Text = apiLimit.AccessLimitResetDate.ToString();
+                item.SubItems[2].Text = apiLimit.AccessLimitResetDate.ToLocalTimeString();
             }
         }
 
index 7c856af..3ef66f1 100644 (file)
@@ -28,6 +28,15 @@ namespace OpenTween
     /// </summary>
     public struct DateTimeUtc : IComparable<DateTimeUtc>, IEquatable<DateTimeUtc>
     {
+        public static DateTimeUtc MinValue { get; }
+            = new DateTimeUtc(DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Utc));
+
+        public static DateTimeUtc MaxValue { get; }
+            = new DateTimeUtc(DateTime.SpecifyKind(DateTime.MaxValue, DateTimeKind.Utc));
+
+        public static DateTimeUtc UnixEpoch { get; }
+            = new DateTimeUtc(1970, 1, 1, 0, 0, 0);
+
         public static DateTimeUtc Now
             => new DateTimeUtc(DateTime.UtcNow);
 
@@ -105,5 +114,8 @@ namespace OpenTween
 
         public static bool operator >=(DateTimeUtc a, DateTimeUtc b)
             => a.datetime >= b.datetime;
+
+        public static DateTimeUtc FromUnixTime(long unixTime)
+            => UnixEpoch + TimeSpan.FromTicks(unixTime * TimeSpan.TicksPerSecond);
     }
 }
index bfcfc10..c8f29d9 100644 (file)
@@ -148,7 +148,7 @@ namespace OpenTween
         protected virtual void UpdateRemainMinutes()
         {
             if (this._ApiLimit != null)
-                this.remainMinutes = (this._ApiLimit.AccessLimitResetDate - DateTime.Now).TotalMinutes;
+                this.remainMinutes = (this._ApiLimit.AccessLimitResetDate - DateTimeUtc.Now).TotalMinutes;
             else
                 this.remainMinutes = -1;
         }