When using Noda Time, is there a more direct way to go from a set of discrete non-UTC values (that is to say, separate year, month, day, hour, minute values) to a UTC DateTimeOffset variable? I'm doing the following in a loop and it seems a bit odd to create LocalDateTime then apply two different timezones in a row.
DateTimeOffset target =
new LocalDateTime(year, month, day, hour, minute)
.InZoneStrictly(dataTimeZone)
.WithZone(utcTimeZone)
.ToDateTimeOffset();
I realize I'm probably overthinking/micro-optimizing, but since I'm new to Noda Time I'm mostly asking in case there is a way with fewer steps or that is better in some way. (I'm aware InZoneStrictly can throw exceptions, this is actually related to a scheduling system, so I definitely don't want invalid or auto-adjusted results.)
Your implementation is fine, though you could use DateTimeZone.Utc instead of utcTimeZone.
Here's another implementation that will give the same results:
DateTimeOffset target =
new LocalDateTime(year, month, day, hour, minute)
.InZoneStrictly(dataTimeZone)
.ToInstant()
.ToDateTimeOffset();
You might consider whether you actually need DateTimeOffset or not. Unless you're calling to some other API that requires one, you could use an OffsetDateTime or just an Instant instead.
As for the part about InZoneStrictly, consider that a user might pass in a perfectly valid set of date and time values that just happen to be ambiguous within the given time zone because they represent a local time during a backward transition (either for DST or change in standard time). Do you really want to throw in such cases?
Also, consider that if you have logic that applies a daily recurrence for the same time on multiple days, eventually you could run into an invalid time during the gap of a forward transition (again either for DST or change in standard time).
In Noda Time 2.x, InZoneLeniently was updated to generally do the right thing in such scenarios (first occurrence of ambiguous values, skip ahead for invalid values). Scheduling was a primary use case in this decision.
I have 2 DateTime values:
date1 <- {15-07-13 20:45:10} with Kind = Unspecified
date2 <- {15-07-13 20:45:10} with Kind = UTC
When comparing these 2 dates, the 2 dates are equal.
if (DateTime.Compare(date1, date2)!=0)
...
Can someone can explain why?
A little bit more strange to me: when converting the date1 (which is Unspecified kind) to UTC, I clearly see that the date is different:
date1.ToUniversalTime() --> {15-07-13 18:45:10} with Kind = UTC
Does someone can explain me why?
Yup. It's because DateTime is a fundamentally broken type, IMO. Basically the Kind isn't used in comparisons. Doing so would quite possibly have broken old code, and it's not always what you want. It was added on for .NET 1.1, and not always in a great way - it definitely wasn't fully integrated in every way you might have expected, as you've seen for comparisons.
As another example, even for a Kind of Local (which is meant to be the system local time zone) it's ignored for arithmetic, which means a call of AddHours(1) really only adds to the local time, rather than it representing elapsed time (which could end up being the same local time or two hours later in local time, around DST transitions).
My advice is just to avoid comparing DateTime values of different kinds in the first place. It's almost never what you want to do.
(Of course I'd also recommend using Noda Time, but that's a slightly different matter.)
From the documentation on DateTimeKind (emphasis is mine):
The members of the DateTimeKind enumeration are used in conversion
operations between local time and Coordinated Universal Time (UTC),
but not in comparison or arithmetic operations.
I understand that to refer a single point in time DateTimeOffset is better and more reliable way compared to DateTime as it replaces .Kind property by a more convenient thing that is the Offset to UTC.
Does this solve all the issues regarding to storing a single point in Date-Time or are there still some cases that I should be concerned about?
(If there are can you give me examples where DateTimeOffset can't be reliable?)
Thanks
Given a DateTimeOffset, there is never any confusion about what point in time that represents. So they are always reliable.
But there are some cases where a DateTimeOffset alone is still not sufficient. Here's an example of a common situation:
You are in New York, USA on March 10th 2013.
You find out about an event happening at 1:00 AM local time.
You record it as a DateTimeOffset with the value 2013-03-10T01:00:00-05:00.
Later, you find out that you were given incorrect information, the event actually occurred at 3:00 AM.
So you go to edit, and you change the value to 2013-03-10T03:00:00-05:00.
But this would be incorrect. On that particular day, daylight saving time starts, and so 3:00 AM is only one hour later than 1:00 AM. If you just advance the time, without considering that the offset may have changed, then you am referencing the wrong point in time.
It should have been 2013-03-10T03:00:00-04:00.
To overcome this situation, you must also know that the time was recorded in New York. You knew that in the first step, but then it was thrown out when you recorded it. Somewhere else in your application, you must hold on to this fact. Preferably, you would keep a time zone id, so that you could re-calculate the correct offset.
If using the TimeZoneInfo class in your application, then you would want to track the value of the .Id property, along with your DateTimeOffset. For New York, the time zone id would be "Eastern Standard Time". This is a bit confusing, because this same value is used regardless of whether DST is in effect or not. (There is no Windows time zone with an Id of "Eastern Daylight Time"). Also, there is no built-in class or struct that will pair a TimeZoneInfo with a DateTimeOffset. You have to do it yourself.
If you are using Noda Time (which I highly recommend). Then you can take advantage of the IANA time zone id of "America/New_York", and the ZonedDateTime object - which is designed for this exact situation.
You should also refer to DateTime vs DateTimeOffset. You should find the analogy there quite useful.
There are also some cases where DateTimeOffset is not appropriate. Maybe this one is obvious, but it's still worth mentioning.
When you are not refering to a single moment in time, but a relative point on the calendar.
This happens more often than you would think. For example:
In the United States, this year daylight saving time began on March 10th 2013 at 2:00 AM.
But it didn't happen at at the exact same moment. Each time zone has their own local 2:00 AM, so there are actually several different transition points on the instantaneous timeline.
(Aside, but worth mentioning, in Europe, DST ("Summer Time") happens all at once. The transition is based on the same UTC moment for Western, Central, and Eastern European time.)
There are other real-world examples where the same point on the calendar is not the same point in time, yet people tend to think of them as if they were.
Day boundaries ("today", "yesterday", "tomorrow")
Other whole named days ("this Wednesday", "last Friday")
Television Shows ("7PM Tuesday nights")
Telephone Calling Plans ("Free nights and weekends")
Countless others...
In Noda Time, you would use a LocalDateTime for these scenarios. Without Noda Time, you would use a DateTime with .Kind == Unspecified.
This is a follow on from a question answered yesterday..
Convert 12hr Time String to DateTime object
Those times in the xml feed are EST (who does that?) but our timezone is BST.
so 10:30PM is 02:30AM UTC or 03:30AM BST
However, TryParseExact yields 10:30PM in local time (as to be expected given that there is not timezone information)
So the question; how can I parse that time as 02:30AM UTC rather than 10:30PM BST?
However, TryParseExact yields 10:30PM in local time
No, it doesn't. Not unless you tell it to. By default, and unless there's any indication of the offset in the pattern, the parse methods will return DateTime values with a Kind of Unspecified - which is entirely appropriate as no information has been specified. If you just convert it to a string, it will assume it's actually a local time, but that's not what the value itself says. You need to understand the three kinds of DateTime - it's a broken model IMO, but that's what we've got in the BCL.
You can pass that to the appropriate TimeZoneInfo to apply a specific time zone and get an appropriate DateTimeOffset, although it's then up to you to remember the actual time zone involved. (An offset isn't the same as a time zone.)
Alternatively, you could use my Noda Time project, which differentiates between the different logical types rather more clearly. You'd parse as a LocalTime, then decide which LocalDate to join that with in order to produce LocalDateTime, which you could then convert to a ZonedDateTime using the "America/Los_Angeles" time zone (or the Windows equivalent; the choice is yours). In performing that conversion, you'd specify what you'd want to happen if the given local time was invalid or ambiguous due to daylight saving transitions.
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.