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.
Related
I have a GUI working on the front end. But on the back end I have a little problem with my math. Code is trying to calculate how much time has gone with only starting and ending hours. (There are no info on days). So I think I found the way to calculate the hours spent on paper. But in C# I failed I think because of local variable stuff.
float start = float.Parse(textBox1.Text);
float end = float.Parse(textBox2.Text);
float hours_spent = end - start;
if (start > end) {
hours_spent = 24.00f -start + end;
}
First part is working correctly but when I give the start bigger than end, it gives me random numbers.
EDIT: When i gave 14.00 as an input and 13.00 as an output i get -76
and for input 14.00 output 12.00 i get -176 and for 18.50 to 10.25 i get -801. It is not random i can see that too my bad on choosing the words. But i dont get it what is wrong
When i gave 14.00 as an input and 13.00 as an output i get -76
You are parsing in a part of the world where . is not the decimal separator but is a common "group" separator. That is, a number like one hundred thousand plus a quarter is written 100.000,25, and not as it would be in the United States, 100,000.25. Parse assumes that the string is in the format of the current user's locale unless you tell it otherwise.
Therefore you are parsing the strings into values 1400 and 1300. Their difference is -100, which is less than 0, so you add 24 to -100 and get -76.
Same for your other case. You have 1850 and to 1025, subtract them to get -825, add 24 and you get -801.
There's nothing "random" at all here; everything is working as expected.
There is a lesson here: work backwards. You got -76. How'd that happen? You must have added 24 to something. What added to 24 gives you -76? -100. How did we get -100? And so on.
Start over. You should not be parsing floats in the first place. If this is a decimal quantity then you should be parsing a decimal, and if you know that it will always have . as the decimal separator, you should say so when you parse it. (Hint: use the version of TryParse that takes a NumberStyles and set the style correctly.)
If, on the other hand, you know that this is two integers separated by a period, then you should not be parsing it as a decimal or a float. You should be parsing an integer, then a period, then an integer.
If this is hours then a period then minutes, then again, you should not be using any of the above. Use a date and time parser to parse dates and times.
In short: use the right tool for the job you actually have to do.
Other problems with your code:
Use TryParse, not Parse, when dealing with user input. You don't know that there is a valid number in there, but Parse will crash if it gets bad input.
Your math is probably wrong. If someone puts in 100 and 200, do you really want -76 as the output?
Take a step back and ask yourself what the real business process is that you're trying to build here. Write that business process down carefully and then implement that process, not an approximation of it. Your business process probably does not say "parse a float using the rules of the current locale" but that's the code you wrote. Write code that means exactly what you intend it to mean.
UPDATE: Comments on the question indicate just how deep a hole you've gotten yourself into:
If entry time is 13.55 and exit time is 14.05 what should be the expected logical result ? It should be 10 (minutes) or 50 (numeric difference) ?
I am expecting 10 as minutes
Then absolutely you should not be parsing as float or decimal! Parsing as float or decimal is obviously completely wrong because 1.1 and 1.10 are the same value as a number, but nine minutes different if it is "hours.minutes", and you can't tell which case you are in by parsing as a number.
Again, you need to stop writing code, erase everything you've written so far, and start over. You're in a hole: stop digging deeper, fill in the hole, and get back to ground level.
You need to figure out exactly what format your strings are in, and parse exactly that format and nothing else.
So, write a specification that poses and then answers questions about what is allowed and what is not. Are negative values allowed? What if the number of minutes is more than 60? What if the minutes or hours are missing entirely? And so on.
Once you have a specification, write test cases that verify the spec. Then write an implementation, and run your tests. The code is more likely to be correct if you write the tests first.
I'm going to completely ignore providing a didactic answer in favor of trying to sidestep the problem.
Avoid writing your own parsing code. Instead, replace all your TextBoxes with DateTimePickers with Format set to Time. Then pull out the time by calling the .Value.TimeOfDay property. TimeOfDay is a TimeSpan, so it supports simple arithmetic.
Warning: Watch out when pulling these results using the provided properties. For example, 150 minutes can be translated as either 2 .Hours and 30 .Minutes or to 150 .TotalMinutes .
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.
The actual version number of my solution is placed in Properties/AssemblyInfo.cs:
[assembly: AssemblyVersion("1.0.0.*")]
The last part of that number is an askerisk. It will be replaced by an revision number. By the following code in my controller, I am able to get that full version number, including the revision number:
ViewBag.VersionNumber = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
Where does MVC3 save the revision number?
When using the * in the revision number, then the 3rd digit will increment each day, and the 4th will be generated based on time-of-day.
What you're seeing is the 4th digit generated based on time-of-day. You'll notice that after midnight it will reset close to 0.
If you use a version such as "1.0.*", then the 3rd and 4th digits will generate automatically.
The Revision number isn't "Saved" anywhere instead it is just generated each time you build your project (it is written into the assembly as part of the version number but not saved for future builds).
As an aside I noted a behaviour that doesn't seem to be documented anywhere (and caught me out). The Revision number seems to be generated based on the time (and not always date)!
I.e. you have v1.0.0.1234 on Day 1 at 11:00
This changes to v1.0.0.1257 on Day 1 at 11:30
But, on Day 2 at 10:00 you re-build thinking it will change to v1.0.0.1279 or similar but it actually changes to v1.0.0.0950 so producing a "lower" version number that the last build (on Day 1)?!
This doesn't always seem to happen but I would warn against using Revision as a guaranteed value to increment.
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.
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.