'Trying to implement NTP Client using Managed C++ but getting date from 1899 using time.windows.com
I am trying to implement a code to get time from time.windows.com but it returns a weird date (year of the date I get is 1899). Since the same servers work for my unmanaged C++ code using WinSock, I can imagine that something must be wrong with my code itself. Can someone look at my code below and tell me what I am doing wrong?
typedef unsigned int uint;
typedef unsigned long ulong;
long GetTimestampFromServer()
{
System::String^ server = L"time.windows.com";
array<unsigned char>^ ntpData = gcnew array<unsigned char>(48);
ntpData[0] = 0x1B;
array<System::Net::IPAddress^>^ addresses = System::Net::Dns::GetHostEntry(server)->AddressList;
System::Net::IPEndPoint^ ipEndPoint = gcnew System::Net::IPEndPoint(addresses[0], 123);
System::Net::Sockets::Socket^ socket = gcnew System::Net::Sockets::Socket
(
System::Net::Sockets::AddressFamily::InterNetwork,
System::Net::Sockets::SocketType::Dgram,
System::Net::Sockets::ProtocolType::Udp
);
try
{
socket->Connect(ipEndPoint);
socket->ReceiveTimeout = 3000;
socket->Send(ntpData);
socket->Receive(ntpData);
socket->Close();
}
catch (System::Exception^ e)
{
System::Console::WriteLine(e->Message);
return 0;
}
const System::Byte serverReplyTime = 40;
ulong intPart = System::BitConverter::ToUInt32(ntpData, serverReplyTime);
ulong fractPart = System::BitConverter::ToUInt32(ntpData, serverReplyTime + 4);
intPart = SwapEndianness(intPart);
fractPart = SwapEndianness(fractPart);
long long milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);
System::DateTime networkDateTime = (gcnew System::DateTime(1900, 1, 1, 0, 0, 0, System::DateTimeKind::Utc))->AddMilliseconds((long)milliseconds);
std::cout << ConvertToTimestamp(networkDateTime);
return 0;
}
static uint SwapEndianness(ulong x)
{
return (uint)(((x & 0x000000ff) << 24) +
((x & 0x0000ff00) << 8) +
((x & 0x00ff0000) >> 8) +
((x & 0xff000000) >> 24));
}
long ConvertToTimestamp(System::DateTime value)
{
System::TimeZoneInfo^ NYTimeZone = System::TimeZoneInfo::FindSystemTimeZoneById(L"Eastern Standard Time");
System::DateTime NyTime = System::TimeZoneInfo::ConvertTime(value, NYTimeZone);
System::TimeZone^ localZone = System::TimeZone::CurrentTimeZone;
System::Globalization::DaylightTime^ dst = localZone->GetDaylightChanges(NyTime.Year);
NyTime = NyTime.AddHours(-1);
System::DateTime epoch = System::DateTime(1970, 1, 1, 0, 0, 0, 0).ToLocalTime();
System::TimeSpan span = (NyTime - epoch);
return (long)System::Convert::ToDouble(span.TotalSeconds);
}
Solution 1:[1]
This is largely a guess, but:
intPart * 1000
It has been about 3.8 billion seconds since 1900. In order to store that number, all 32 bits of the ulong are used. Then you multiply by 1000, without up-casting first. This keeps the result as a 32-bit integer, but it overflows, so your data is destroyed.
To fix, cast to a 64-bit integer first, before converting to milliseconds. Or don't bother converting, just call AddSeconds directly.
That said, you could have a networking problem and are getting all zeros as your result, which would be January 1 1900, but then you're converting to Eastern Standard Time, which is a 5 hour offset, which would be 7:00 PM on December 31, 1899.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
