-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Date time proposed improvements #7096
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
Conversation
|
Looks great! Have you seen #6978? I think it makes some changes that are relevant to this PR. I think instead of introducing separate procs like proc now[D: Date|DateTime](): D
proc parse[D: Date|DateTime](value, format: string): DThe reason that I prefer that design is that I think it will be more intuitive when even more types are added (
I disagree with this. When
Excellent. This will break code that tries to modify those fields, but IMO it's worth it. |
| rtl, extern: "ntEqTime", tags: [], raises: [], noSideEffect, borrow.} | ||
| ## Returns true if ``a == b``, that is if both times represent the same point in time. | ||
|
|
||
| proc `-`*(a, b: EpochDate): int32 {.borrow.} |
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 this should return the Duration type from #6978
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 soon as Duration will appear in devel I can do that, otherwise it is problematic to test
| proc date*(monthday: MonthdayRange, month: Month, year: int): Date = | ||
| ## Create a new ``Date`` | ||
| result = Date(monthday: monthday, month: month, year: year) | ||
| assertValidDate result |
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 proc should be named initDate.
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.
done
lib/pure/times.nim
Outdated
| proc date*(s: string): Date = | ||
| ## Parse `s` date string using ISO format | ||
| runnableExamples: | ||
| date"2019-03-21" |
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.
Example should verify the result of date"2019-03-21", this will likely complain about missing discard.
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 not really sure about this proc. If the use case is initialization, then IMO it should limit the argument to string literals so that parseDate(str, "yyyy-MM-dd") must be used when parsing input. A proc named date that does parsing seems a bit unclear.
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.
Removed this proc as requested. I can add date alias locally in my project.
I understand that it is deviation from the existing API.
However, it is super convenient to have a single function date that does all ways of date creation.
date"2019-02-03"
date(2019, mFeb, 3)
date(2019, 02, 03)
date() current date
date(x), where x can be EpochDate, Time, DateTime
So all you need to remember is the word date and you will be just fine with stdlib.
You can't do that effectively with DateTime as it has far too many members to keep specifying them one by one.
Please vote if you want date function back
lib/pure/times.nim
Outdated
| proc toEpochDate*(time: Time): EpochDate = | ||
| EpochDate(time.int64 div secondsInDay) | ||
|
|
||
| proc toEpochDate*(epoch_days: int32): EpochDate = |
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.
Should be epochDays instead of epoch_days
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.
Done
lib/pure/times.nim
Outdated
| let dt = date() | ||
| result.monthday = dt.monthday | ||
| result.month = dt.month | ||
| result.year = dt.year |
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 is not correct? It will overwrite all of monthday, month and year even if some of them might have been parsed.
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.
Previous behavior was to call now() at the begging of parse function unconditionally. It is tearing my heart apart when I see a such wasteful behavior, now() is not cheap and it is 95% probably that you will find a date in the string, so results of now() call will be overridden and wasted. The idea is to call now() only it date was not found in the string
lib/pure/times.nim
Outdated
| assertValidDate d | ||
| toEpochDate(d.year, d.month.int, d.monthday.int) | ||
|
|
||
| proc date*(epochdate: EpochDate): Date = |
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 dislike the naming of this. I think fromEpochDate better matches the rest of the API in the times module.
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.
done for now, unless idea of single entry date will be supported
lib/pure/times.nim
Outdated
| proc yearday*(d: Date): YeardayRange {.tags: [], raises: [], benign .} = | ||
| ## Returns the day of the year since January 1, | ||
| ## in the range 0 to 365. | ||
| assertValidDate d |
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.
assertValidDate shouldn't be needed here. When taking proper types like Date or DateTime as input they can be assumed to be valid.
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.
done
lib/pure/times.nim
Outdated
| proc toEpochDate*(epoch_days: int32): EpochDate = | ||
| epoch_days.EpochDate | ||
|
|
||
| proc toEpochDate(year, month, day: int): EpochDate = |
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.
Use the argument ordering day, month, year instead to be consistent with rest of the times module.
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.
done
|
After thinking about this some more, I don't think my idea of using generics for |
|
If you're using inheritance then I don't think generics are a good idea. Why the need for |
|
@GULPF
|
|
EpochDate naturally exists. It is in the heart of every date algorithm. The only question if you want to expose it or not. For example how is any |
lib/pure/times.nim
Outdated
| let dt = nowDate() | ||
| result.monthday = dt.monthday | ||
| result.month = dt.month | ||
| result.year = dt.year |
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.
Take his example: parse(str, "MM/dd"). It should parse the month and monthday and use the current year. This code however will overwrite all of the date fields with the current ones. The code needs to check if each individual field is missing before overwritting:
if ptMonthday notin found_tokens:
result.monthday = dt.monthdayThere 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.
done
lib/pure/times.nim
Outdated
| $d.year & "-" & $ord(d.month) & "-" & $d.monthday & " is not a valid date" | ||
|
|
||
| proc toEpochDate*(time: Time): EpochDate = | ||
| EpochDate(time.int64 div secondsInDay) |
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 don't think this will be correct for times before 1970-01-01, e.g a time of -1 will give the epoch date 0, but it should be -1.
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.
fixed, should work now
The reason that If we need a fast and short way to get the current UTC day, would introducing a If we really need a single proc for getting the UTC date, then it should be named
After reading this I think I was wrong to say that |
|
@GULPF |
|
@cooldome As you can see, the date in |
|
@GULPF: |
|
I catched myself in the act again checking for an update on this PR. I use the times module extensively, but need improvements. This is what I'm waiting for. Great work—can't wait for an update / merge on this. No joke. |
|
@jschopplich Will have to a wait a little longer then, this won't make it into the next release, sorry. |
That sounds wrong. If so, why is |
|
@Araq |
Alright. 😐 A proper times module is the one thing missing to put Nim above other languages in my production use cases. I will wait then—thank you @GULPF and @cooldome for the already merged improvements since v0.17.2. Keep it up! 👍 |
|
Please don't introduce the inheritance relation between Date and DateTime. Consider what happens if you want to implement arithmetic on Dates. Lets say you implement subtraction of date1 from date2. With your inheritance relation this becomes also valid for DateTimes but gives undesired results. How would you then implement subtraction specifically for DateTimes? Given that @GULPF will surely convince you, that you have to take timezones into account also for dates, you actually gain very little from a separate Date type. |
I'm not sure what you mean by this since the |
sorry this was a failed attempt to argue from authority ... if dates represent some number of days since an epoch and days are defined as in UTC (based on solar mean time), then it seems clear to me, that at least the question "what date is it today?" depends just as much on the location on earth where you are located as the question "what time is it now()?". |
|
The question "what date is it today" requires knowledge of timezones, but not questions like "what date was I born?" or "what date is next Christmas?". The main purposes of the The fact that this PR adds the type |
|
my humble opinion: close this PR and wait until @GULPF comes up with a separate Date type |
|
I think the PR queue for times.nim is now otherwise empty. Time to revisit this. |
|
Was not paying attention what is was happening with this PR. Will get back to it soon |
|
A friendly reminder. Ping @cooldome |
|
ah, yes. In next release then, all my energy is drained by #8489 which a blocker for my project |
|
No progress. Please reopen when you get back to it. |
|
@Araq that's what the label |
After major rework of
timesmodule by GULF, I decided to give it a second chance and try to replace my hand written closed sourceDatemodule with standard libtimesmodule.I found that now
timeshas all the functionality I need, but unfortunately external interface is such that I can't used it effectively. Coupling date and time together has its drawbacks. Time requires timezones and timezones requires reading external files that takes enormous amount time compared to rest of the calculations.There no tests yet so it is work in progress, but I would like to start the discussion if anyone see major problems with the design.
Summary of changes:
DateandEpochDateDateTimeis inherited fromDatewhich helps sharing large part of the functionality.Datehas similar functionality toDateTimebut much more efficient