Get dayspan according to dates, not duration? - c#

I am trying to get the number of days between two datetimes, but not according to the exact timespan, rather according to the "day date" difference between date a and date b. No hours taken in account.
So far, I calculated the age of an item using :
(DateTime.Now - creationDate).Days
The problem with this code is that, for something that was created the day before but less than 24h ago, it will output "0 days", which is not very clear to my users apparently.
So what I want to accomplish is, even for an item that was created at 11:59pm for example, to get an output of "1 day old" as soon as the clock hits midnight. How could I accomplish this?

Two options:
1) Take the two dates first:
var days = (DateTime.Today - creationDate.Date).Days;
2) Use my Noda Time date/time library instead, using LocalDate for the two dates involved, and then Period.Between(start, end, PeriodUnits.Days) to get a period of just days. (You can also get weeks, months etc.) Admittedly getting "today's date" is deliberately a bit trickier in Noda Time - where .NET implicitly uses "the system time zone," Noda Time forces you to be more explicit.

I would use it simply like
int days =(int)DateTime.Now.Subtract(creationDate).TotalDays;
hope this helps

Related

How to perform multiplication in date (datetimeoffset format)

I have following 3 fields
startingdate, expirydate, number of months
startingdate = DateTimeOffset.Now;
and number of months, say 24 months
How to calculate expirydate = ?
Can anybody give me an idea?
You don't need multiplication in this case - just addition, specifying the units:
DateTimeOffset startDate = DateTimeOffset.Now;
DateTimeOffset expiryDate = startDate.AddMonths(months);
Two things to note:
Date and time arithmetic can be odd. In your example case it's less likely to be odd than normal, as you've got 2 years, so the only corner case is adding 2 years to February 29th and getting February 28th; normally you'd need to consider (say) adding 1 month to August 31st and getting September 30th. In other words, just because two expiry dates are the same doesn't mean they came from the same start date.
You might want to consider using DateTimeOffset.UtcNow and doing everything in UTC, rather than using the local time zone. Using DateTimeOffset instead of DateTime protects you from time zone problems to some extent, but keeping everything in UTC is clearer.
If you really mean you have dates rather than dates and times, you might want to explicitly use midnight... it's unfortunate that .NET doesn't have any "date-only" type. You might want to consider using my Noda Time which is designed to make things rather clearer than the BCL API.

Why is DateTime.Date defaulted to midnight

I cannot find any elaboration on why the Date property of the DateTime object is defaulted to midnight. I know that it is, through my own work as well as MSDN, but I am trying to understand the reasoning behind this. I cannot find any articles elaborating on why this is so.
Edit: To elaborate on some of the points being asked in comments.
string a = "2014-10-22 09:00 PM";
DateTime d = DateTime.Parse(a);
In this example I would have assumed it would default to 21:00:00.000- again I know it does not.
DateTime.Date means the day, the same way DateTime.Today returns the current date's DateTime at midnight (as opposed to DateTime.Now). So what do you expect it to return instead? A DateTime is a struct which always contains a time even if it's set to 0:00:00.
So every DateTime has a time component. It's the same as if you'd say: give me an hour without minutes. Every hour can also be represented by 60 minutes. By using dt.Date you say explicitly that you want that DateTime "without" time which means midnight and is a shortcut for new DateTime(dt.Year,dt.Month,dt.Day).
As far as I'm aware, aside from being the start of the date, it's there so you can ignore the Time part of the DateTime.
I'm sure there's better, more detailed explanations (and I'm sure someone, somewhere will come along and mention the use of NodaTime - possibly Jon Skeet himself - and it's Date class)
Because it's got to be set to something, and midnight (ie all zeros) is as good a value as any!
Seriously though, it makes sense at you've asked for a date, and 00:00:00 is the start of that date. There's no Date type in the framework, the designers overloaded DateTime to cover both, and midnight was chosen as the time in the day.

How do I accurately represent a Date Range in NodaTime?

Goals
I have a list of LocalDate items that represent sets of start dates and end dates.
I would like to be able to store date ranges, so that I can perform operations on them as a set of overlapping or distinct ranges, etc.
Questions
Does NodaTime provide some sort of DateRange construct that I've missed in the docs?
Am I thinking about this wrong? Is there a more natural / preferred way to accomplish this that NodaTime already allows for?
Am I setting myself up for trouble by attempting to think about a date range using a LocalDate for a start and an end date?
I'm completely new to NodaTime and assuming that this is a conceptual misunderstanding on my part.
Update: I noticed a similar question on the subject from 2009, but that seems to refer to another utilies class; I'm assuming that since then NodaTime may have evolved to accomodate this situation.
Noda Time provides an Interval type for a range of Instant values, but it doesn't provide range types for the other types. Part of the reason for this is the nuance of how ranges are used for different types.
If I give you a range of instants, it is always treated as a half open interval. The start value is included, but the end value is excluded. Humans do this naturally any time we provide a time value, such as when I say an event runs from 1:00 to 2:00, clearly I mean that the event is over at 2:00, so 2:00 is excluded.
But with whole calendar date ranges, typically the end dates are inclusive. To represent the entire month of January (as a range of LocalDate values), I would probably say Jan 1st through Jan 31st, and I am including the last day in its entirety.
We could probably add some additional range types to enforce these things, but we would need to think about how much value there is in having them in the API when you could probably just create them as needed. I'm not saying I'm for or against it either way, but that's probably something to be debated on the Noda Time user group.
To answer your specific questions:
No, there is no predefined range class for local dates.
The only other thing to consider is that calendar math is usually done via the Period class. For example, to determine how many days there are between two calendar dates:
LocalDate ld1 = new LocalDate(2012, 1, 1);
LocalDate ld2 = new LocalDate(2013, 12, 25);
Period period = Period.Between(ld1, ld2, PeriodUnits.Days);
long days = period.Days;
No, there's nothing wrong with creating a range class of local dates, there just might not be a whole lot of advantage. You may do just as well by having two properties, StartDate and EndDate, on your own classes. Just be careful about the inclusiveness of the end dates, vs the exclusiveness you'd see with an interval or time range.
And lastly, you said:
... so that I can perform operations on them as a set of overlapping or distinct ranges, etc.
You're probably looking for operations like intersection, union, calculating gaps, sorting, etc. These and more are defined by the Time Period Library, but Noda Time doesn't currently have anything like that. If one was to create it, it should probably be in a companion library ("NodaTime.Ranges", perhaps?). Likely it wouldn't be desired to pull it into the core, but you never know...
If you do end up using that Time Period Library, please make sure you recognize that it works with DateTime only, and is completely oblivious to DateTimeKind. So in order to be productive with it, you should probably make sure you are only working with UTC values, or "unspecified" calendar dates, and try not to ask it things like "how many hours are in a day" because it will get it wrong for days with daylight saving time transitions.

