I'd like to represent dates with different precisions (accuracies). Ideally I can use the DateTime datatype to store the date information though it doesn't come with a precision setting. For example, I have the date "1/1/2015", but depending on its precision it will be understood to be:
an exact date: 1 JAN 2015
month and year only: JAN 2015
year only: 2015
The precision is needed for both UI formatting as well as business logic hence I don't like to use the .NET out of the box formatting options that come with DateTimeFormatInfo or others - they have a different purpose.
Consequently, there is my own solution that is essentially an enumeration ...
public enum DateTimePrecision
{
DayMonthYear = 0,
MonthYear,
Year,
...
}
... that goes with the date (struct or class) ...
public class MySuperDupaAwesomeDateTime
{
public DateTime Date { get; set; }
public DateTimePrecision Precision { get; set; }
}
Alternatively, I could build my own custom DateTime of course.
Anyway, this is like re-inventing something that feels so common and must be out there already. Can anybody think of an improvement of the above approach or knows about a .NET Framework feature? I am not looking for a library or anything, but a solution that comes straight out of .NET.
DateTime has some identifiers for Month and Year that are integers. Use them and format it into a String.
If you need more accuracy than just a day, DateTime also has other identifiers for Seconds, Minutes, Hours, Milliseconds... check the attributes for yourself!
After you get the integer values for them, you can even start to do calculations for getting elapsed time for something to complete (by getting a DateTime and setting it for Now when you start and getting another DateTime and setting that for Now when it's over, then use the name of second object.Subtract( name of the first object ), or .Add())!
Related
Given a C# website using ASP.NET Core Mvc using SQL Server and EF Core.
For a hobby project I'm looking in old newspapers, documents and searching for specific buildings. Each time I find information of such a building I try to write down date information. So that I can keep track in which period this building was there.
So let's say I come across Build X and see date 1880. I write down the date 1880.
A few weeks later I come across Building X again and see date: 16/03/1877. I know now that the building was there for sure from 16/03/1877 till 1880.
Period: 16/03/1877 - 1880
Now some buildings don't have any date info.
Some buildings have only a single date (maybe with extra research another one could be found)
Some buildings might have information that it existed in the 17th century (without a specific year or date).
dates can contains year, year+month or year+month+day
Now what would be the best to store this in the database and represent this in a model.
Would 2 properties on a model be sufficient?
public class Building {
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime? Date1 { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime? Date2 { get; set; }
}
Would it be suitable for search filters on the website. E.g. searching everything between 1830 - 1930 or everything from 17th century.
With the last question, I mean, how would you write a linq query if there is only one date given for a building (e.g. 1835). Would each query contain an extra check for the nullable date in case there is only a single date given? or are there better scenarios?
.Where(x => x.Date1 != null && x.Date1 >= 1830 && (x.Date2 == null || x.Date2 <= 1930))
Or is saving a DateTime? object not a good idea and better to store a short or integer and only keep track of the year component (if any)?
Really, your problem boils down to showing exact vs "fuzzy" dates. There's no one single strategy, but I've had a somewhat similar requirement before and handled it by having a start date, a fuzzy start, an end date, and a fuzzy end, all nullable.
If you know any exact portion of the date at all, you use the actual datetime field. For example, if all you know is 1880, you store it as 1880-01-01. If you know the year and month, you just make the day 01, and of course, if you know the full date, then you store that. Now, granted, this can potentially be problematic. How do you know it wasn't literally built January 1st, 1880, versus just generically 1880? Well, that's up to you to decide how to handle those situations. You can just assume that any 01 is the same as a null value for that date portion. For whatever reason, buildings don't tend to open on January 1st, or really the 1st of any month, but there could always be an exception out there.
If you do need greater precision, you might need to break the date apart and store it literally as year, month, and day - all nullable int columns. Then, you can simply piece it together however you like when it comes time to display it.
The "fuzzy" date columns would be strings and are where you'd store more nebulus "dates" like "Victorian Era", i.e. you may not have a true date or even year, but you know it was during some period of time. You could do the same with things like "19th century", but I'd personally prefer to store that as 1800-01-01 and then intuit that it should be displayed as "19th century" when there's a date of that form.
Another option is to use both the date and the fuzzy text. For example, you could store it as 1800-01-01 and "19th century", and then you can make the determination that it's not literally January 1st, 1800, based on the presence of the fuzzy text not being null. That can help solve the ambiguity problem described previously, as you could do this for all such cases. For example, if all you know is "July 1880", then you can store that in the fuzzy text, and set the date as 1880-07-01. Then, based on the presence of the fuzzy text, you can choose to decipher the 01 portion as essentially null, versus literally the first of the month. If there's no fuzzy text set, then you assume it's an exact date.
As far as representing it on your model, I wouldn't use actual DateTime properties or DisplayFormat. You'd be better served by having utility methods that can work over the logic and return a pre-formatted "date". Then you'd simply do something like #building.GetBuiltDisplay(), and return all the information you know (including start and end if you have it) already formatted.
I'm looking to make a custom data structure that holds a schedule for a particular class in a 5-course course load in university. It doesn't matter to me what year and date the classes are taking place - I only care about the day of the week and the time that it takes place.
How can I represent this without the DateTime? Or is there a way to do this with it?
Thanks.
Create your own class that holds the bits of data that are important for you.
The DayOfWeek enumeration is suitable to hold the day of the week and you can model the hours/minutes with int fields.
Something like:
public struct ClassSchedule
{
private DayOfWeek dayOfWeek;
private int hours;
private int minuts;
public ClassSchedule(DayOfWeek dayOfWeek, int hours, int minutes)
{
// test the incoming data for validity and throw exception if not valid
}
}
You need to ensure that the values passed in valid (say hours can be between 0 and 23, minutes between 0 and 59 and that the enum value passed in is actually a valid enum value.
I suggest making this an immutable value type.
You can use DateTime and then only display the information in it that you want. Or you can create your own class/struct and store information in it that you get from DateTime.Now.
I've played a little with SQLite in the past, and I like it enough that I want to use it for a new project.
Step 1 is creating the database, and I need to create a DateStamp field where I place a time stamp on when an event occurred.
In the SQLite Documentation, the Date and Time Datatype is defined as follows:
1.2 Date and Time Datatype
SQLite does not have a storage class set aside for storing dates
and/or times. Instead, the built-in Date And Time Functions of SQLite
are capable of storing dates and times as TEXT, REAL, or INTEGER
values:
TEXT as ISO8601 strings ("YYYY-MM-DD HH:MM:SS.SSS").
REAL as Julian day numbers, the number of days since noon in Greenwich on November 24, 4714 B.C. according to the proleptic
Gregorian calendar.
INTEGER as Unix Time, the number of seconds since 1970-01-01 00:00:00 UTC.
Applications can chose to store dates and times in any of these
formats and freely convert between formats using the built-in date and
time functions.
I'd rather not save dates as text, and since the Windows DateTime object does not go back to November 24, 4714 B.C., I supposed I'm left with storing DateTime values as an INTEGER.
So, how do I store the DateTime as an Integer? Would I get the TimeSpan between base date and date I want, extract the number of days, and store that?
// is this a UTC date?
private static readonly DateTime utc1970_01_01 = new DateTime(1970, 1, 1);
public static double GetIntDate(DateTime dateTime) {
// FYI: subtracting dates in .NET returns a time span object
return (dateTime - nov24_4714bc).TotalSeconds;
}
Is that right? Is this what everyone else is doing that uses SQLite?
It also says that SQLite stores datetime in UTC time, so I need to convert again on top of that.
Surely someone has done this before. I would appreciate seeing tools someone has made already that handles these inputs. SQLite has some built in functions, but I don't really understand how to use them.
Solved:
Well poo.
Could it be as simple as this?
public static long ToFileTimeUtc(DateTime dateTime) {
return dateTime.ToFileTimeUtc();
}
public static DateTime FromFileTimeUtc(long fileTimeUtc) {
return DateTime.FromFileTimeUtc(fileTimeUtc);
}
Comments?
Can I not do that?
Whether or not you can use FileTime depends on whether anything but your app will ever be accessing the data. FileTime represents the number of 100-nanosecond intervals since January 1, 1601 (UTC).
As such, you will need to make sure the integer is an 8 byte integer in SQLLite in order to store the entire value.
As long as your app is the only app to deal with this data, and you always use FileTime, then there's no problem. If others will access this data, and they're capable of understanding FileTime, and they are aware that this is what it is, then there is also no problem.
Well poo.
Could it be as simple as this?
public static long ToFileTimeUtc(DateTime dateTime) {
return dateTime.ToFileTimeUtc();
}
public static DateTime FromFileTimeUtc(long fileTimeUtc) {
return DateTime.FromFileTimeUtc(fileTimeUtc);
}
Comments?
Can I not do that?
I need to compare whether date is less than 3 months old.
I will get installation date:
DateTime installdate=DateTime.Parse("1/5/2012 8:12:14 PM");
if ((installdate<DateTime.Now.AddMonths(-3)))
{
// do something
}
Is this the best way to compare the dates?
Thanks.
A few things to think about:
"Is date x earlier than 3 months before today" isn't the same as "today is more than 3 months later than date x"; you'll need to make sure you have the exact semantics you want.
Consider what you want to do with the time component - are you interested in dates or dates and times? (Would you expect the condition evaluation to change based on the current time of day?)
Consider time zones: are you interested in "today in the system's current time zone" or some fixed time zone?
Depending on the source of the text data, you should possibly use DateTime.TryParse and you should possibly use DateTime.ParseExact or DateTime.TryParseExact, passing in the expected format (and culture)
Basically, there are various corner cases around date and time behaviour - you should explicitly think about all of these things (some of which are forced upon you if you use Noda Time instead of DateTime, btw :)
Regarding the first point, if the idea is that you get a trial period of three months from the installation date (or something similar), that suggests you should be adding three months to that instead.
I'd also change the variable name and get rid of the redundant parentheses, by the way:
DateTime installationDate = DateTime.Parse("1/5/2012 8:12:14 PM");
DateTime trialPeriodEnd = installationDate.AddMonths(3);
if (trialPeriodEnd > DateTime.Now)
{
// do something
}
Assuming you're storing the installation date yourself somewhere, I would try to store it in some form which is less ambiguous - possibly even storing just a "ticks" value instead of a string. But assuming you are storing it yourself, you shouldn't need to use TryParse - it makes sense to go "bang" if you can't parse the value. I'd use ParseExact, probably with a standard format specifier of "o" (round trip).
DateTime installdate ;
if (DateTime.TryParse("1/5/2012 8:12:14 PM", out installdate))
{
if ((installdate < DateTime.Now.AddMonths(-3))) { }
}
Tryparse is used so as to validate if the date passed in the parameter is valid or invalid
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.