I have searched around but have yet to find a satisfying answer for my issue:
Overview: I am working on a small app that uses several DateTime fields into a single table using WCF. We are trying to eliminate null fields in all of our tables. Up until now, whenever we are converting a datetime field selected from a table we first verify that it is null before we display or otherwise "use" it. If the value is NULL, we substitute DateTime.MinValue for the value. Since we are now removing the nullable aspect of all fields, we need to insert a common value representing null; since DateTime.MinValue() is substituted everywhere in the code, it seems like a viable value to put into the field as a null substitute.
The problem: Inserting a DateTime.MinValue() causes the generic "problem executing this request" error.
Solution? : As has been documented elsewhere, the DateTime.MinValue() has an unspecified DateTimeKind so... we add the ToUniversalTime call, as in :
DateTime nullDate = DateTime.MinValue.ToUniversalTime(); // 1/1/0001 6:00:00 AM
This doesn't work, perhaps because of some "acceptable range" setting within Date conversions on WCF?
Noted in the comment is the resulting value of "1/1/0001 6:00 am". The odd 6:00am or the year "1" aside, that seems fine. (Considering the past of default years like 12:00 AM 1970 are still fairly standard, but I digress...)
Yes, I know that DateTime is not C#, it's .NET. I'm also aware that WCF has some form of "min" and "max" times allowed within its conversion constraints. I don't know how to set those (nor do I know how to set the VerboseMessages bit; I'm fairly new to WCF.)
The suggestion to manually create a new field value that converts nicely into the table is viable, and it works:
DateTime nullDate = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
(BTW, If we use the year 1 instead of 1970 (for example) the insert will also fail.)
Even if we were to use the above nullDate as a workable substitute... the problem is that everywhere in the code we are still evaluating against DateTime.MinValue() representing a null date, and those two dates aren't quite the same.
The only viable solution that I can think of is to override or otherwise create an extended class from DateTime to create a common NullDate and modify all the code accordingly.
Does anyone see a good alternative? Does anyone know a solution to inserting the System.DateTime.MinValue() into a WCF table such as altering the acceptable boundries of a good/bad date?
I feel like I'm going to have to bite the bullet and change all references to MinValue... I'm trying to avoid that because it doesn't follow any sort of standard logical thought in evaluating "default" values.
Suggestions anyone?
It depends on the database you are using to store the data. SQL Server, for example, has a minimum date of 1/1/1753, see MSDN. I am not sure about Oracle.
If you Have to use a magic date, you can use that, or something else specific (I use 10 December 1815 in honor of the Lady Ada Lovelace, the first programmer). Generally speaking, if you have a situation where you have no known value, the data store should represent the value as 'null.' Now in practice, that's not always viable. What you could do is refactor the nullable columns into a subtable, and only include a child record when you in fact have something to record.
Related
I often find myself working with databases with nullable date fields so other return something along the lines of select coalesce( t.dt, cast( '0001-01-01' as date) ) from t (for sql server) and implicitly treating LocalDate as a unsigned value in my code. LocalDate defines a MinIsoValue and MaxIsoValue defining the smallest and biggest value that can be represented. MinIsoValue is defined as -9998-01-01 obviously stating LocalDate is a signed value. Usually negative dates don't really make sense in my problem domain hence that I refer to 0001-01-01 as "the beginning of time" in most cases.
My questions are:
Why is there no LocalDate.Zero? If the min and max are demarcated I think it would make sense to define "the middle" or "zero" as the point from where the sign starts to matter.
I can't be the only one who has dealt with this but I can't really find any super useful information on how to deal with this. I've tried looking in the NodaTime newsgroup, tickets and SO questions. How do other people solve this? In the case of a database query just use '-9998-01-01' instead of '0001-01-01'? Are there better solutions?
Most of the software I'm writing doesn't need negative dates, and in most of my cases it wouldn't make sense and would like an exception if it does happen. Does a unsigned version of LocalDate make sense?
(I'm using LocalDate as an example here, same applies to LocalDateTime. Not to sure about LocalTime as I never have to reason at that low of a resolution about time.)
LocalDate.Zero doesn't really have any particularly special meaning - it just happens to be where BCE becomes CE. You can easily create your own static property for it though. (I don't remember ever seeing a feature request for this.)
As Sweeper said, it's not that LocalDate is "signed" - the "absolute year zero" is pretty arbitrary, and the year 1 in one calendar will often be a different year in a different calendar. I strongly suspect that in the vast majority of problem domains where the year 1BCE isn't relevant, the year 1CE isn't relevant either... if you're only thinking about "modern dates" then you'll probably have a cut-off of 1800CE or later. If you're actually dealing with historical dates that go as far back as 1CE, then it's pretty likely you need to handle 1BCE too.
I suspect you're fine to just keep writing database queries that coalesce null to 0001-01-01, and if you want to make sure you don't have any dates earlier than that, you can just use value = LocalDate.Max(value, YourConstantClass.MinLocalDate) or similar to "clamp" it.
We have a Scala/Java back end that is generating the equivalent of DateTime.MaxValue in .NET.
I am sent the following date as a string "9999-12-31T23:59:59.999999999Z".
If I used DateTime.TryParse("9999-12-31T23:59:59.999999999Z", out var dateTime), then it throws an ArgumentOutOfRangeException (The added or subtracted value results in an un-representable DateTime.Parameter name: value).
I didn't expect this, since I was calling TryParse. Perhaps returning false would have been more intuitive?
If I reduce the year, I can see .NET is rolling the date over to the following day, which obviously wont work on a max date/time!
DateTime.TryParse("9998-12-31T23:59:59.999999999Z", out var dateTime);
dateTime.ToString().Dump();
Outputs: 01/01/9999 00:00:00
If I reduce the precision of the ms by 2, then it works:
DateTime.TryParse("9998-12-31T23:59:59.9999999Z", out var dateTime);
dateTime.ToString().Dump();
Outputs: 31/12/9998 23:59:59
This really looks like a bug in .NET? Is this expected behaviour?
Passing Min/Max/Infinity and etc. values between different platforms is a bad idea. Each platform might have its own representation of special values (not only dates). Therefore the only valid option is to pass epoch values (milliseconds options are preferable in most cases), since they are known to the both parties.
If the above is impossible for some reason then you have two ugly options:
Replace special values in your Scala/Java output with your own "encoding". For example as "MaxValue", or take your pick as your see fit. On the .Net side you will detect special values and translate them accordingly.
Insert some simple preprocessing into your .Net code. For example check
"9999-12-31T23:59:59.999999999".StartsWith("9999")
for max values.
You have too many nines in your string. The exception you observing is the precision issue.
Try doing the following:
DateTime.MaxValue.ToString("o")
it will result in "9999-12-31T23:59:59.9999999" rather than "9999-12-31T23:59:59.999999999Z", i.e. two less nines at the end.
Use "9999-12-31T23:59:59.9999999Z" as an input and it will parse successfully into DateTime.MaxValue.
PS: TryParse will also convert this value to your local timezone, which I assume is not somewhat you would anticipate. Use extended version instead:
DateTime.TryParse("9999-12-31T23:59:59.9999999Z", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var dateTime);
Adding DateTimeStyles.AdjustToUniversal as argument fix it for .NET Framework
e.g. for Windows Powershell:
$d = [DateTime]::Parse("9999-12-31T23:59:59.9999999Z", $null, 16)
Get-Date $d
Say there is some code that compares a DateTime object with a DateTime object that has been saved and returned from SQL Server, stored in a DATETIME object.
The comparison is done on hh:mm:ss-equality, but it is possible that SQL Server 'changes' the second component when saved which makes the comparisons fail ~1.5/1000 of the time or so.
This is because SQL Server will round/truncate this value when saved in the database as a DATETIME value:
datetime values are rounded to increments of .000, .003, or .007 seconds..
Is there a (standard) C#/.NET function that does the same rounding?
The primary goal of this question is to normalize the value prior to saving, for use in comparisons. That is, F(original) == F(saved) should always be true.
The final goal overall is to ensure the values are saved 'within the correct second', such that hh:mm:01.999 is stored as hh:mm:01.997. This would allow the hh:mm:ss-equality comparisons to be reliable regardless of if done to the original DateTime values or restored values. In this case, original.Second == F(original).Second should always be true as well.
For better or worse, one widely-used assumption is the comparison is done per hh:mm:ss, so a simple epsilon-compare of 2 milliseconds is out; although I wouldn't be opposed to a strongly-argued for comparison function that might also solve the final goal.
The SqlDateTime structure stores date/time values in the same way as SQL Server's datetime type. It provides conversions from and to the .NET DateTime type, and rounds when the conversion is performed.
Note that you have contradictory requirements in your question. You say you want the same rounding as SQL Server. You also say you want the rounding to never change the "second" component. You can't have it both ways. If you need the "second" component to not change, you may need to implement that yourself. You can check after the conversion has been done whether the second changed, and then restore it, or you may implement the conversion yourself to always round down.
Note up front, my question turns out to be similar to SO question 1668172.
This is a design question that surely must have popped up for others before, yet I couldn't find an answer that fits my situation. I want to record date-of-birth in my application, with several 'levels' of information:
NULL value, i.e. DoB is unkown
1950-??-?? Only the DoB year value is known, date/month aren't
????-11-23 Just a month, day, or combination of the two, but without a year
1950-11-23 Full DoB is known
The technologies I'm using for my app are as follows:
Asp.NET 4 (C#), probably with MVC
Some ORM solution, probably Linq-to-sql or NHibernate's
MSSQL Server 2008, at first just Express edition
Possibilities for the SQL bit that crossed my mind so far:
1) Use one nullable varchar column e.g. 1950-11-23, and replace unkowns with 'X's, e.g. XXXX-11-23 or 1950-XX-XX
2) Use three nullable int columns e.g. 1950, 11, and 23
3) Use an INT column for year, plus a datetime column for full known DoBs
For the C# end of this problem I merely got to these two options:
A) Use a string property to represent DoB, convert only for view purposes.
B) Use a custom(?) struct or class for DoB with three nullable integers
C) Use a nullable DateTime alongside a nullable integer for year
The solutions seem to form matched pairs at 1A, 2B or 3C. Of course 1A isn't a nice solution, but it does set a baseline.
Any tips and links are highly appreciated. Well, if they're related, anyhow :)
Edit, about the answers: I marked one answer as accepted, because I think it will work for me. It's worth looking at the other answers too though, if you've stumbled here with the same question.
The SQL Side
My latest idea on this subject is to use a range for dates that are uncertain or can have different specificity. Given two columns:
DobFromDate (inclusive)
DobToDate (exclusive)
Here's how it would work with your scenarios:
Specificity DobFromDate DobToDate
----------- ----------- ----------
YMD 2006-05-05 2006-05-06
YM 2006-05-01 2006-06-01
Y 2006-01-01 2007-01-01
Unknown 0000-01-01 9999-12-31
-> MD, M, D not supported with this scheme
Note that there's no reason this couldn't be carried all the way to hour, minute, second, millisecond, and so on.
Then when querying for people born on a specific day:
DECLARE #BornOnDay date = '2006-05-16'
-- Include lower specificity:
SELECT *
FROM TheTable
WHERE
DobFromDate <= #BornOnDay
AND #BornOnDay < DobToDate;
-- Exclude lower specificity:
SELECT *
FROM TheTable
WHERE
DobFromDate = #BornOnDay
AND DobToDate = DateAdd(Day, 1, #BornOnDay);
This to me has the best mix of maintainability, ease of use, and expressive power. It won't handle loss of precision in the more significant values (e.g., you know the month and day but not the year) but if that can be worked around then I think it is a winner.
If you will ever be querying by date, then in general the better solutions (in my mind) are going to be those that preserve the items as dates on the server in some fashion.
Also, note that if you're looking for a date range rather than a single day, with my solution you still only need two conditions, not four:
DECLARE
#FromBornOnDay date = '2006-05-16',
#ToBornOnDay date = '2006-05-23';
-- Include lower specificity:
SELECT *
FROM TheTable
WHERE
DobFromDate < #ToBornOnDay
AND #FromBornOnDay < DobToDate;
The C# Side
I would use a custom class with all the methods needed to do appropriate date math and date comparisons on it. You know the business requirements for how you will use dates that are unknown, and can encode the logic within the class. If you need something before a certain date, will you use only known or unknown items? What will ToString() return? These are things, in my mind, best solved with a class.
I like the idea of 3 int nullable columns and a struct of 3 nullable int in C#.
it does take some effort in db handling but you can avoid parsing around strings and you can also query with SQL directly by year or year and month and so on...
Whatever you do is going to be messy DB wise. For consumers of these kind of dates, I would write a special class/struct which encapsulates what sort of date it is (I'd probably call it something like PartialDate), to make it easier to deal with for consumers- much like Martin Fowler advocates a Money Class.
If you expose a DateTime directly in C#, this could lead to confusion if you had a "date" of ????-11-23 and you wanted to determine if the customer was over 18 for example- how would you default the date, how would the consumer know that part of the date was invalid etc...
The added benefit of having a PartialDate is it will allow other people reading your code to quickly realise that they are not normal, complete dates and should not be treated as such!
Edit
Thinking about the Partial data concept some more, I decided to Google. I found that There is the concept of Partial on Joda time and an interesting PDF on the topic, which may or may not be useful to you.
Interesting problem...
I like solution 2B over solution 3C because with 3C, it wouldn't be normalized... when you update one of the ints, you'd have to update the DateTime as well or you would be out of sync.
However, when you read the data into your C# end, I'd have a property that would roll up all the ints into a string formatted like you have in solution 1 so that it could easily be displayed.
I'm curious what type of reporting you'll need to do on this data... or if you'll simply be storing and retrieving it from the database.
I would not worry to much about how to store the date, I would still store the date within a datetime field, BUT, if knowing if some part of the date was not populated, I would have flags for each section of the date that is not valid, so your schema would be:
DBODate as Date
DayIsSet as Bit
MonthIsSet as Bit
YearIsSet as Bit.
That way you can still implement all the valid date comparisons, and still know the precision of the date you are working on. (as for the date, I would always default to the missing portion as the min of that value: IE Month default is January, day is the first, year is 1900 or something).
Obviously, all of the solutions mentioned above do represent some kind of compromise.
Therefore, I would recommend to think carefully which of the 'levels' is the most likely one and optimize for that. Afterwards go for proper exception handling for the other rare cases.
I don't know whether reporting is an issue for you right now or may be later, but you might consider that as third dimension apart from the DB / C# issues.
In our C# project we have the need for representing a date without a time.
I know of the existence of the DateTime, however, it incorporates a time of day as well.
I want to make explicit that certain variables and method-arguments are date-based.
Hence I can't use the DateTime.Date property
What are the standard approaches to this problem?
Why is there no Date class in C#?
Does anyone have a nice implementation using a struct and maybe some extensionmethods on DateTime and maybe implementing some operators such as == and <, > ?
Allow me to add an update to this classic question:
DateOnly (and TimeOnly) types have been added to .NET 6, starting with Preview 4. See my other answer here.
Jon Skeet's Noda Time library is now quite mature, and has a date-only type called LocalDate. (Local in this case just means local to someone, not necessarily local to the computer where the code is running.)
I've studied this problem significantly, so I'll also share several reasons for the necessity of these types:
There is a logical discrepancy between a date-only, and a date-at-midnight value.
Not every local day has a midnight in every time zone. Example: Brazil's spring-forward daylight saving time transition moves the clock from 11:59:59 to 01:00:00.
A date-time always refers to a specific time within the day, while a date-only may refer to the beginning of the day, the end of the day, or the entire range of the day.
Attaching a time to a date can lead to the date changing as the value is passed from one environment to another, if time zones are not watched very carefully. This commonly occurs in JavaScript (whose Date object is really a date+time), but can easily happen in .NET also, or in the serialization as data is passed between JavaScript and .NET.
Serializing a DateTime with XML or JSON (and others) will always include the time, even if it's not important. This is very confusing, especially considering things like birth dates and anniversaries, where the time is irrelevant.
Architecturally, DateTime is a DDD value-object, but it violates the Single Responsibly Principle in several ways:
It is designed as a date+time type, but often is used as date-only (ignoring the time), or time-of-day-only (ignoring the date). (TimeSpan is also often used for time-of-day, but that's another topic.)
The DateTimeKind value attached to the .Kind property splits the single type into three, The Unspecified kind is really the original intent of the structure, and should be used that way. The Utc kind aligns the value specifically with UTC, and the Local kind aligns the value with the environment's local time zone.
The problem with having a separate flag for kind is that every time you consume a DateTime, you are supposed to check .Kind to decide what behavior to take. The framework methods all do this, but others often forget. This is truly a SRP violation, as the type now has two different reasons to change (the value, and the kind).
The two of these lead to API usages that compile, but are often nonsensical, or have strange edge cases caused by side effects. Consider:
// nonsensical, caused by mixing types
DateTime dt = DateTime.Today - TimeSpan.FromHours(3); // when on today??
// strange edge cases, caused by impact of Kind
var london = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
var paris = TimeZoneInfo.FindSystemTimeZoneById("Romance Standard Time");
var dt = new DateTime(2016, 3, 27, 2, 0, 0); // unspecified kind
var delta = paris.GetUtcOffset(dt) - london.GetUtcOffset(dt); // side effect!
Console.WriteLine(delta.TotalHours); // 0, when should be 1 !!!
In summary, while a DateTime can be used for a date-only, it should only do so when when every place that uses it is very careful to ignore the time, and is also very careful not to try to convert to and from UTC or other time zones.
I suspect there is no dedicate pure Date class because you already have DateTime which can handle it. Having Date would lead to duplication and confusion.
If you want the standard approach look at the DateTime.Date property which gives just the date portion of a DateTime with the time value set to 12:00:00 midnight (00:00:00).
I've emailed refsrcfeedback#microsoft.com and that's their answer
Marcos, this is not a good place to ask questions like these. Try http://stackoverflow.com
Short answer is that you need a model to represent a point in time, and DateTime does that, it’s the most useful scenario in practice. The fact that humans use two concepts (date and time) to mark points in time is arbitrary and not useful to separate.
Only decouple where it is warranted, don’t do things just for the sake of doing things blindly. Think of it this way: what problem do you have that is solved by splitting DateTime into Date and Time? And what problems will you get that you don’t have now? Hint: if you look at DateTime usages across the .NET framework: http://referencesource.microsoft.com/#mscorlib/system/datetime.cs#df6b1eba7461813b#references
You will see that most are being returned from a method. If we didn’t have a single concept like DateTime, you would have to use out parameters or Tuples to return a pair of Date and Time.
HTH,
Kirill Osenkov
In my email I'd questioned if it was because DateTime uses TimeZoneInfo to get the time of the machine - in Now propriety. So I'd say it's because "the business rules" are "too coupled", they confimed that to me.
I created a simple Date struct for times when you need a simple date without worrying about time portion, timezones, local vs. utc, etc.
https://github.com/claycephus/csharp-date
System.DateOnly and System.TimeOnly types were recently added to .NET 6, and are available in the daily builds.
They were included with the .NET 6 Preview 4 release.
See https://github.com/dotnet/runtime/issues/49036
They are in the .NET source code here:
https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/DateOnly.cs
https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/TimeOnly.cs
I've blogged about them here.
If you need to run date comparisons then use
yourdatetime.Date;
If you are displaying to the screen use
yourdatetime.ToShortDateString();
Allow me to speculate: Maybe it is because until SQL Server 2008 there was no Date datatype in SQL so it would be hard so store it in SQL server?? And it is after all a Microsoft Product?
Who knows why it's that way. There are lots of bad design decisions in the .NET framework. However, I think this is a pretty minor one. You can always ignore the time part, so even if some code does decide to have a DateTime refer to more than just the date, the code that cares should only ever look at the date part. Alternatively, you could create a new type that represents just a date and use functions in DateTime to do the heavy lifting (calculations).
Why? We can only speculate and it doesn't do much to help solve engineering problems. A good guess is that DateTime contains all the functionality that such a struct would have.
If it really matters to you, just wrap DateTime in your own immutable struct that only exposes the date (or look at the DateTime.Date property).
In addition to Robert's answer you also have the DateTime.ToShortDateString method. Also, if you really wanted a Date object you could always use the Adapter pattern and wrap the DateTime object exposing only what you want (i.e. month, day, year).
There is always the DateTime.Date property which cuts off the time part of the DateTime. Maybe you can encapsulate or wrap DateTime in your own Date type.
And for the question why, well, I guess you'll have to ask Anders Heljsberg.
Yeah, also System.DateTime is sealed. I've seen some folks play games with this by creating a custom class just to get the string value of the time as mentioned by earlier posts, stuff like:
class CustomDate
{
public DateTime Date { get; set; }
public bool IsTimeOnly { get; private set; }
public CustomDate(bool isTimeOnly)
{
this.IsTimeOnly = isTimeOnly;
}
public string GetValue()
{
if (IsTimeOnly)
{
return Date.ToShortTimeString();
}
else
{
return Date.ToString();
}
}
}
This is maybe unnecessary, since you could easily just extract GetShortTimeString from a plain old DateTime type without a new class
Because in order to know the date, you have to know the system time (in ticks), which includes the time - so why throw away that information?
DateTime has a Date property if you don't care at all about the time.
If you use the Date or Today properties to get only the date portion from the DateTime object.
DateTime today = DateTime.Today;
DateTime yesterday = DateTime.Now.AddDays(-1).Date;
Then you will get the date component only with the time component set to midnight.