Converting datetime to time in C# / ASP.NET

I am trying to insert time on my asp.net project.
RequestUpdateEmployeeDTR requestUpdateEmployeeDTR = new RequestUpdateEmployeeDTR();
requestUpdateEmployeeDTR.AttendanceDeducID = int.Parse(txtAttendanceDeducID.Text);
requestUpdateEmployeeDTR.TimeInChange = txtTimeOutChange.Text;
requestUpdateEmployeeDTR.TimeOutChange = txtTimeOutChange.Text;
TimeInChange and TimeOutChange are DateTime data types. But I am inserting a time data type. How can I convert that into a time data type using C#? Thanks!
The .NET Framework does not have a native Time data type to represent a time of day. You will have to decide between one of the three following options:
Option 1
Use a DateTime type, and ignore the date portion. Pick a date that's outside of a normal range of values for your application. I typically use 0001-01-01, which is conveniently available as DateTime.MinValue.
If you are parsing a time from a string, the easiest way to do this is with the DateTimeStyles.NoCurrentDateDefault option. Without this option, it would use today's date instead of the min date.
DateTime myTime = DateTime.Parse("12:34", CultureInfo.InvariantCulture,
DateTimeStyles.NoCurrentDateDefault);
// Result: 0001-01-01 12:34:00
Of course, if you prefer to use today's date, you can do that. I just think it confuses the issue because you might be looking to apply this to some other date entirely.
Note that once you have a DateTime value, you can use the .TimeOfDay property to get at just the time portion, represented as a TimeSpan, which leads to option 2...
Option 2
Use a TimeSpan type, but be careful in how you interpret it. Understand that TimeSpan is first and foremost a type for representing an elapsed duration of time, not a time of day. That means it can store more than 24 hours, and it can also store negative values to represent moving backwards in time.
When you use it as a time of day, you might be inclined to think of it as "elapsed time since midnight". This, however, will get you into trouble because there are days where midnight does not exist in the local time zone.
For example, October 20th 2013 in Brazil started at 1:00 AM due to daylight saving time. So a TimeSpan of 8:00 on this day would actually have been only 7 hours elapsed since 1:00, not 8 hours elapsed since midnight.
Even in the United States, for locations that use daylight saving time, this value is misleading. For example, November 3rd 2013 in Los Angeles had a duplicated hour for when DST rolled back. So a TimeSpan of 8:00 on this day would actually had 9 hours elapsed since midnight.
So if you use this option, just be careful to treat it as the representative time value that matches a clock, and not as "time elapsed since midnight".
You can get it directly from a string with the following code:
TimeSpan myTime = TimeSpan.Parse("12:34", CultureInfo.InvariantCulture);
Option 3
Use a library that has a true "time of day" type. You'll find this in Noda Time, which offers a much better API for working with date and time in .NET.
The type that represents a "time of day" is called LocalTime, and you can get one from a string like this:
var pattern = LocalTimePattern.CreateWithInvariantCulture("HH:mm");
LocalTime myTime = pattern.Parse("12:34").Value;
Since it appears from your question that you are working with time and attendance data, I strongly suggest you use Noda Time for all your date and time needs. It will force you to put more thought into what you are doing. In the process, you will avoid the pitfalls that can come about with the built-in date/time types.
If you are storing a Time type in your database (such as SQL server), that gets translated as a TimeSpan in .Net. So if you go with this option, you'll need to convert the LocalTime to a TimeSpan as follows:
TimeSpan ts = new TimeSpan(myTime.TickOfDay);

Ways to format time/duration in C# using short version

I'm looking for a way to format time duration originally expressed in hours (as a 'double' variable) for an ASP.NET web app written in C#. I need a short version that has only 2 significant values. For instance:
1h:20m
2d:20h
2mo:12d
5y:2mo
I searched and it seems like C# does not have a built-in function for what I need.
So I decided to write my own but I'm stumped with correct formatting of all the parts. For instance, I may get a string, such as "1d:24h", or for a simple 2 months, I may get "1mo:29d"
PS. The problem I've encountered is in defining how many days are in a month and in a year.
DateTime's are renowned for being an annoying task.
As there is no indication as to which months you are referring to, with the given information this would be impossible. Months can have 28, 29, 30 and 31 days depending on what month/year you are taking into consideration..
Without an indication as to which months you are dealing with, the flip from 1 to 2 months would be a random guess as to which day you make the transition. You will either have to add in more incoming parameters to account for this, or explain to the user that a month is considered x days and only x days.
Another thing to consider would be daylight savings. 1pm + 24 hours may not be 1pm the next day. In such circumstances with you or the end user may wish to consider such days 23h=1d or 25h=1d.

Categories