-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Add documentation and type annotations for Time #5093
Conversation
@@ -181,7 +181,7 @@ struct Time | |||
# ``` | |||
# Time.epoch(981173106) # => 2001-02-03 04:05:06 UTC | |||
# ``` | |||
def self.epoch(seconds : Int) : self | |||
def self.epoch(seconds : Int) : Time |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not keep self
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- If something subclasses
Time
, this will not hold anymore (uhh subclassing astruct
is impossible, but the theoretic point still stands) - It can be confused with actually returning
self
(but modified). This way it's clear that it's an entirely new instance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- hmm I'm not sure I understand, do you think that if one subclasses Time to Time2 (in theory), the returned type of
Time.epoch
could be understood asTime2
? Is that what you're trying to avoid? (TIL something! I thought it was just a shortcut to the current class) - Well, it is a class-level method, so it won't be able to 'return'
self
in any case.
Also, I think the doc generator should change self
to the actual type (when it's used as a type) when possible & known.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, since epoch
calls new
, which can be overloaded by the theoretical subclass (if s/struct/class/
), it could return anything!
It's theoretical, Time
is fine.
src/time.cr
Outdated
self | ||
end | ||
|
||
def +(other : Span) | ||
# Returns a `Time` that is later by this `Time::Span`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/this/a/
? hmm.
"later by this timespan" doesn't quite sound right to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean... I had already considered at least 4 options and none sound right to me. What do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
C# uses "Returns a new DateTime
that adds the value of the specified TimeSpan
to the value of this instance." I don't like that though.
So how about "Returns a new Time
which is later than this Time
by the Time::Span
span", and rename the parameter to span
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure
src/time.cr
Outdated
@@ -203,12 +203,12 @@ struct Time | |||
self | |||
end | |||
|
|||
# Returns a `Time` that is later by this `Time::Span`. | |||
# Returns the `Time` that is later by this amount. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer a
to the
here (and everywhere else).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, reverted that
Please merge? 😐 |
src/time.cr
Outdated
@@ -275,76 +281,90 @@ struct Time | |||
end | |||
end | |||
|
|||
def self.now : self | |||
# Returns the current time in the current time zone. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think "local time zone" is a better wording here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
src/time.cr
Outdated
Time.new(year, month, day, kind: kind) | ||
end | ||
|
||
def year | ||
# Returns the year number (Common Era). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Returns the year number (in the Common Era)"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
src/time.cr
Outdated
year_month_day_day_year[1] | ||
end | ||
|
||
def day | ||
# Returns the day number of the month (`0..31`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Surely it's 1..31
to fit in with month
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
src/time.cr
Outdated
year_month_day_day_year[2] | ||
end | ||
|
||
def hour | ||
# Returns the hour of the day (`0...24`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not 0..23
? I think it's clearer. What about leap seconds? We should document that as an exception in addition to the "standard range" 0..23
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The day is defined as 24 hours and it's also clearer that time goes up to almost 24, not just 23. I will not be making this change.
I also don't know about leap seconds, and whether they are even possible in this implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A leap second doesn't lead to 24:00:00
. It is represented as 23:59:60
. So the only field that might have a irregular maximum value because of leap seconds is second
.
And I'd strongly suggest to use 0..23
because this accurately represents the value range of hour
. There is no "almost 24", it is not represented in this granularity. Times from 23:00:00
to 23:59:59
(or :60
) are all hour 23
without any further distinction. There is no sense in using an exclusive range here.
Besides, the exact meaning of the exclusive range literal ...
is not as commonly known and easily understood as the inclusive range ..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm even more convinced this is bad now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
src/time.cr
Outdated
(total_seconds % SECONDS_PER_MINUTE).to_i | ||
end | ||
|
||
def millisecond | ||
# Returns the millisecond of the second (`0...1000`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto on 0..999
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto. 😛
(to_i.to_f * NANOSECONDS_PER_SECOND) + nanoseconds | ||
end | ||
|
||
def to_f | ||
total_seconds | ||
# Converts to a number of milliseconds. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be fractional too, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes but come on, it's to_f
src/time/span.cr
Outdated
abs | ||
end | ||
|
||
def abs | ||
# Returns a non-negative `Time::Span` by removing the sign from this one. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Returns the absolute, non-negative amount of time this Time::Span
represents by removing the sign."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
Span.new(seconds: to_i.abs, nanoseconds: nanoseconds.abs) | ||
end | ||
|
||
def from_now | ||
# Returns a `Time` that happens later by `self` than the current time. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Returns a Time
which is in the future by this Time::Span
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I disagree with this. The method name already conveys what you're saying, so this description rephrases it in a different, more explicit way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another way is "Returns a Time that results of adding span to this time"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@asterite "... to the current time." But otherwise I'd vote for this suggestion.
Time.now + self | ||
end | ||
|
||
def ago | ||
# Returns a `Time` that happens earlier by `self` than the current time. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
to_i == 0 && nanoseconds == 0 | ||
end | ||
end | ||
|
||
struct Int | ||
def week | ||
# :nodoc: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was exactly what I thought when I saw this abomination.
"We don't want aliases, oh except for when they make a kewl DSL even cooler."
If someone has been conditioned to like this, they can keep using it, but new people don't have to know this.
It's a big amount of noise in the docs, so I did not want to document it. But I also didn't want to not document it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you all agree on removing these aliases it's fine with me. Maybe it's not that bad to write 1.minutes
instead of 1.minute
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either have them and document it, or not have them. I'd vote for the latter.
src/time.cr
Outdated
@@ -452,7 +474,8 @@ struct Time | |||
epoch.to_f + nanosecond.to_f / 1e9 | |||
end | |||
|
|||
def to_utc | |||
# Converts this time to UTC. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe "converts" can be understood as if it mutates the instance, maybe something like "Returns a new Time instance where ..." but I don't know how to reword it.
end | ||
|
||
def duration | ||
# Alias of `abs`. | ||
def duration : Time::Span |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can probably remove this alias in a later PR.
src/time.cr
Outdated
@@ -474,7 +474,7 @@ struct Time | |||
epoch.to_f + nanosecond.to_f / 1e9 | |||
end | |||
|
|||
# Converts this time to UTC. | |||
# Returns a copy of this `Time` converted to UTC. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure it's important, but it's not always a copy: if self
is already an UTC time, it returns self
, not a copy of it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a struct
, it's still a copy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@oprypin Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh right I forgot that minor fact
For immutable objects, copy and not are indistinguishable. Especially for structs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks really good, great work! However there are a few suggestions for further improving the wording.
self | ||
end | ||
|
||
def +(other : Span) | ||
add_span other.to_i, other.nanoseconds | ||
# Returns a `Time` that is later than this `Time` by the `Time::Span` *span*. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Returns a Time
that is later than this by adding span."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding time is not a thing. That's why I explain "+
" (that already conveys the "adding" part) with a real-world concept. So I think this suggestion is not an improvement. Same for the other ones.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is, that's what this method is for. The main part of my suggestion was anyway to remove the imo unnecessary types.
end | ||
|
||
def -(other : Span) | ||
add_span -other.to_i, -other.nanoseconds | ||
# Returns a `Time` that is earlier than this `Time` by the `Time::Span` *span*. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Returns a Time
that is earlier than this by subtracting span."
end | ||
|
||
def +(other : MonthSpan) | ||
# Adds a number of months specified by *other*'s value. | ||
def +(other : Time::MonthSpan) : Time |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
other
=> span
(or month_span
)
And doc: "Returns a Time
that is later than this by adding month_span."
add_months other.value | ||
end | ||
|
||
def -(other : MonthSpan) | ||
# Subtracts a number of months specified by *other*'s value. | ||
def -(other : Time::MonthSpan) : Time |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
other
=> month_span
And doc: "Returns a Time
that is earlier than this by subtracting span."
@@ -241,7 +245,8 @@ struct Time | |||
temp + time_of_day | |||
end | |||
|
|||
def add_span(seconds, nanoseconds) | |||
# Returns a `Time` that is this number of *seconds* and *nanoseconds* later. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Returns a Time
that is later than this by adding seconds and nanoseconds."
@@ -262,7 +267,8 @@ struct Time | |||
Time.new(seconds: seconds, nanoseconds: nanoseconds.to_i, kind: kind) | |||
end | |||
|
|||
def -(other : Time) | |||
# Returns the amount of time between *other* and `self`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
amount
=> difference
?
@@ -275,76 +281,90 @@ struct Time | |||
end | |||
end | |||
|
|||
def self.now : self | |||
# Returns the current time in the local time zone. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Returns the current local time".
Currently time zones are not implemented at all.
Even if, it would be debatable if the local time returned by Time.now
would necessarily be in a specific time zone. I'm not sure how this is going to be handled once we get there, but currently there is obviously no time zone attached.
This wording is also used in the doumentation for Go's Time.Now or Python's datetime.now
seconds, nanoseconds = compute_seconds_and_nanoseconds | ||
new(seconds: seconds, nanoseconds: nanoseconds, kind: Kind::Utc) | ||
end | ||
|
||
def date | ||
# Returns a copy of `self` with time-of-day components (hour, minute, ...) set to zero. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not name it explicitly hour, minute, second, nanosecond
?
I feel like at this point I'm just annoyed with the comments even if they are good. |
src/time.cr
Outdated
year_month_day_day_year[2] | ||
end | ||
|
||
def hour | ||
# Returns the hour of the day (`0...24`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm even more convinced this is bad now.
This is ready for merge too for me. About the inclusive/exclusive ranges, both are fine by me. Maybe inclusive is slightly better because if read quickly there's no possibility of confusion. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Last ones I promise...
@@ -262,7 +267,8 @@ struct Time | |||
Time.new(seconds: seconds, nanoseconds: nanoseconds.to_i, kind: kind) | |||
end | |||
|
|||
def -(other : Time) | |||
# Returns the amount of time between *other* and `self`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My only concern is that this method doesn't make it 100% clear that the time returned can be negative. "The amount of time between" can easily be interpreted as being abs(difference)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe just saying/adding "The amount can be negative if self
is a Time that happens before other`
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
((total_seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE).to_i | ||
end | ||
|
||
def second | ||
# Returns the second of the minute (`0..59`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"(0..59
, or 0..60
when there's a leap second)"? We mention leap years below so perhaps we should be consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure 60
can actually be returned? It doesn't look like, seeing that the method does a remainder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're correct: https://stackoverflow.com/a/16539734/2035962. Nevermind.
No description provided.