-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
API proposal/RFC - System.Time namespace #14744
Comments
WRT VB's aliasing of If this new API lives in a |
I think that instead of I think that there are a lot of good ideas between Joda/Noda and JSR310. However, before we can really move forward fixing the time issue I think that .NET needs a better answer to the time zone issue. The current |
@HaloFour - That's one of the reasons I posted the issue; to get extra stuff to look into. Borrowing and tweaking the table you posted in an earlier issue, we need (at minimum) narrow types for the following areas (ignore names for now):
... a big question at that point is, do we go the JodaTime/NodaTime route and have Date maintain references to a calendar, or go the Java 8 route and have distinct date types for each calendar (and they and Date implement some common interface). Then there's the common utility types, which are slightly less important but still nice to have .
|
I would also suggest |
@jskeet - Thanks. Guess I'm too used to the Java 8/JodaTime convention. Haven't had the opportunity to do much in C# yet. |
For a namespace, might be worth considering For classes, might be worth considering JSR-310 names as is, simply to aid developers moving between languages. (The "Local" part of Step 1 in a process like this is to understand the mistakes of the past design, examine the bugs that get raised. Step 2 is to decide on the value types. Step 3 is to figure out the level of extensibility you want and find a way to make that work. (JSR-310 is extensible in calendar system, fields, units and value types for example) |
@jodastephen - re Step 1: any insight WRT java.time? |
See https://github.com/ThreeTen/threeten/wiki for some captured thoughts. |
Thanks for tagging me due to my suggestion #14089. I'm happy to see this conversation kicked up again. My only input in looking at the Java world is to make sure that our equivalent of getMonth() isn't zero-based :-) (I kid, I kid... I know that java.time.LocalDate finally righted this wrong.) I did not know about the LocalDate name coming from ISO-8601, thanks @jodastephen for that info. That changes my mind and makes me okay with using that name for the .NET version. I'm sorry I don't have much more input here at the moment, I exhausted my input on #14089. |
Thanks for tagging me. I'll admit that I have not gone deep on a bunch of the improvements NodaTime brings to .NET, but I'll try to help out however I can. One question I have to start with (which will probably lead to a bunch of follow up questions) is about this statement:
It's unclear to me what "we" means here. Does this mean that types in CoreFX can't take a dependency on it? Is it that other libraries outside CoreFX don't want to take a dependency on NodaTime? Something else entirely? I'm interested in understanding the differences between some new time APIs in a future version of .NET Core vs a future version of Noda Time that runs on top of the .NET Core surface area and hence can be used by any library targeting .NET Core. What does the former provide that the latter does not? When all of the libraries in .NET Core ship on NuGet and can version independently from one another and have no ties to the runtime itself, I struggle to see the difference between something in CoreFX vs a popular "third-party" library like NodaTime, JSON.net, etc. |
@ellismg - the 'we' here was intended to be corefx. Some in-house devs may also not be allowed to take 3rd party library dependencies, but this is rare and not an interesting reason. The former (doing a new library) would allow us to pull in tertiary types (like OData's Date type), and to allow wider use (OData's Date doesn't work directly with the globalization calendars, you have to take a trip through DateTime). It's enabling corefx to accept or return a better, more specific type than DateTime. If the future deployment model would allow us to use NodaTime types in corefx, I could probably work/live with that. |
Looking at the roadmap, I see Would it be reasonable for Or perhaps the time-portions would be broken out into What about backwards compatibility? If we are suggesting that these new types be created independently, are we also suggesting dropping the current date and time types? What about all of the existing code that folks will want to port to .NET Core? It would be quite frustrating to find that you had to make tons of changes because Besides, there's really very little wrong with I'm not trying to be a naysayer, but IMHO, thrusting a whole new and different time API on folks is bound to be problematic. Likewise, doing nothing when we know there are issues also has it's consequences. I think the key to success here is balance. Add the missing pieces, while keeping the good parts intact. Here's a detailed proposal that I think achieves everyone's goals (please correct if I'm mistaken):
Other important changes that would be introduced:
There are really only a few other things that Noda Time provides that are absent from the above. We can debate/discuss these:
There are a few trivial bits also, such as After all is said and done, there would be a few new .NET Core nuget packages, which I would expect assemblies like the aforementioned @Clockwork-Muse - Do you think this goes far enough? Or are you really set on the death of @ellismg @tarekgh - does this sound reasonable? Or is it overreaching? |
@mj1856 - I think I'd prefer the death of DateTime through neglect (nobody uses it) in favor of something better. I don't want people yelling at us for it being gone - at least at first I'd prefer gentle encouragement to use something better (say, a StyleCop rule or something). Make the new API available but not even deprecate the old one (at least for a while). People could use the existing libraries with minimal/no changes, and update to the new API as time allowed. (All of a sudden I'm wondering if we could distribute a Roslyn syntax rewiter to do gross conversions, based on types and method calls... Tricky though). One of the biggest problems is dealing with DateTimeKind, and the issues it causes. I have little issue with TimeSpan or DateTimeOffset as they're (probably) implemented (although DateTimeOffset.Date returns a DateTime, which isn't really correct). (The purist in me also wants TimeSpan in here, too, but I mostly get what you're saying about the dependency.) ZonedDateTime doesn't feel to me like it has DateTimeOffset in it. Yeah, you can get it without much trouble, but it's really Date and Time with 'location' attached. Ehhh, semantics really. Dealing with time zone info providers does sound like an interesting idea. I'm not as up on some of the deployment/management side of things, though. I personally (just for right now) dislike how you have to use the current calendar system, but don't have problems with it otherwise. A good Period class would help in that regard, anyways. |
Just a few points based on my .NET experience.
|
In NodaTime, I really like the way how the time zone info (e.g. DST, etc.) gets updated. AFAIK, this information changes based on the government rules. So, I should be able to update this by myself or the official update channel should be very responsive to changes and releases should be frequent. |
IIRC I'm on the fence about @ashmind The Microsoft time zone information doesn't contain those abbreviations at all. The IANA tzdb does for supported time zones, but they are mostly useless in parsing scenarios. You'd need a known time zone as a starting point, at which point the abbreviation can aid in resolving ambiguous times at DST boundaries. |
I believe we need to take some time to think more about the whole space. exposing a lot more date/time classes will create more complexity. I understand the need of such types but we need to think how all of this will fit with what we have today. this is why we suggested to start with what @mj1856 creating and have the experiment to know what most needed types and how simple/complex it is. also we'll see what is wrong in such design. #14089 has the detailed discussion about this direction. I want to second @ellismg point. we need to encourage people to use and consume the third parity packages. Json.Net is very good example of that. not every type should be part of the framework core. we need to understand why people can't take dependency on such Third parity libraries. deploying such third parity library shouldn't be different than deploying the corefx itself. @mj1856 as we have talked offline a couple of months ago regarding different issues. and I have shared my thoughts with you. mostly what you have mentioned align with what we thought but we need to spend some more time exploring different options and design to make sure everything will fit nicely especially with types like TimeZoneInfo which is shared with the desktop framework. |
@HaloFour - The single base-offset issue was described in KB3012229, and has already been fixed in .NET Core and .NET 4.6RC. However, there's still a related API issue open in #14457. WRT the WRT abbreviations, only English abbreviations are in TZDB, and the TZDB list has discussed several times that many were just made up by the group to fill in the gaps. Some non-English ones are also in CLDR, but in general, not every zone has an abbreviation. I've got the CLDR abbreviations and names wrapped nicely in TimeZoneNames, which I plan to do a .NET Core release in a future update. I'm not sure if it would make sense to pull this in as a core dependency - though it would solve the globalization issues with |
Third party libraries are just fine for non-primitive types or primitive types of niche usage. A calendar date is a primitive type that is universally used. JsonConvert is not a primitive type and not much framework code would call into it. However, quite a bit of framework code could make use of a primitive Date type, in particular SqlClient as @mj1856 mentioned. SqlClient not being able to have a 1:1 mapping to SQL Server's |
@paulirwin - From your perspective, can you clarify the meaning of "primitive"? There is some debate on what this term actually means. The C# Language Specification uses this word only twice, and in an indirect way. The VB.Net Language Specification defines it more definitively as:
Furthermore, VB lists If we apply C#'s definition to VB, then So when we say "primitive", are we talking about a framework concept of primitive in some way? Or is there some other distinguishing factor in your mind that makes date/time related classes and value types a lower-level feature? I can understand this lower-levelness at least with |
@tarekgh - I agree we should in general be encouraging people to use 3rd party libraries, but I'm pretty sure JSON.Net is a terrible example to use here:
In the case of date and time, there's a lot of stuff that is "stuck" returning I didn't really have any problem with @mj1856 's experiments. The problem was that the direction at the end of #14089 seemed more like, "We'll just do these few types, and tell people to use NodaTime for the rest". I firmly believe that's not a good solution long-term:
|
@mj1856 Sorry, I wasn't intending to use the word primitive in any kind of way as to imply something specification-related but I appreciate the digging into the meaning. What I meant by primitive was a value type that is a fundamental building block of framework code ( |
@mj1856 - I'm personally all for sourcing time zone info from the CLDR, it's an excellent resource and, from what I can tell, very accurate; plus it's updated regularly. Its format lends itself to generating the code via a tool. There's also the possibility (getting ahead of us all, here, but just throwing it out there) that this could pave the way to start driving some of the culture and region information from it, too - the data is much more comprehensive than Windows, certainly. That said, it would make the most sense to have a provider model (as mentioned earlier) for timezones et al, of which a CLDR-driven source would be just one implementation. As wonderful as NodaTime is, I'm not entirely comfortable with the framework taking a dependency on it for something as fundamental as date and time. Its reach is pervasive, and I'd wager would very quickly make NodaTime seem to be a core 'part' of the wider framework, when in fact it isn't. I'm very happy for a new, more flexible, Date/Time API to be introduced into the framework that supersedes the old one, but feel it should fall under the general .Net umbrella, not a third party umbrella. I realise that that, along with much else besides, is a debatable issue, however, and that is also true for whether anything I've just said here has really added anything to the discussion! |
Hi there i am new here, For reference here is some light readings about leep seconds |
For Noda Time, I made a very conscious decision not to include leap seconds. Originally I believe JSR-310 was going to support multiple timelines, but ended up deciding that clock-smearing (with a simple "60 seconds per minute, always" model) was a better fit. My contention is that few applications require understanding of leap seconds, and it's reasonable for those applications to require other libraries or custom handling rather than imposing the complexity of leap seconds on all other applications. More interesting to me is whether there's a clean way of representing a time-of-day value of 24:00, which has far more practical applications - but still ends up causing pain in various ways. |
@rebizu - @jskeet - WRT to 24:00, one of the big problems being "does adding it to a date give the next day?" (when combining a date and time). It certainly would be nice for exclusive upper-bounds checking. |
I agree with @jskeet regarding the leap seconds too.
as discussed in #14089 Matt's library is experimental components and any type proven in the field we'll consider adding it to the core. it is matter of time. the long term direction is we'll include all needed types in the core as long as it make sense these types to be there and in same time most of apps will need such types. as I mentioned before I am really worried exposing many date/time types which will add more complexity to what we are currently have and in end up not many people will use such new types. we still can add more types to Matt's library as needed. |
At this point I feel the need to remind us all: I am honestly very confused by the resistance to using NodaTime itself. @jskeet and @mj1856 (and others) have put a lot of effort into understanding both the (extremely complex) domain and the myriad of ways that it trips up developers every day, and designing a library to help expose these critical concepts as a "pit of success". IMHO they have been quite successful in that effort. I think we would be crazy to throw all of that away just to recreate it again. If there are problems that NodaTime doesn't solve, let's solve them. If there are design issues that make NodaTime less than ideal, let's fix them. But I have yet to see any justification for starting from scratch.
That's the whole idea: when we identify a gap in Core, and find that there is an existing library that solves the problem well, Core should take a dependency on that library rather than building it over again.
This is an unfortunate problem, but re-building a new date/time library in Core does not solve it. Other than taking massive breaking changes in the framework - which I am pretty sure is off the table - the best thing I know to do is ensure that our new date/time library has good interop with the existing types. But we're in luck! NodaTime already has such interop, allowing developers to convert back and forth in a reasonable way. As a disclaimer, I should acknowledge that I have a couple of small commits in NodaTime from the relatively early days. But I don't consider myself particularly invested in NodaTime, nor is my concern whether my (minor) work in particular survives. My concern is this...
...the apparently still-prevalent philosophy that because a library is not published by Microsoft and doesn't have the "System.*" namespace that it can't be considered "part of the framework". This is the philosophy that has been holding back .NET open source for over a decade, but it has no place in the world of .NET Core. Needlessly re-inventing the wheel - as has already been done so often in the history of .NET - only reinforces the stereotype that .NET open source projects can't have a real impact because only "the framework" matters. We need to kill that stereotype if .NET is going to compete with all of the other popular development ecosystems whose beating heart is community-driven open source. </soapbox> |
While I agree with a lot of what you say I do think that if a part of the .NET framework takes a dependency on something that is not a part of the .NET framework then that something must become a part of the framework. It would be impossible for System.Data.dll to have a dependency on NodaTime without NodaTime then being distributed and maintained as a part of the whole because neither would work without the other. CoreFX being more modular might alleviate some of that issue. I think NodaTime is good but it's also very complicated, moreso than the typical scenario requires. Chronologies throw a lot of common assumptions out the window in order to support a very small minority of use cases. Separation of chronologies is one reason that Java 8 did not just use JodaTime. Mutability is another. I don't doubt that ownership and maintainability was also a part of that conversation. |
Maybe what we need is a I've pushed up an old type I created for myself (and updated it to use interpolated strings - yum), just for reference here: https://github.com/whoisj/xtypes/blob/master/Src/Timestamp.cs |
@mj1856 I agree. It's amazing how much software really gets it wrong but companies either hack around it or deal with the pain through manual workarounds. I think the vast majority of that software is born out of simple needs running out of a single branch office location where the default local behavior just happens to be correct. Then they open a new office, or sign a new client in another country (or Arizona/Hawaii). @whoisj That's pretty much how these libraries work. |
Sounds perfect. My strongest push here is that there be a "common" type by which all others can be represented, such that there's a way to translate between the various time types both current and future. By agreeing to the statement any point in time can represented as an amount of elapsed time from a given agreed upon common point in time, then we can create such a "common" type. I'm recommending we use milliseconds (because Ticks are far too granular for this king of thing), the date and time of 1-1-0000 00:00:00.0000, and allow both positive and negative values (both preceding and following the common-point-in-time. From there, various calendaring schemes are moot. People can do as they please, 'cause I really, really do not care if somebody claims to live in a world where the number of hours in a day shifts around constantly or not, and years have 360 days in them. Have at it. |
@whoisj The exact unit isn't really that relevant because you wouldn't be exposed to the value as a raw number. Given that .NET and NodaTime already both use 100-nanosecond increment "ticks" I think it makes sense to at least keep that level of precision. Java 8 |
Limiting ourselves to plus or minus 10,000 should be fine -- but can we agree to support minus 10,000 years? Some of us do care about dates in classical history and most of that is before the common era. |
@whoisj - do you care about instants-in-time in classical history? or about dates in classical history? I imagine normally the latter, and that a simple DateTime would serve you fine. I can't imagine what kind of UTC/DST issues you'd even face with this. |
Given that detailed record were kept as far back as 5,000 BCE - having the hour of the day would be useful. But no, I do not think anyone really cares about the seconds value. |
@whoisj Looks like NodaTime already supports a range between the years -9998 and 9999 (actually it seems that |
@HaloFour agreed, but it would still be nice to be able to say "given this arbitrary date/time construct you gave me, how many years is it after Julius Caesar was born?" simply because it is useful to do so. Additionally, dates stored in a database regarding simple date+time (down to minutes maybe) should be represent-able in the structure without the need to implement a custom structure. This allows utilities like SqlDataReader to remain useful without having to do funky conversions to Int64 and stuff which then invalidates the logic in the database itself. I can see a need to do something like
By ensuring the base type is common, this is trivial to implement. All of the "I don't care about minutes, seconds, etc can be handled by the |
My opinion is that very specialized use cases like that are probably the domain of a separate library. Trying to resolve the hour of a day 6,000 years ago is far from a common scenario. |
@whoisj - the types you want are already being considered. I'm actually surprised that @tarekgh - you fail to understand just how quickly things become advanced. Trying to get the duration between two dates, and you only care about the local time zone? This returns the wrong value if the range crosses only one DST boundary (or possibly more, if the offsets change):
... because the subtraction doesn't actually care about DST. Even if it did, adding time doesn't either:
... returns a value happily printing
... plan on keeping track of and applying the offsets yourself? |
@HaloFour I agree, but why actively design a system which cannot support it? |
I wouldn't, but I also wouldn't actively design a system that supported it All that said, Noda demonstrates that a 64-bit instance can cover those On Wed, Jul 1, 2015, 5:13 PM J Wyman notifications@github.com wrote:
|
Agreed (and to be fair I've not actually looked at Noda yet). |
FYI - I created an issue for the |
I feel like I've arrived late to this party. Date and time is something I care a lot about and have felt pain on, especially around accurate scheduling. I've used NodaTime a lot recently, so the idea of the BCL moving past the mistakes of DateTime is very appealing. One of the most valuable things the core libraries provide is a central "standard" that other, more specific libraries can work around. Is there value in defining a few primitive types or interfaces, like A subject I haven't seen addressed yet is mechanisms of obtaining the current instant. One of the key things NodaTime did for my projects was to include an |
I just want to chime in from the perspective of the apps we have at BlueMountain Capital, since some folks (e.g. @tarekgh) are arguing that the need for something better than DateTime is niche. We have prevalent problems with DateTime, mostly due to the offset being ambiguous and the fact that we run things in multiple timezones. DateTimeOffset is better, but the fact that framework and 3rd party libraries don't really use it means that we end up converting in lots of places, and that encourages developers who don't know the error of their ways to allow DateTime to infect our own codebase. The implicit coercions between DateTimeOffset and DateTime are really unhelpful here, because people don't even know they are doing it wrong and end up with incorrect DateTimeOffset values because they are converted from DateTimes. We also felt the need to define our own Date type (one of many) since it makes an API much clearer to know if it works in terms of dates or date/times. It also allows the use of adding/subtracting days, whereas adding days is essentially undefined for date/times unless they are zone-away (which neither DateTime not DateTimeOffset is. This area is badly in need of improvement. And PLEASE don't do implicit conversions between the bad old DateTime and the new clean types. My 2c. |
this is not my position. it looks my points was not clear. here is some points I hope it clarify and summarize what I was saying:
I hope this is clear enough to everyone. |
Thanks @Clockwork-Muse for starting this this discussion, and to everyone who participated. Moving forward:
Thanks! |
Closed for length issues. |
It seems that times have changed (looking at System.Text.Json 😄) |
With Windows now natively supporting leap seconds, and PTP becoming more of a thing, I've been contemplating a design that would support leap seconds from the beginning. Not only do the current types not fully support leap seconds (because of legitimate back-compat concerns), NodaTime doesn't either, that I'm aware of. For that matter java.time also doesn't (and by default slews the clock for +/- some hours around it), although at least the extra package has TAI instants |
I'm a little confused: is there a plan to include the new date/time API in the .NET 5 BCL? [Maybe there is a summary page for the planned/actively developed upcoming APIs, but I failed to find it.] |
No, there is no plan to do so. |
(aka "programmers for good dates")
Related:
#14089 - Adding
Date
andTime
types.#14052 - Deprecating
DateTime.Now
.See also:
What's wrong with
DateTime
anyway?Date and Time are foundational concepts in our daily lives, and in programming; it's why we have
DateTime
.Unfortunately,
DateTime
isn't sufficient. Date and time are part of a larger ecosystem of concepts, ranging from an absolute point in time something occurred (anInstant
), to the value reported on a wristwatch (LocalTime
). They're related, and you can (usually) transition or convert from one to the other, but they are very definitely not the same thing.But wait! We have NodaTime! Well, the biggest problem with NodaTime is... it's a separate, third-party library. It means we can't take dependencies on it. This results in things like OData having a separate
Date
type for XML compliance (and there are other examples in different namespaces). There's a lot of stuff that NodaTime does, and does well, and most of it is stuff that the default libraries should be handling (like, say, time zone ids from non-windows sources).What about patching some common holes with new, standard types (ie, Matt's
Date
andTime
types)? This alleviates some problems for us, but leaves the problem when interacting with NodaTime. That is, "Why do I have to use the deficient framework types/something else to do XML serialization!?". (Note NodaTime has been looking to get the library installable on SQLCLR; I don't think it's made it into a release yet). Oh, and it means we have to keep three time zone databases in sync, instead of two (at least on windows).So: I'm proposing a new namespace as a modern, good implementation of a date and time library, our own version of JSR310/java.time . We need a good set of narrow value types, and a range of support classes to handle conversions and many other use cases.
Unfortunately... I... don't have an API on hand: I'm creating this issue to get things started. Coming from the Java world, I really like the new java.time library, but don't know if we can (or should, really) do a straight port. It's possible we might just use NodaTime; however that library was deliberately implemented with limited extensibility, something we would need to consider (ie, no custom calendars). It would be good to ask Jon Skeet what version 8.0 would look like, if we went that route.
Known pain points:
DateTime
toDate
. This limits type names somewhat.End-of-life considerations:
First, even if we had an implementation now, corefx isn't releaseable yet. Then, there's whatever delay is involved in possibly getting such a library into the desktop release, and into wider distribution. So nothing is going anywhere any time soon.
DateTime
(and other existing types): eventually, mark obsolete/deprecate (and remove?). Timeline for this is probably multiple versions after release, although documentation should be changed to point to the new types as part of the initial one.Interested parties (?):
@jasonwilliams200OK , @mj1856 , @gafter , @paulirwin , @tarekgh, @eatdrinksleepcode , @michaelstaib , @HaloFour , @ellismg
@jskeet (Jon Skeet - NodaTime lead)
@jodastephen (Stephen Colebourne - JodaTime and java.time implementer - informational/possible wisdom only)
The text was updated successfully, but these errors were encountered: