-
-
Notifications
You must be signed in to change notification settings - Fork 281
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
Time v0.2 pre-release feedback #190
Comments
Some questions that come to mind after reading this issue and poking through the docs and code briefly:
|
my wish list item: a u64 wrapper representing a nanosecond timestamp with serialization/deserialization and interoperability with the other types. it's not always possible to use u64 to store timestamps (e.g. dates > 2554-07-21) but in many cases it is, and u64 is half the size of a libc timespec. (i64 would be ok as well, max date is 2262-04-11). relatedly, a i32/u32 wrapper representing hourly precision timestamps, u16 representing daily, etc. I've used these approaches in certain circumstances but it would be a joy to have a library that allows painless conversion between these and more full-fledged datetime types. |
The primary problem with doing something like this is that the epoch is not immediately obvious. You could always do something like |
@jhpratt do you mean it wouldn't be obvious whether the type uses 1970-01-01 or some other epoch (1582! who's with me!?) as its reference point? My assumption was it would use the unix epoch; I think that would be the obvious choice. But there's a variety of ways to mitigate possible confusion, including, as you suggest, explicitly named "constructor" methods. In |
@jstrong-tios Yes, that is what I meant with regard to the epoch. I would personally assume the unix epoch as well, but I don't think that should be the case without being clear in the method name. That would be similar to other items excluded in the scope, where any assumptions are clearly indicated. However, you do make a decent argument with the size of the struct. Running
On initial thought, I could do something along the lines of Feel free to join the Matrix channel if you'd like to discuss this outside of this issue! I'll likely respond quicker there as well. |
Why not name the functions the same as their std library counterparts? For example: I think there would be value in having this as a drop-in replacement. |
@aloucks I presume you're only referring to Basically what it comes down to is I think that "secs" is odd to use — some others like millis, micros, and nanos are more common, but as a native English speaker, I've never seen anyone use "secs" when referring to seconds in any context other than that one. Plus, at what point do you stop shortening names? Why not just While I understand the concern, I think it's more logical to just spell it out. Time wouldn't be able to be a drop-in replacement regardless, due to differing behaviors and function headers due to its ability to be negative. And on top of that, you picked probably the most similar method name 😛 Most of the methods are Side note! If Rust had method overloading, my ideal API would actually be along the following lines: impl Duration {
fn seconds(i64) -> Self; // same as current
fn seconds(self) -> i64; // same as `.whole_seconds()`
fn seconds(self) -> f32; // same as `.as_seconds_f32()`
fn seconds(self) -> f64; // same as `.as_seconds_f64()`
} Unfortunately that's not quite the case. I looked into just supporting |
@jstrong-tios Looking into this some. It looks doable, though I'm not 100% sold on it being in the 0.2 release. There would be 8 types and conversions in between all of them. Then we'd also have arithmetic between the various types (adding, subtracting, and dividing, plus multiplying by integers), equality, ordering, etc. Needless to say, there would likely be a few hundred manual trait impls that could only be partially generated with macros. |
@jhpratt if it's any use to you, I just dug up this implementation of a daily and hourly integer wrapper types I wrote for an unpublished project. What do you have in mind in terms of things that cannot be done with macros? Comparing between the types? |
Yeah, that's roughly what I had in mind for the API, sans chrono of course. With regard to macros, off the top of my head I think a large portion wouldn't be able to due to the conversion constants. I believe there's a way around it, but I'd have to check to be sure (it deals with the orphan rule). I could, of course, convert it to a |
I’m a little unsure about trying to bake in our own i18n effort here. Specifically whether it’s likely to hinder broader support in the future for apps that need to work with more than just dates and might run into inconsistencies with libs that take different approaches. Do you know of any other |
Not entirely sure what you mean by potential inconsistencies with other libraries. I suppose there could be differences in spellings or abbreviations if that's what you mean, but I'm not aware of any major i18n/l10n crate in the ecosystem. Upon a quick search, With regard to other languages, yes! I actually pulled the localization from glibc.
Of those that I searched, PHP, C♯, and Go appear to have neither language nor locale support (PHP says so explicitly). The others are above. So at least from first glance, it seems a significant number of languages have some level of support, even if not customizable. I think it's important to have it not implicitly rely on the system locale or language, as that causes inconsistencies when running otherwise identical systems. At the minimum, the user should have to call |
@wezm I've just removed the log dependency in favor of a more detailed compile-time message. @jstrong-tios After thinking about your idea a bit more, I think it would be best to push this past 0.2, given the inherently large amount of code & complexity. |
@KodrAus Would you prefer 0.2 not have localization? Everything could be in English, which is currently assumed if not specified. It would be relatively easy to remove the languages as it currently is. Looking down the road, I recently ran across the Unicode Common Locale Data Repository, which seems to be the de facto authoritative source on locale information, being used by Windows, Mac, and most Linux distros, as well as by browsers like Chrome and Firefox. I am going to look through the raw data some more; I'm trying to determine how hard it would be to extract the requisite information and publish a l10n crate, which time could then depend upon. That would be a ways away, though. |
Thanks for your patience on this @jhpratt! And I should’ve mentioned before that the new API you’ve designed is great and a real leap forward. I’m trying to start at a higher-level before digging into specific API decisions.
I haven’t actually worked on a localized app myself, so this is really just my impression based on the scope of the localization API. If anybody who has needed to work in this space has different impressions I would defer to those 🙂 I imagine a project that requires localization would want a fully-featured localization system like Project Fluent, which looks like it has out-of-the-box datetime support, and an implementation for Rust. In this case we don’t need to build localization support into |
No problem @KodrAus. I haven't actually done a large-scale app that requires localization (yet), so I'd likewise defer as well if anyone else is following this and has input. Fluent seems useful, and handles both full and abbreviated text as well; it appears to be based off of JavaScript's API. You're probably right that anything needing localization would be on a scale higher than just dates and times. After taking a quick look at Fluent on the playground, I'll almost certainly pull the localization code tonight, unless I see some significant reason not to. Update: Language handling has been fully removed. |
Currently functions which create Date/Time objects from parts (e.g. |
@Y0ba I can look into additional methods that would return an |
My usecase is that these parts come from device via COM-port, and they might be either wrong or just corrupted, therefore both
|
Ok, sounds good! I'll take a look into it tomorrow or Tuesday; hopefully updating the macros won't be too tricky. |
Well, I just tried implementing a trait and a variety of objects to allow for a very detailed error (actual range, given value, what type it was), but it seems like it's not currently possible to do without a ton of effort. I could likely work around it by creating another layer of abstraction, but then it gets confusing to follow for the end user. So, they'll be methods returning an Update: Implemented returning an |
Issue I would like to resolve: Should I can't think of any conceivable reason why How overflows are handled in general is something that I do need to check and possibly modify behavior before a release, though. Update: Overflow handling should be sensible now. |
Are there any good reasons to require Rust v1.40? I'm quite curious. It seems like a time crate should be able to be built using older compilers. |
@stevenroose After the initial release, bumping the minimum version for rustc will allow for the then-current stable and the two previous versions (which would currently be 1.37, as stable is 1.39). I don't think I wrote that down anywhere, so I'll add it to the wiki in a bit. Keep in mind that once rust-lang/rust#65262 lands, that stable can be the permanent MSRV, as any future changes could be gated behind that. This is currently possible via |
@alexcrichton @KodrAus Any final concerns, or can publishing rights be granted on crates.io in anticipation of a release next Thursday(ish)? That's the final item in the rough plan here from back in September. Pinging @Manishearth as well, who had initially expressed reservations about transferring control of the crate. |
Thanks for the ping @jhpratt! This is looking great! The only real concern I have besides localization, which we’ve sorted, is the presence of a raw Can we think of any really compelling usecase for |
Would |
|
Yeah, I just feel like "naive" would lead users away from it, even when it's the appropriate type to use. I'll make that change in a minute — should be relatively easy. |
Just pushed up the change, should be all set @alexcrichton (unless @KodrAus has anything else). |
I'll just do one more quick pass over the public API now 🙂 |
So I just had a few more questions: Do we need our own public Having the pub struct Error {
kind: ErrorKind,
}
enum ErrorKind {
Message(&'static str),
Parse(ParseError),
}
impl From<ParseError> for Error { .. }
impl std::error::Error for Error {
fn cause(&self) -> Option<&dyn std::error::Error> {
match self.kind {
ErrorKind::Parse(e) => Some(e),
_ => None,
}
}
}
impl Error {
fn as_parse(&self) -> Option<&ParseError> { .. }
} and then return this top-level And I promise that's the last of it from me! 😁 This really is a phenomenal effort! |
The I was originally going to split the enum into its own crate, but the "sign" name is being squatted, and despite the obviousness of it, crates.io policy is ambivalence. I'd actually prefer a For And I swear I don't mind! Feedback is important 😄 |
cc @skade IIRC you mentioned you were also curious in this, would you like a chance to review this API? |
can't help but ++ @Y0ba request about introducing non-panic API. time is used directly or indirectly by many crates, it's a real shame to have otherwise solid Rust app to panic because there is user input with invalid data. It's a little burden to deal with Result<>, but we do not have much control over what 3rd party crate pass to time internally. |
👍 Or at least mark them as deprecated and remove in v1. That way v0.2 and 0.1 will be more compatible and developers will have more time to migrate to fallible versions. |
Would it be satisfactory to clearly indicate in documentation that the I hesitate to remove them entirely, because if you're using a hard-coded value, you'd still have to use Note that there will almost certainly be released between 0.2 and 1.0, which would give sufficient time for deprecation. |
may be introduce just to illustrate what the pain the panic is: i have 2 crates outside of my control between my app and time crate. My QA figured to try |
Hmm…a feature flag may work, provided it's disabled by default. It could be clearly indicated in documentation that the feature is necessary to use the function, similar to existing methods (rustdoc is built using nightly). The fact that everything has to cascade through the ecosystem is a good point, and is definitely a reason to do something now as opposed to later. I'll think about it tomorrow at some point, but my initial thought is that it would be an acceptable solution. |
I've decided to go ahead with gating the panicking API behind a feature flag. This will not apply to the various "format" methods, as the only time they can panic is if the developer provided an invalid formatting string. |
May I ask what needs to be done to convert a UTC time to a local time in 0.2? Before we could do: tzset();
let tm = at(timespec); |
@ymtvx Unfortunately getting the system time zone is not possible in 0.2, at least yet. I am going to investigate how difficult it would be to support, at a minimum, Unix and Windows APIs, which would cover the major three operating systems. However, it shouldn't come as a surprise that it's basically impossible to cover all systems (that's one of the large problems with 0.1). Note that this is probably the one thing where I'd be okay with changing If this is included in a future version, it would definitely be gated, since it would add a runtime dependency (libc). |
Hm, I personally find the use of a feature flag for panicking a big strange unless it's an explicit goal to remove them, in which case I think they should just be changed to return |
So I'm 👍 on updating the crate owners and publishing a |
@KodrAus Long-term (like 1.0), I would like to have them removed. The panicking methods, when used with known values, can be verified at compile-time. I actually have a proof of concept time macro now, though it relies on Would it be preferable to just nuke the panicking versions right now, before a release? That would force users to explicitly handle the case where input is invalid, at least until a macro of that sort is allowed on stable. |
Also, awesome! @alexcrichton unless anyone else has objections, we should be good to go for Thursday. |
Closing this issue, as all necessary reviews have been performed. v0.2 will be published on crates.io at some point tomorrow. If you encounter any issues, please file a new issue. Thanks everyone for your input! |
Hello rustaceans! Until recently, the time crate was soft-deprecated, in that bug fixes would be considered, but no features would be actively added. It is the 25th most downloaded crate all-time, and is still being downloaded slightly more than chrono. As such, I began a bottom-up rewrite of the time crate, taking inspiration from time v0.1, chrono, the standard library, and some RFCs, along with some localization pulled in from glibc.
My goal is to release time v0.2 alongside Rust 1.40, which is currently scheduled to be released on December 19. By going to the community for a public review now, this will allow me sufficient time to make any necessary changes.
To view the documentation for the master branch, you can use
time-rs.github.io
. There are also some helpful shortcuts, so you can go totime-rs.github.io/Duration
and be brought to the relevant documentation immediately.Follows are two pages from the wiki, which provide some detail as to what will occur in the future and the differences between existing crates.
Differences from chrono and time v0.1
Chrono has been the de facto crate for time management for quite a while. Like time, its original implementation predates rust 1.0. Presumably due to its age, chrono still relies on time v0.1 (though it's partially inlined the relevant code). The disadvantage of this is that any third-party functions that rely on chrono essentially mandate you import chrono or time v0.1 to use its
Duration
type. This single fact makes interoperability with the standard library quite difficult. Time v0.1 is identical to chrono in this manner.Time v0.1 is what the standard library was built upon. Time v0.2 flips this, being built upon the standard library. This provides for a higher-level abstraction, while also supporting the same targets as the standard library.
In time v0.2, there is full interoperability with the standard library. Every type can perform the same arithmetic that its standard library counterpart can and vice versa. Types are freely convertible to and from their standard library equivalents.
Vision
Scope
Most things that simplify handling of dates and times are in the scope of the time crate.
Some things are specifically not in scope.
Explicitly in scope, but not yet implemented include the following:
Period
type, which would be usable with a zonedDateTime
. While this would expose a similar (if not identical) API toDuration
, the advantage is that it could take into account leap seconds, DST, etc. As such, aPeriod
would not be directly convertible to aDuration
- one minute could be either 59, 60, or 61 seconds.Both lists are explicitly non-exhaustive. Additional items that are not in scope will be added to this list as they are brought up.
Strategy
Wherever possible, types are implemented as wrappers around those in the standard library. Additional functionality is still able to be provided, such as allowing a
Duration
to be negative.Some types (like
Sign
) were helpful to implement generically, simplifying arithmetic implementations. They may be extracted to a separate crate in the future and re-exported in time.Future plans
If all necessary reviews go well, my intent is to release time v0.2 shortly after the release of rust 1.40.
For post-v0.2 features, eventually I'd like to support tzdb, including automatic time zone shifts for DST and native leap second support. I'd also like to be able to have
5.seconds()
be able to return either atime::Duration
orstd::time::Duration
, but the compiler is currently unable to infer the return type and choose the appropriate trait to use.Let me know your thoughts, positive or negative. All I ask is that you be constructive and follow the code of conduct. I can be reached on Matrix either via direct message or on the #time-rs channel.
The text was updated successfully, but these errors were encountered: