We're writing a dll that can be accessed by other teams. One of our requirements is that every DateTime passed has a DateTimeKind.Utc.
However, we're not enforcing this requirement which leads to errors. So we were wondering how we can enforce this.
We had a few ideas:
Write an aspect that checks each parameter passed to a method. Throw an exception when the Kind != UTC. This works but does not work when you pass an object that contains a DateTime.
Change all our DateTimes with a custom object, UtcDateTime.
This might work but would need to make sure that we replace every DateTime and all calls to our datetimes. Would look something like this:
public class UtcDateTime
{
private DateTime _dateTime;
public UtcDateTime(DateTime dateTime)
{
if(dateTime.Kind != DateTimeKind.Utc)
{
throw new ArgumentException();
}
_dateTime = dateTime;
}
}
Any better ways to do this?
Change all our DateTimes with a custom object, UtcDateTime.
If you want to go that way and replace DateTime with something else, you might as well use DateTimeOffset, which includes time zone information.
You could use code contracts to enforce this.
Read about them here.
http://msdn.microsoft.com/en-us/library/dd264808(v=vs.110).aspx
As an example, you could use
Contract.Requires(yourDateTime.Kind == DateTime.Utc);
Alternatively, you could enforce the conversion in your method. If it is DateTimeKind.Unspecified, throw.
void Foo(ObjectWithDateTime foo)
{
if (foo.Date.Kind == DateTimeKind.Unspecified) {
throw ....
}
// convert here.
}
Related
I am aware of the standard procedure for displaying a DateTime in a custom format, like so:
MessageBox.Show(dateSent.ToString("dd/MM/yyyy hh:mm:ss"));
However, when I change the variable from a DateTime to a DateTime? to accept null values, I lose the definition for the ToString(string) overload. I need to use DateTime? as I am reading from a database which potentially has null values - if the field in the database has a null value, then I need to assign the variable a null value too.
So I have two questions:
1) Out of curiosity, does anyone know if there is a reason why DateTime? does not contain an overload for ToString(string)?
2) Could anyone suggest an alternative method for what I am trying to achieve?
DateTime? is syntactic sugar for Nullable<DateTime> and that's why it don't have ToString(format) overload.
However, you can access underlying DateTime struct using Value property. But before that use HasValue to check, if the value exists.
MessageBox.Show(dateSent.HasValue ? dateSent.Value.ToString("dd/MM/yyyy hh:mm:ss") : string.Empty)
Instead of having to manually perform a null check every time, you can write an extension method.
public static string ToStringFormat(this DateTime? dt, string format)
{
if(dt.HasValue)
return dt.Value.ToString(format);
else
return "";
}
And use it like this (with whatever string format you want)
Console.WriteLine(myNullableDateTime.ToStringFormat("dd/MM/yyyy hh:mm:ss"));
You can still use
variableName.Value.ToString(customFormat);
DateTime? testDate = (DateTime?)arrayOfObjects[dateObject];
Does that code look ok? I attempted to use the as operator but I got the 'non-nullable' error. What I'm trying to say is that the object I'm choosing from the array is either DateTime or a null DateTime but either can be assigned to testDate.
Doesn't feel right doing it this way, I think I'm missing something obvious.
EDIT: I suppose it's the same as the way I could've adapted the as in the following way:
DateTime? testDate = arrayOfObjects[dateObject] as DateTime?;
Is either line of code the best way of handling potential nulls?
Is either line of code the best way of handling potential nulls?
The second form will silently result in null when the array contains something other than a DateTime. That seems a good reason to use the first.
To the basic question:
am I missing something or is this the typical (or at least an acceptable) approach
It is acceptable but a little obscure maybe, because it is 'hiding' an unboxing operation.
You could use:
DateTime? testDate = null;
if (arrayOfObjects[dateObject] != null)
testDate = (DateTime) arrayOfObjects[dateObject]; // no '?'
But that's verbose. And this particular problem doesn't lend itself well to the conditional operator (?:)
So I would stick with your first version.
DateTime? is a shorter form for another struct
Nullable<DateTime> {
bool HasValue;
DateTime Value;
}
You will never get this type from your DB, so the first line will never cast correctly. The database will provide you with a DateTime value stored in an object variable. Or a null (untyped).
DateTime is a struct, so "as" operator won't work for it. So, simply check for null as follows:
DateTime? testDate = arrayOfObjects[dateObject] == null ? (DateTime?) null : (DateTime)arrayOfObjects[dateObject];
A better approach would be to do something like:
if(arrayOfObjects[dateObject] != null && arrayOfObjects[dateObject] is DateTime)
{
DateTime testDate = (DateTime)arrayOfObjects[dateObject];
// logic here
}
or something like:
DateTime? testDate = null;
if(arrayOfObjects[dateObject] is DateTime)
{
testDate = (DateTime)arrayOfObjects[dateObject];
}
else if (arrayOfObjects[dateObject] is Nullable<DateTime>)
{
testDate = (Nullable<DateTime>)arrayOfObjects[dateObject];
}
Try using Array.ConvertAll method. Below is roughly how it is implemented:
DateTime?[] dates = Array.ConvertAll<object, DateTime?>arrayOfObjects,DateTime);
Note: This is just a rough idea. you can correct it to suit your self.
I have a Datetime object which I take from an XML file (closingDate).
I want to dynamically display all closingDates to the user. However, not all objects in the XML file necessarily contain a dateobject.
How can I do this (pseudocode):
DateTime closingDate = DateTime.Parse(xmlFile.selectSingleNode("Closing_Date")).toString();
and then later, I am writing out an HTML file with:
String fileListHTML += "<li><a href='#'>The file name gets put here</a> (Closed:
"+closingDate+")</li>";
Now, as long as there is a datetime, there is no issue. However, if there is no datetime object (ie: null), I get an error.
Can I somehow do an if statement to say (again, pseudo):
if (closingDate =="")
{
closingDate = "To be determined";
}
I am, of course, getting an error about casting a datetime to string.
Is there a way to do this?
I'm not a fan of turning DateTimes to strings until it is necessary.
You could use a nullable DateTime. Use null to denote it's not set or parsable. Alternatively scratch the nullable approach and use a sentinel such as DateTime.MinValue instead.
This is untested but should get the point across:
DateTime? closingDate;
if (!string.IsNullOrEmpty(myClosingDateString))
{
closingDate = DateTime.Parse(myClosingDateString);
}
// do whatever else you need
// when it comes time to appending ...
if (!closingDate.HasValue) // or check if it's `DateTime.MinValue`
{
fileListHtml += "No closing date";
}
else
{
fileListHtml += closingDate.Value.ToString();
}
I'd caution you to be careful about converting DateTime to strings without considerations to time zones and internationalization (for example, DateTime.Parse() can interpret dates very differently depending on regional settings and/or the culture you pass in).
For simplicity, if you can control the format of the string, I'd suggest using UTC and the ISO 8601 format.
Use DateTime.TryParse instead, here's a sample code showing how it works:
DateTime res;
if ( DateTime.TryParse(str,out res))
{
// Res contain the parsed date and you can do whatever you want with
}
else
{
// str is not a valid date
}
http://msdn.microsoft.com/fr-fr/library/ch92fbc1.aspx
I am using LINQ and have a few properties thats DateTime? type.
If i now want to add the value from a textbox i cant seem to get this to work.
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ScoringLastUpgrade", DbType="Date")]
public System.Nullable<System.DateTime> ScoringLastUpgrade
The textbox i use i have made sure with javascript that the format will be '2011-06-17'
But now when i try to do this:
myObject.ScoringLastUpgrade = Convert.ToDateTime(txtScoringUpgradeDate.Text).ToShortDateString();
I get this error: "Cannot convert type string to DateTime?"
How to do this?
The .ToShortDateString() call is converting it into a string. You should remove that call.
Also, you say you've made sure of the format with javascript. What if the user doesn't have javascript, you should do server-side checks too. Also, since it's in a given format, you can use DateTime.ParseExact or DateTime.TryParseExact (so an invalid format doesn't throw an exception) since its more efficient. (The format string would be "yyyy-MM-dd") i believe.
Don't convert it to string using 'ToShortDateTimeString', just set the result of Convert.ToDateTime:
myObject.ScoringLastUpgrade = Convert.ToDateTime(txtScoringUpgradeDate.Text);
Assuming you've done sufficient validation on txtScoringUpgradeDate.Text?
My preference when dealing with these type conversions is to use the TryParse method, e.g.:
DateTime date;
if (DateTime.TryParse(txtScoringUpgradeDate.Text, out date))
myObject.ScoringLastUpgrade = date;
The Convert.ToDateTime, much like the explicit DateTime.Parse will throw an InvalidCastException when an excepional value occurs. It's better to make your code fault tollerant then needlesly catch an exception.
UPDATE: based on your last comment:
You shouldn't return DateTime.MinValue in this case, as MinValue is less than the supported min value of a datetime column. the CLR DateTime supports a date range down to 0000-01-01, whereas the SQL datetime (as well as the comparative CLR SqlDateTime type) supports a minimum value of 1753-01-01. As it as a nullable DateTime, you should set it to null:
public static DateTime? ToNullableDateTime(this string date)
{
DateTime dateTime;
return (DateTime.TryParse(date, out dateTime))
? (DateTime?)dateTime
: null;
}
The problem is that you have put ToShortDateString() at the end there, effectively converting the DateTime back to a string again. Try removing that part of the line.
In my case (.cshtml):
<td>#item.InvoiceDate.Value.ToShortDateString().ToString()</td>
Where InvoiceDtae is Nullable Date in DB
i'm starting to build a part of a system which will hold a lot of DateTime validations, and a lot of 'if it was done before now' or 'if it will start in an hour etc'.
Usual way to go is to use DateTime.Now to get the actual time.
I predict however, that during unit test that will give me a real headache because i will have to setup my testdata for the time when the test will run in stead of use a default set of test data.
So i thought: why not use my own 'now' so i can set the current datetime to any moment in time.
As i don't want to set the testservers internal clock i was thinking about this solution, and i was wondering what you think of it.
Base thought is that i use my own DateTime class.
That class gives you the current datetime, but you can also set your own time from outside.
public static class MyDateTime
{
private static TimeSpan _TimeDifference = TimeSpan.Zero;
public static DateTime Now
{
get
{
return DateTime.Now + _TimeDifference;
}
}
public static void SetNewNow(DateTime newNow)
{
_TimeDifference = newNow - DateTime.Now;
}
public static void AddToRealTime(TimeSpan timeSpan )
{
_TimeDifference = timeSpan;
}
public static void SubtractFromRealTime(TimeSpan timeSpan)
{
_TimeDifference = - timeSpan;
}
}
Some time ago i already read something about it. A short search for mock DateTime.Now with your favorite search engine should reveal enough links.
This seems to look quite interesting:
http://blog.typemock.com/2009/05/mockingfaking-datetimenow-in-unit-tests.html
what do u mean ?
if u need any specialization, so u can use Extension methods !
easily write an extension method for DateTime class and do whatever u need.