I have been trying to use TimeZoneInfo.GetSystemTimeZones in .net4 to replace our old method which uses COM to call into some MFC code. However, I've had to revert to the COM method because GetSystemTimeZones doesn't return all time zones. Being based in the UK and not including GMT Standard Time in our list of options is a problem.
When I look in the registry, I find that GMT Standard Time has a Dynamic DST subkey with no rules defined. I downloaded the .net4 source code and, in TimeZoneInfo.cs, GetSystemTimeZones eventually calls TryCreateAdjustmentRules which appears to return false if the Dynamic DST key has no FirstEntry or LastEntry defined.
//
// loop over all of the "<time_zone_name>\Dynamic DST" hive entries
//
// read FirstEntry {MinValue - (year1, 12, 31)}
// read MiddleEntry {(yearN, 1, 1) - (yearN, 12, 31)}
// read LastEntry {(yearN, 1, 1) - MaxValue }
// read the FirstEntry and LastEntry key values (ex: "1980", "2038")
Int32 first = (Int32)dynamicKey.GetValue(c_firstEntryValue, -1, RegistryValueOptions.None);
Int32 last = (Int32)dynamicKey.GetValue(c_lastEntryValue, -1, RegistryValueOptions.None);
if (first == -1 || last == -1 || first > last) {
rules = null;
return false;
}
As TryCreateAdjustmentRules returns false, TryGetTimeZoneByRegistryKey throws an InvalidTimeZoneException which means GMT Standard Time doesn't get added into the time zone collection. I've tried deleting the empty Dynamic DST subkeys but something adds them back in again (probably Windows Update).
I've done alot of searching but haven't seen anyone else report this problem. I'm not sure whether there is a GetSystemTimeZones fix or whether I can stop the empty Dynamic DST subkey appearing in the first place. Any ideas?
I'm guessing this is just a registry issue.
Something similar is outlined here for WinXP / Server 2003 SP1.
Please see if the following helps:
http://blogs.technet.com/b/dst2007/archive/2007/03/06/missing-time-zones-in-registry.aspx
My guess is you could export the entire registry Key from another machine, and apply it to your problematic box(es).
It turns out that the problem is with our COM object and not with the .NET code. The code to read the registry should only be reading but it mistakenly calls RegCreateKey to optimise multiple calls to the same registry branch.
When the COM object is registered (with admin rights) because of a new version, it loads the time zones and creates Dynamic DST for the local time zone which in my case is GMT/UTC.
Administrators, I guess this question should be marked for deletion.
After looking it over your problem and even running the code you provided in the comments to print out a list of Time Zones I am not able to get GMT to show up on my system. I am running Windows 7 Professional and selecting GMT is just not an option. I know that doesn't solve your problem and you - like a lot of other people - sound like you really need to get this to work with GMT.
However if at all possible, if you see a way to use UTC then I would check out these links:
Windows 7 Lack of Support for GMT
Converting UTC to GMT
Just another possible answer to your problem, is there anyway you can create a wrapper around the UTC values to display GMT? I ask because this problem doesn't seem like it is going to go away anytime soon. Even if you get it to work now - in the future it might break again. If I come up with a method for this I will update my answer.
Related
In C# on Windows Vista - 7 with dot net 4.0 or less
I am trying to compare the values of login time, current time, and the modified time of a file to see which is the greater and which is least. I have found ways to declare and cast these three values but not as the same type. I figured unix epoch made the most since and I seem to be stuck with converting the long format of
File.GetLastWriteTime("time.cs" )
Apparently overflows are a problem, who would have guessed, not my esp. Such a superior os & language. Anyway. Can someone please give me a full example of how to cast return and output the modified time of a file to int32 unix epoch. Or, can some one show me, in full example how to compare the above three values without trolling a log file or the use of jQuery or defining functions or languages beyond the scope of what I have requested. Speed is key and the parameters are required not optional.
The csharp crowd doesn't have the answer? there is a surprise. Well this is about as exact as there being 365 days in a year but for my purpose it will work. Because two forms of builtin not traversal date time isn't enough. For the pleasure of all that is prime and dec ten. A solution:
DateTime dt = File.GetLastWriteTime("time.cs");
var sec = ( ( dt.Year - 1970 )*31536000) + (dt.Month*2592000) + (dt.Day*86400) + (dt.Hour*3600) + (dt.Minute*60) + (dt.Second * 1) - 2592000 - 86400;
I guess for windows this is actually considered efficient. Can anyone tell my why DateTime isn't just considered a string? is base24 replacing base 16 or some thing? Did we add a register to our processor just for msns inefficiencies. Im going with the ladder. Front end convenience is no excuse for back end ugliness. Ill be posting a pure assembly answer next on how to convert gregorian to epoch via means of base 2 and 127 bit addressing... crazy.
I've been searching high and low and can't find an answer to this. How come the TZIs are different??
I've done some digging on MSDN and seen this:
http://msdn.microsoft.com/en-us/library/system.timezoneinfo.findsystemtimezonebyid.aspx
Which explicitly states:
FindSystemTimeZoneById tries to match id to the subkey names of the HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Time Zones branch of the registry under Windows XP and Windows Vista. This branch does not necessarily contain a comprehensive list of time zone identifiers.
So I assume that means it's going to the registry every time?
But then this confuses the issue:
http://msdn.microsoft.com/en-us/library/system.timezoneinfo.utc.aspx
And says:
This is a built-in object; information about this TimeZoneInfo object is not retrieved from the registry.
So it appears my call to FindSystemTimeZoneById() is actually short circuiting and returning TimeZoneInfo.UTC, and not going to the registry at all! This is not idea though because I want the other version's DisplayName. What gives???
This quirk is explained because of the different ways you searched for the timezone. The top one with the full name came from the registry and started life by you using GetSystemTimeZones(), it enumerates the registry keys.
The bottom one was produced by FindSystemTimeZoneById(), it has a short-cut:
public static TimeZoneInfo FindSystemTimeZoneById(string id)
{
if (string.Compare(id, "UTC", StringComparison.OrdinalIgnoreCase) == 0)
{
return Utc;
}
// etc..
}
So you get the pre-baked one with the short name.
I was thinking of changing system's local time to server's time and then use it but I bet there are other ways to do this. I've been trying to find something like a clock in c#, but couldnt find anything. I'm receiving server's time in a DateTime format.
edit:
I need my application to use while working same time server does. I just want to get server's time once and after that, make my application work in a while loop using the time I've obtained from the server. There might be a difference between my system's time and server's time (even 5 seconds) and that's why I want to do this.
It's not entirely clear what you mean, but you could certainly create your own IClock interface which you'd use everywhere in code, and then write an implementation of that which is regularly synchronized with your server (or with NTP).
My Noda Time project already uses the idea of an injectable clock - not for synchronization purposes, but for testability. (A time service is basically a dependency.) Basically the idea is workable :) You may well not find anything which already does this, but it shouldn't be too hard to write. You'll want to think about how to adjust time though - for example, if the server time gets ahead of your "last server time + local time measurements" you may want to slew it gradually rather than having a discrete jump.
This is always assuming you do want it to be local to your application, of course. Another alternative (which may well not be appropriate, depending on your context) is to require that the host runs a time synchronization client (I believe Windows does by default these days) and simply start failing if the difference between your server and the client gets too large. (It's never going to be exactly in sync anyway, or at least not for long - you'll need to allow for some leeway.)
The answer #JonSkeet's provided to synch the times looks good, I just wanted to point out some things.
As #Alexei already said, users require admin privileges to be able to change their local time (in Windows as least), but there may also be other issues that can cause the time to be out of synch (bad internet connection, hacks etc.). This means there is no guarantee that the client time is indeed the same as the server time, so you will at least need to check the time the request was received serverside anyway. Plus there might also be a usability issue at hand here, would I want an application to be able change the time of my own local machine? Hell no.
To sum things up:
Check the time of the request serverside at least
Don't change the time of the client machine but show some kind of indicator in your application
How to handle the indicator in your application can be done in various ways.
Show a clock in your application (your initial idea) that is periodically synched with the server
Show some kind of countdown ("you can submit after x seconds.."), push a resetCountdown request to the clients when a request is received.
Enable a 'send button' or what ever you have, this would work kind of similar to the countdown.
Just remember, it's nearly impossible validate a request such as this clientside. So you have to build in some checks serverside!
I actually wanted to write a comment but it got kind of long.. :)
Okay a bit of necromancy as this is 6 years old, but had to deal with a similar problem for a network game.
Employed a technique I referred to as "marco-polo" for reasons that will be obvious soon. It requires the two clocks to be able to exchange messages, and its accuracy is dependent on how fast they can do that.
Disclaimer: I am fairly certain I am not the first to do this, and that this is the most rudimentary way to synchronize two clocks. Still I didn't find a documented way of doing so.
At Clock B (The clock we're trying to synchronize) we do the following ::
// Log the timestamp
localTime_Marco_Send = DateTime.UtcNow;
// Send that to clock A
SendSyncRequest();
// Wait for an answer
Sleep(..);
At Clock A (the reference clock) we have the following handler ::
// This is triggered by SendSyncRequest
OnReceiveSyncRequest()
{
// We received "Marco" - Send "Polo"
SendSyncReply(DateTime.UtcNow);
}
And back at Clock B ::
// 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;
}
As a result we now have access to a nifty TimeSpan we can subtract from our current local time to estimate the remote time
DateTime estimatedRemoteTime = DateTime.UtcNow - estimatedDT_A_B;
The accuracy of this estimate is subject to the Round Trip Time of send-receive-send-receive, and you should also account for Clock drift (you should be doing this more than once):
Round-trip-time. If it were instant, you'd have the exact dT. If it takes 1 second to come and return, you don't know if the delay was on the sending or the receiving. As a result, your error is 0 < e < RTT, and on average will be RTT/2. If you know send (or receive) takes more than the other, use that to your advantage - the time you received is not the half-time, but is shifted relatively to how long each leg takes
Clock drift. CPU clocks drift, maybe 1s per day. So poll again once potential drift may play an important role.
Your server should always save the time in UTC mode.
You save time in UTC like this in the server:
DateTime utcTime = new DateTime(0, DateTimeKind.Utc);
or:
DateTime utcTimeNow = DateTime.UtcNow;
In the client, when you get the time which is stored in utc you can sonvert it to local time like this:
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);
}
If You want to change your local time zone , here is a code example on how to read time zone to use from config:
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;
}
Is there an alternative to a revision number (incremented int)? I'd like to create a revision tag (or identifier if you like) from date+time (and later convert the tag back to a date time object).
Preferably the revision is as small as possible. CouchDB uses a format like this for revision: 765B7D1C - but I'm uncertain how they made this and if it's even a time stamp.
Any suggestions?
You could use something like this:
DateTime.Now.Subtract(new DateTime(2000, 1, 1)).Days
This returns the number of days since 2000-01-01 (as of today, this would be 3566).
This is similar to what is used in .NET if you specify the assembly version (in AssemblyInfo.cs) as "1.0.*". Of course you could also use another start date, such as the start of your project.
I recently went through the same thought process. I couldn't find a good way to fit it into the signed int that your allowed. Instead I went with Maj.{Year-2000}.{MMdd}.{svn revision}. You could still try and cram the date... here is the issue:
1 year = 365 days = 8760 hours = 525600 minutes. As you can see given a max of 32k the best you can do for the current year is hours. That can record the next 3.5 years worth, so you could do:
int revision = (int) (DateTime.Now - new DateTime(2009, 1, 1)).TotalHours;
... and this will then blow up around Aug, 2012. Or if you use days you be able to store apx 88 years, so you could go with Martin's suggestion safely.
Take a look at VSVersion Manager which is a set of macros for setting version numbers in AssemblyInfo based on date.
The macro is fired on each build.
You can set up a rules for setting revision fields to any of the date elements (month, day, year in different formats), have them increment by one or leave them untouched.
The site includes detailed instructions for installing the macros.
The challenge is: Can you get the date+time of compilation compiled into your program? Preferably in the format you choose, but any format is sufficient, because you can re-format into a "tag" any way you like. (If you cannot re-format it at compile time, you can re-format it beyond recognition at run-time.)
The answer is: There is no direct way. C# has nothing like __DATE__ or __TIME__. The date+time of compilation are completely unavailable at compile-time. If a program wants to know the date+time of its compilation, it can only try to pick them up at run-time, by examining itself. C# creates data structure(s) in and around the compiled program, but none of the fields is available at compile-time, and none is guaranteed to have the date+time of compilation.
Solution 1 (my favorite so far): VS doesn't unconditionally write the compilation date+time into suitably named fields, for the purpose of giving you that information. But it does conditionally write a derivative of the compilation date+time into 2 of the 4 version fields, as a klugey way of putting an automatic incrementing version number on the executable file, if you tell it to. "AssemblyVersion" is a structure of 4 fields ("Major Version", "Minor Version", "Build Number", and "Revision"), which are normally just 4 UInt16 numbers typed in by the programmer (or version control software). But, If you set the fields of AssemblyVersion to a, b, *, and [empty string], and no one changes the last 2, then the compiler overrides the last two to c and d, where c == days and d*2 == seconds since Jan. 1, 2000 at 00:00 (local time, but disregarding daylight saving time) (making a non-human-decodable timestamp, which is visible under File Properties of the file), at the moment it parses AssemblyInfo.cs. These are easily accessed via:
private string DateCompiled()
{
System.Version v = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
// v.Build == days and v.Revision*2 == seconds since Jan. 1, 2000 at 00:00 (midnight, 12:00am). (Local time, but disregards daylight saving time.)
return new DateTime(2000, 1, 1).AddDays(v.Build).AddSeconds(v.Revision * 2).ToString("yyyyMMdd-HHmm (local no DST)");
// "Assembly version" has four UInt16 fields: "Major Version", "Minor Version", "Build Number", and "Revision".
// When Build is "*" and Revision is empty, the compiler overrides them with the encoded date and time.
// AssemblyVersion can be specified in the solution Properties window, Application tab, "Assembly Information..." button and dialog box: Assembly version.
// AssemblyVersion can also be specified in "AssemblyInfo.cs". Example:
// [assembly: AssemblyVersion("2016.11.*")]
// AssemblyFileVersion is optional, defaulting to AssemblyVersion if not specified. (Build is NOT allowed to be "*".)
// Properties of the file (in Windows Explorer) displays AssemblyFileVersion.
// AssemblyVersion can be specified in the solution Properties window, Application tab, "Assembly Information..." button and dialog box: File version.
// AssemblyVersion can also be specified in "AssemblyInfo.cs". Example:
// [assembly: AssemblyFileVersion("1.2.3.4")]
}
If you want File:Properties (in Internet Explorer) to show an arbitrary a.b.c.d version of your choice, you can do that too. File:Properties shows AssemblyFileVersion, which defaults to AssemblyVersion if not specified. You can only specify AssemblyFileVersion in "AssemblyInfo.cs" (just add a new line for it, using the same syntax as AssemblyVersion, except "*" is not allowed). The use of [half of] AssemblyVersion for the encoded date+time of compilation is hidden from that view.
Solution 2: (I don't like it because metadata changes easily and access could be blocked.) The running program finds itself (the .exe file) through the file system and reads its own last-modified date. But the last-modified date is metadata stored in the file system, not the program file. The last-modified date can easily be changed or lost by transfer across time-zones or DST changes via FAT, CDFS, or FTP; lazy FTP servers that do not accept incoming date+time metadata; insane FTP servers that round older timestamps; and file utilities that change metadata on request. And sometimes file permissions get in the way. And the needed procedure varies by operating system. (Even if I had tried this approach, I wouldn't paste code)
Solution 3: (I find it better than Solution 2 because the data cannot change, but worse than Solution 2 because the executable file opens and reads itself as binary data.) "Dustin Aleksiuk recently posted a clever blog entry describing how to retrieve the embedded linker timestamp from the IMAGE_FILE_HEADER section of the Portable Executable header" --https://blog.codinghorror.com/determining-build-date-the-hard-way/ (with code). The blog entry (from March 3, 2005) that it cites is gone (along with the entire blog), but it is archived at http://web.archive.org/web/20060615040705/http://blog.signaleleven.com/index.php?itemid=10
If you are asking about formatting a date, the answers vary according to the data type, the precision (resolution) that you want, the time span that you want to cover, how human-readable or machine-readable it should be and how to address time zone.
Imagine the date and time are 2016-11-08 14:08:12. That is already a string encoding of 19 characters (19 bytes if string, not wstring).
String: I like yyyyMMdd-HHmmss: 20161108-140812. 15 characters. I think it is more human readable without the dashes and colons.
BCD: Int64 stores 16 decimal digits in only 8 bytes, preserving human readability (if viewed as hexadecimal). Choices:
0x0020161108140812 (years 0-799,999; resolution 1s)
0x0201611081408120 (years 0-79,999; resolution 0.1s)
0x2016110814081200 (years 0-7999; resolution 0.01s)
(First digit is limited to 0..7 because Int64 is signed; its maximum value is 0x7fffffffffffffff.)
Decimal: Int64 stores 18.96 decimal digits in only 8 bytes.
0000020161108140812 (years 0-922,337,203; resolution 1s)
0020161108140812000 (years 0-922,337; resolution 0.001s)
(maximum value is 9,223,372,036,854,775,807.)
UInt32 can store the date (8 digits) as BCD or decimal.
0x20161108 (years 0-9999 or 15,999)
0020161108 (years 0-429,496)
Int32 can store the date as BCD or decimal.
0x20161108 (years 0-7999)
0020161108 (years 0-214,748)
There are nearly endless possibilities (if you don't look to a standard).
These are just some of the more human-readable variations.
I have a .net 2.0 C# application in Visual Studio 2005 for which I'd like to automatically generate the correct version build number which should contain a number that allows me to guess the build date of the application.
I tried to use the 'AssemblyInfo Task' tool from Microsoft but by default this tool doesn't work. For today it would generate a build number '090227' which exceeds the maximum of 65535 and thus geneartes an error.
I could also live with a build number which contains the year and the day in the year, like 09001 for January 1 2009...
Do you know any solution for this problem?
Do I have to update the source code for this 'AssemblyInfo Task' or would this be possible to achieve in VS2008 or so?
Thanks for your help.
You'll want to look at msbuildtasks. It is an open source set of msbuild tasks. The module has a task to increment/modify/etc a build number. It's also super easy to use and super easy to extend.
The default automatic build number generated by VS/C#/msbuild is the number of days since 1.1.2000 and the release number is the number of two second increments since midnight, so that you can compute the date and time of the build backwards like this:
new DateTime(2000, 1, 1).AddDays(assemblyName.Version.Build).AddSeconds(assemblyName.Version.Revision*2)
msbuildtasks didn't solve my problem. As explained in the description I need a special format. Also the documentation for msbuildtasks is well... go find it.
I've modified the source code for AssemblyInfo Task by adding a new increment type 'YearAndDay' with my needs:
case IncrementMethod.YearAndDay:
{
DateTime dDate = DateTime.Now;
long buildNumber = dDate.Year % 2000 * 1000;
buildNumber += dDate.DayOfYear;
string newVersionNumber = buildNumber.ToString();
Log.LogMessage(MessageImportance.Low, logMessage, newVersionNumber);
return newVersionNumber;
}
Seemed to be the simplest solution.