我在考虑将系统的本地时间更改为服务器的时间,然后使用它,但我敢打赌还有其他方法可以做到这一点。我一直试图在c#中找到类似时钟的东西,但找不到任何东西。我正在以DateTime格式接收服务器的时间。
编辑: 我需要我的应用程序使用同时服务器工作。我只想获得服务器的时间一次,之后,使用我从服务器获得的时间使我的应用程序在while循环中工作。我的系统时间和服务器时间(甚至5秒)之间可能存在差异,这就是我想要这样做的原因。
答案 0 :(得分:4)
你的意思并不完全清楚,但是你当然可以创建自己的IClock
接口,你可以在代码中的任何地方使用它,然后编写一个与你的服务器定期同步的接口(或者NTP)。
我的Noda Time项目已经使用了可注射时钟的概念 - 不是出于同步目的,而是出于可测试性。 (时间服务基本上是一种依赖。)基本上这个想法是可行的:)你可能找不到任何已经做到这一点的东西,但它写起来应该不会太难。您可能想要考虑如何调整时间 - 例如,如果服务器时间超过“上次服务器时间+本地时间测量”,您可能希望逐渐转换它而不是进行离散跳转。
这总是假设您做希望它在您的应用程序中是本地的,当然。另一个替代方案(可能不合适,取决于您的上下文)是要求主机运行时间同步客户端(我相信 Windows默认情况下这些天)并且如果差异则只是开始失败服务器和客户端之间的关系太大了。 (无论如何,它永远不会完全同步,或者至少不会很长时间 - 你需要允许一些余地。)
答案 1 :(得分:2)
答案@ JonSkeet提供的同步时间看起来不错,我只是想指出一些事情。
正如@Alexei已经说过的,用户需要管理员权限才能更改他们的本地时间(至少在Windows中),但也可能存在其他可能导致时间不同步的问题(糟糕的互联网连接,黑客等)。这意味着无法保证客户端时间确实与服务器时间相同,因此您至少需要检查服务器端接收请求的时间。此外,这里可能还有可用性问题,我是否希望应用程序能够更改我自己的本地计算机的时间?没有。
总结一下:
如何在应用程序中处理指标可以通过各种方式完成。
请记住,几乎不可能验证此客户端之类的请求。所以你必须在服务器端内置一些检查!
我其实想写评论,但它有点长......:)
答案 2 :(得分:1)
好吧,因为它已经6岁了,但是不得不处理类似的网络游戏问题。
采用了一种我称为“ marco-polo”的技术,其原因很快就会显现出来。它要求两个时钟能够交换消息,而其准确性取决于它们可以做到的速度。
免责声明:我可以肯定我不是第一个这样做的人,这是使两个时钟同步的最基本的方法。仍然我没有找到记录在案的方法。
在时钟B(我们尝试同步的时钟)处,我们执行以下操作::
git@github.com:YourName/RepoName.git
在时钟A(参考时钟)处,我们有以下处理程序::
// Log the timestamp
localTime_Marco_Send = DateTime.UtcNow;
// Send that to clock A
SendSyncRequest();
// Wait for an answer
Sleep(..);
然后回到时钟B ::
// This is triggered by SendSyncRequest
OnReceiveSyncRequest()
{
// We received "Marco" - Send "Polo"
SendSyncReply(DateTime.UtcNow);
}
因此,我们现在可以访问一个漂亮的TimeSpan,我们可以从当前本地时间中减去该时间以估算远程时间
// This is triggered by SendSyncReply
OnReceiveSyncReply(DateTime remoteHalfTime)
{
// Log the time we received it
DateTime localTime_Polo_Receive = DateTime.UtcNow;
// The remote time is somewhere between the two local times
// On average, it will be in the middle of the two
DateTime localHalfTime = localTime_Marco_Send +
(localTime_Polo_Receive - localTime_Marco_Send) / 2;
// As a result, the estimated dT from A to B is
TimeSpan estimatedDT_A_B = localHalfTime - remoteHalfTime;
}
此估计的准确性取决于发送-接收-发送-接收的往返时间,并且您还应该考虑时钟漂移(您应该多次这样做):
答案 3 :(得分:0)
您的服务器应始终以UTC模式保存时间 您可以在服务器中以这样的方式节省UTC时间:
DateTime utcTime = new DateTime(0, DateTimeKind.Utc);
或:
DateTime utcTimeNow = DateTime.UtcNow;
在客户端,当你得到存储在utc中的时间时,你可以将其转换为当地时间,如下所示:
public DateTime ToLocalTime(DateTime utcTime)
{
//Assumes that even if utcTime kind is no properly deifned it is indeed UTC time
DateTime serverTime= new DateTime(utcTime.Ticks, DateTimeKind.Utc);
return TimeZoneInfo.ConvertTimeFromUtc(serverTime, m_localTimeZone);
}
如果您想更改本地时区,以下是有关如何从配置中读取时区的代码示例:
string localTimeZoneId = sysParamsHelper.ReadString(LOCAL_TIME_ZONE_ID_KEY, LOCAL_TIME_ZONE_DEFAULT_ID);
ReadOnlyCollection<TimeZoneInfo> timeZones = TimeZoneInfo.GetSystemTimeZones();
foreach (TimeZoneInfo timeZoneInfo in timeZones)
{
if(timeZoneInfo.Id.Equals(localTimeZoneId))
{
m_localTimeZone = timeZoneInfo;
break;
}
}
if (m_localTimeZone == null)
{
m_logger.Error(LogTopicEnum.AMR, "Could not find time zone with id: " + localTimeZoneId + " . will use default time zone (UTC).");
m_localTimeZone = TimeZoneInfo.Utc;
}