{
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 };
}
[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));
}
{
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();
["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) {
["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) {
["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> {
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);
}
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);
}
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]
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>(
.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);
}
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());
+ }
}
}
{
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
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";
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;
{
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
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);
class TestToolStripAPIGauge : ToolStripAPIGauge
{
- public DateTime DateTimeNow = DateTime.Now;
+ public DateTimeUtc DateTimeNow = DateTimeUtc.Now;
protected override void UpdateRemainMinutes()
{
{
using (var toolStrip = new TestToolStripAPIGauge())
{
- var now = DateTime.Now;
+ var now = DateTimeUtc.Now;
toolStrip.DateTimeNow = now;
toolStrip.AutoSize = false;
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)
/// <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;
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);
}
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 =
Limit: new ApiLimit(
item.Value.Limit,
item.Value.Remaining,
- UnixEpoch.AddSeconds(item.Value.Reset).ToLocalTime()
+ DateTimeUtc.FromUnixTime(item.Value.Reset)
)
);
new string[] {
endpoint,
apiLimit.AccessLimitRemain + "/" + apiLimit.AccessLimitCount,
- apiLimit.AccessLimitResetDate.ToString()
+ apiLimit.AccessLimitResetDate.ToLocalTimeString()
});
item.Group = group;
this.ListViewApi.Items.Add(item);
{
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();
}
}
/// </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);
public static bool operator >=(DateTimeUtc a, DateTimeUtc b)
=> a.datetime >= b.datetime;
+
+ public static DateTimeUtc FromUnixTime(long unixTime)
+ => UnixEpoch + TimeSpan.FromTicks(unixTime * TimeSpan.TicksPerSecond);
}
}
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;
}