-
Notifications
You must be signed in to change notification settings - Fork 323
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
More robust Date/Time format patterns parsing #7826
Conversation
Time_Of_Day is mostly unchanged. Date has got 3 week-based selector examples and Date_Time got only one, since it seems likely less common on Date_Time and that one has alraedy lots of formats anyway. They are mostly to show how to use them. If the user selects the week-based selector, this is what is generated (then the user can tweak the format string too): The 'simple' patterns are plain Text that is converted using a The locale option was decoupled from the As shown above, it can be customized for the week-based year. For simple patterns, we need to add additional arguments to the Later, I hope we will be detecting these conversions and will have some way to display in the IDE a way to add these additional arguments (essentially, we will need to promote the auto-converted expression like Most importantly - regarding the original bug - most patterns are case insensitive - i.e. I can now put either Mixed case - like The only case sensitive ones left are There is also possibility to construct a Advanced users can discover it in the Component Browser. |
One thing that I didn't like about this new approach is that the So, to improve the discoverability of 'how does one customize the locale', I decided to add an example with custom locale to Date and Date_Time dropdowns: Does that seem OK? |
On the mixed case, I think we should error if we detect mixed cases on We could keep the Locale attached to the format/parse method? That would keep it as visible as before. |
f2e31bd
to
e421654
Compare
Ok, can do - I guess we would error on any two same letters with mixed case then - I don't think
I wanted to remove it, because now the locale has to be part of the formatter - since it is set at construction of the Java However, if you think that makes sense, I can re-add the Does that sound OK? |
I was meaning that we can mix 24hr and 12hr so that should be an error (2 hours). I'm happy for the locale to be embedded in the Date_Time_Formatter - most of the time the default is the correct one anyway. |
9b6b7a6
to
39db2eb
Compare
… infra, TODO: rest
// Allow Year and Quarter to be parsed without a day (use first day of the quarter). | ||
if (parsed.isSupported(ChronoField.YEAR) && parsed.isSupported(IsoFields.QUARTER_OF_YEAR)) { | ||
int dayOfQuarter = | ||
parsed.isSupported(IsoFields.DAY_OF_QUARTER) ? parsed.get(IsoFields.DAY_OF_QUARTER) : 1; | ||
int year = parsed.get(ChronoField.YEAR); | ||
int quarter = parsed.get(IsoFields.QUARTER_OF_YEAR); | ||
int monthsToShift = 3 * (quarter - 1); | ||
LocalDate firstDay = LocalDate.of(year, 1, 1); | ||
return firstDay.plusMonths(monthsToShift).plusDays(dayOfQuarter - 1); | ||
} | ||
|
||
// Allow Month and Day to be parsed without a year (use current year). | ||
if (parsed.isSupported(ChronoField.DAY_OF_MONTH) | ||
&& parsed.isSupported(ChronoField.MONTH_OF_YEAR)) { | ||
return LocalDate.of( | ||
LocalDate.now().getYear(), | ||
parsed.get(ChronoField.MONTH_OF_YEAR), | ||
parsed.get(ChronoField.DAY_OF_MONTH)); | ||
} | ||
|
||
if (parsed.isSupported(IsoFields.WEEK_BASED_YEAR) && parsed.isSupported(IsoFields.WEEK_OF_WEEK_BASED_YEAR)) { | ||
// Get the day of week or default to first day if not present. | ||
long dayOfWeek = parsed.isSupported(ChronoField.DAY_OF_WEEK) ? parsed.get(ChronoField.DAY_OF_WEEK) : 1; | ||
HashMap<TemporalField, Long> fields = new HashMap<>(); | ||
fields.put(IsoFields.WEEK_BASED_YEAR, parsed.getLong(IsoFields.WEEK_BASED_YEAR)); | ||
fields.put(IsoFields.WEEK_OF_WEEK_BASED_YEAR, parsed.getLong(IsoFields.WEEK_OF_WEEK_BASED_YEAR)); | ||
fields.put(ChronoField.DAY_OF_WEEK, dayOfWeek); | ||
|
||
TemporalAccessor resolved = IsoFields.WEEK_OF_WEEK_BASED_YEAR.resolve(fields, parsed, ResolverStyle.SMART); | ||
if (resolved.isSupported(ChronoField.EPOCH_DAY)) { | ||
return LocalDate.ofEpochDay(resolved.getLong(ChronoField.EPOCH_DAY)); | ||
} | ||
} | ||
|
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 have replicated the logic we had originally for parsing 'partial matches' and even extended it a bit to new cases.
However, for longer term - I'm not sure if this is the right approach. Doing the week-based-year proved to be challenging this way and it seems there is a much simpler way, preferred by the JDK APIs - that is setting defaults for missing fields using parseDefaulting
. I think ideally we should switch towards this direction - of detecting missing fields at the point of constructing the formatter and adding their defaults there - instead of fighting with the parser here.
I did it for the quarter as there was no other way to do it apparently:
https://github.com/enso-org/enso/pull/7826/files#diff-9d5efa451e02ef4abbd6920679d8933499c9d53fe9a94cd5e404df8d0ffe8506R50-R54
But I think we could move all of this logic into it, and it would be cleaner.
@jdunkerley what do you think?
I'd like to do it but this PR is huge already so I don't want to introduce any further changes. I'd do it as a followup. It's also low priority since the current solution works OK, it just could be a bit cleaner.
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.
Agree - good to do this in the more standard way.
And yes a separate PR would be good!
Pull Request Description
YYYY
instead ofyyyy
in date format yields to parsing wrong year #7461 by introducing aDate_Time_Formatter
type and making parsing date time formats more robust and safer.M/m
andH/h
) to avoid theYYYY
vsyyyy
issues and make it less error prone.YYYY
now has the same meaning asyyyy
in simple mode. The old meaning (week-based year) is moved to a separate mode, triggered byDate_Time_Formatter.from_iso_week_date_pattern
.DateTimeFormatter
can also be used byDate_Time_Formatter.from_java
.ISO_ZONED_DATE_TIME
) have now become methods onDate_Time_Formatter
, e.g.Date_Time_Formatter.iso_zoned_date_time
).Important Notes
Checklist
Please ensure that the following checklist has been satisfied before submitting the PR:
Scala,
Java,
and
Rust
style guides. In case you are using a language not listed above, follow the Rust style guide.
./run ide build
.