-
Notifications
You must be signed in to change notification settings - Fork 176
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 support for width-aware noon and midnight options for DayPeriod #444
Add support for width-aware noon and midnight options for DayPeriod #444
Conversation
} | ||
} | ||
} | ||
} |
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 test moved to the newtests/mod.rs
file.
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.
Is this a conventional place to save tests? @zbraniecki @Manishearth
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 /components/datetime/tests/dayperiod.rs ?
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.
Given that you are writing these tests as parameterized tests with fixtures, I definitely think that they belong as an integration test, not hidden in a test directory in the library.
(sorry for the triple-comment)
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 would have liked for it to be an integration test, but as I noted in the description of the PR, there is no public functionality to format dates with a custom pattern, so it has to live within the privateformat
module. This seemed, to me, to be the best compromise, but I'm open to other suggestions.
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.
For unit tests it's fine to create a tests
module. I personally don't feel a need to prefer integration tests over unit tests, though it is definitely easier to find integration tests.
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.
@sffc So I looked into this a bit more this morning, specifically into how I might use StructProvider
.
Even if I used StructProvider
to get a custom payload, it seems that both write_pattern()
and DateTimeFormat
must take a DatesV1
struct specifically as their data.
Unless there is another way to format the datetime using the custom provider, I'm not seeing any viable options to format with a custom pattern publicly. That being said, I'm still trying to build an overall familiarity with the code base, so I certainly could have missed a key insight 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.
Right. Create a DatesV1, either using Default::default()
or by loading a stock locale from test data, then modify a field like patterns.time.full
with your desired pattern.
I like the idea of data-driven tests being able to overwrite locale data for that testing. @zbraniecki thoughts?
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.
Okay, so I've now moved this test back to the file where it existed previously, and I moved the new tests to the components/datetime/tests
folder to be integration tests. I really like this a lot more.
But it feels somewhat hacky to me to grab the CLDR data for the locale, and then just overwrite the long
patterns for each relevant case in my test data. Is this really intended functionality? I had previously overlooked that every member in DatesV1
is public.
I had a conversation with @zbraniecki about how custom patterns are often misused in practice. My understanding is that this is why we don't really have a public functionality to directly do something like DateTimeFormat::try_format(&date_time, &pattern)
, and that we prefer to have people use only the options bags.
It just seems strange to me to have this preference to funnel people through pre-existing options, but still allow "backdoors" for custom patterns by letting people directly mutate the DatesV1
data directly. I'm almost of the opinion that, if the functionality exists anyway, why not provide something likeDateTimeFormat::try_format(&date_time, &pattern)
?
I suppose I just want to gain clarity around the design decisions behind not having a custom format with pattern function, and for making all of the DatesV1
members public, since I wasn't involved in the project at the time when these were conceived or implemented.
In the interest of not having duplicated conversations, if there are links to relevant pre-existing conversations that would be helpful 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.
In the interest of not having duplicated conversations, if there are links to relevant pre-existing conversations that would be helpful to me.
We've had conversations about this before, but I think they weren't written down.
The fields in all the data structs are public by design. The data struct is designed to be the place where you can "overlay" stock data with custom overrides.
That being said, I agree that in this particular case, it would probably be cleaner to have a low level pattern API. We can revisit this test when we have such API.
572aff5
to
dfebcfd
Compare
Notice: the branch changed across the force-push!
~ Your Friendly Jira-GitHub PR Checker Bot |
dfebcfd
to
ff5df4d
Compare
Notice: the branch changed across the force-push!
~ Your Friendly Jira-GitHub PR Checker Bot |
Codecov Report
@@ Coverage Diff @@
## master #444 +/- ##
==========================================
+ Coverage 75.28% 75.49% +0.20%
==========================================
Files 113 113
Lines 6058 6116 +58
==========================================
+ Hits 4561 4617 +56
- Misses 1497 1499 +2
Continue to review full report at Codecov.
|
Pull Request Test Coverage Report for Build d48ff169ff786e1a24ae8e08ab4a6c8c62092f22-PR-444
💛 - Coveralls |
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.
lgtm!
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.
(setting review bit)
2e710b3
to
3ed730e
Compare
Notice: the branch changed across the force-push!
~ Your Friendly Jira-GitHub PR Checker Bot |
ac00238
to
efe4f59
Compare
Hooray! The files in the branch are the same across the force-push. 😃 ~ Your Friendly Jira-GitHub PR Checker Bot |
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.
lgtm!
I just want to clarify everything that we have discussed formally in a comment. So the goal is to add two new sets of functionality to this PR:
if (m == 0) {
if (h == 0) {
"'midnight'"
} else if (h == 12) {
"'noon'"
} else {
"h a"
}
} else {
"h:mm a"
}
Is this correct? I think that number 2) makes sense, I am still a bit unclear still about number 1) because the It's the |
The pseudo-syntax I posted above is something we should do later in #380. For now we just need to do what you posted in #444 (comment), which is a bit simpler. |
As a first pass to achieve the functionality described in #444 (comment), I have naively added the capability for a Currently, the maximum granularity is computed every time the pattern is written. This is obviously going to be slower than computing the maximum granularity once on creation and caching the value, but it was one of the simplest approaches that touched the least amount of existing code in order to get new tests written for the functionality. I am curious to see if and how much this regresses the benchmarks. I suspect that I will likely add one more commit to compute and cache this value. |
15c6b89
to
770936d
Compare
Notice: the branch changed across the force-push!
~ Your Friendly Jira-GitHub PR Checker Bot |
7c08500
to
ba149fd
Compare
- Restructures `format` module to use directory structure instead of single file. - Adds a `format/tests` directory. - Moves existing local tests from `format.rs` to `format/tests/mod.rs` - Adds JSON test data for `DayPeriod` patterns. - Adds JSON-serializable structs for testing formatting patterns. - Adds test cases for `DayPeriod` patterns. - Adds parsing test cases for the `b` `DayPeriod` pattern.
- 24:00 will not be a valid time once unicode-org#355 is fixed. - Removes logic than handles 24:00 for now.
- Converts `DayPeriod` pattern tests to be integration tests. - Tests no longer direclty use the private `write_pattern()`. - Tests now mutate the `DatesV1` struct to the desired pattern, using `DateTimeFormat` to format the custom patterns.
bbfe8a5
to
6c87afd
Compare
Notice: the branch changed across the force-push!
~ Your Friendly Jira-GitHub PR Checker Bot |
Uh-oh, spoke too soon. Looks like the CI is having an issue with the optional serde serialization, even though it works for me locally. It probably has something to do with you making serde optional. I will look into this. |
- Rewrites the `symbols!()` macro as a token tree muncher. - For `Option` members, adds serde attributes to skip serializing if none. - Otherwise, includes them in the seralization.
- Regenerates the test data now that `noon` and `midnight` are skipped if not present. - Previously `noon` and `midnight` would show up as `null`.
- Moves a few expressions in the dayperiod patterns test to outer loops.
- Adds capability for a pattern to compute its most granular time. - e.g. `h:mm:ss` is `Seconds`. - e.g. `h` is `Hours`. - e.g. `E, dd/MM/y` is `None`. - Patterns containing `b` the `NoonMidnight` pattern item will now display noon or midnight only if the displayed time falls on the hour. - This means that `12:00:00` is always noon-compatible. - However, `12:05:15` is noon-compatible only if the display pattern does not contain the minutes or seconds.
- Time granularity functionality is no longer associated with Pattern or PatternItem. It is now local to the format module alone as standalone functions.
- Format no longer needs to be a directory.
- Makes TimeGranularity private instead of public.
- Only calculates the time granularity if the `DayPeriod` is `NoonMidnight`.
- Converts `Pattern` from a tuple struct to a traditional struct. - Adds a new data member `time_granularity` to `Pattern`. - `time_granularity` is a lazily initialized, interrior-mutable cached value. - Makes `Pattern`'s data members private. - The cached `time_granularity` is dependent on the `Pattern`'s `items`. It is no longer safe to allow `items` to be publicly accessible, because mutating `items` must invalidate the cached granularity. - Adds new method `items()` to `Pattern` to return a slice of its items. - Implement `From<Vec<PatternItem>` for `Pattern` - This is out of convenience in many places where tuple-struct syntax was used previously.
- Pattern::from_iter now uses Pattern::from::<Vec<_>>
- `Pattern`'s time granularity is no longer lazily evaluated. - It is instead evaulated on construction.
6c87afd
to
4d1ca3b
Compare
Notice: the branch changed across the force-push!
~ Your Friendly Jira-GitHub PR Checker Bot |
@sffc all fixed. The CI failure was due to me not handling optional serde in the macro rewrite. Should be good to go now. |
- filter_map is more specialized, and arguably more readable.
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.
lgtm!
Fixes #435
This patch adds functionality and tests for width-aware
DayPeriod
patterns fornoon
andmidnight
.https://unicode.org/reports/tr35/tr35-dates.html#dfst-period
According to the spec, when formatting with this pattern:
noon
options are used from12:00:00
before12:01:00
midnight
options are used from00:00:00
before00:01:00
noon
and/ormidnight
the appropriateAmPm
option will be used as a fallback.AmPm
as expected.There is no public functionality in icu4x to create a
DateTimeFormat
with a custom pattern. The function that handles formatting with a pattern,write_pattern()
, lives in theformat
module, which is private. In order for tests to have access to thewrite_pattern()
function, all testing must live within theformat
module itself, so this patch restructures the previousformat.rs
module intoformat/mod.rs
and adds aformat/tests
directory where the relevant testing lives.