-
Notifications
You must be signed in to change notification settings - Fork 29k
[SPARK-31771][SQL] Disable Narrow TextStyle for datetime pattern 'G/M/L/E/u/Q/q' #28592
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
Changes from 11 commits
78fb74a
e178a6b
d5b5a9c
1d31ed2
1144c03
549a122
c877ac5
b2abeeb
1503042
052bfad
8141ef9
4491e79
09b407f
75fdbcb
0a76ba3
5360d88
ee1d62a
3047f88
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,7 @@ package org.apache.spark.sql.catalyst.util | |
|
|
||
| import java.text.SimpleDateFormat | ||
| import java.time.{LocalDate, ZoneId} | ||
| import java.time.format.DateTimeFormatter | ||
| import java.util.{Date, Locale} | ||
|
|
||
| import org.apache.commons.lang3.time.FastDateFormat | ||
|
|
@@ -33,6 +34,8 @@ sealed trait DateFormatter extends Serializable { | |
| def format(days: Int): String | ||
| def format(date: Date): String | ||
| def format(localDate: LocalDate): String | ||
|
|
||
| def initialize(): Unit = {} | ||
|
||
| } | ||
|
|
||
| class Iso8601DateFormatter( | ||
|
|
@@ -43,7 +46,11 @@ class Iso8601DateFormatter( | |
| extends DateFormatter with DateTimeFormatterHelper { | ||
|
|
||
| @transient | ||
| private lazy val formatter = getOrCreateFormatter(pattern, locale) | ||
| private lazy val formatter: DateTimeFormatter = { | ||
| try { | ||
| getOrCreateFormatter(pattern, locale) | ||
| } catch checkLegacyFormatter(pattern, legacyFormatter.initialize) | ||
| } | ||
|
|
||
| @transient | ||
| private lazy val legacyFormatter = DateFormatter.getLegacyFormatter( | ||
|
|
@@ -93,13 +100,16 @@ class LegacyFastDateFormatter(pattern: String, locale: Locale) extends LegacyDat | |
| private lazy val fdf = FastDateFormat.getInstance(pattern, locale) | ||
yaooqinn marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| override def parseToDate(s: String): Date = fdf.parse(s) | ||
| override def format(d: Date): String = fdf.format(d) | ||
| override def initialize(): Unit = fdf | ||
| } | ||
|
|
||
| class LegacySimpleDateFormatter(pattern: String, locale: Locale) extends LegacyDateFormatter { | ||
| @transient | ||
| private lazy val sdf = new SimpleDateFormat(pattern, locale) | ||
| override def parseToDate(s: String): Date = sdf.parse(s) | ||
| override def format(d: Date): String = sdf.format(d) | ||
| override def initialize(): Unit = sdf | ||
|
|
||
| } | ||
|
|
||
| object DateFormatter { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -86,6 +86,33 @@ trait DateTimeFormatterHelper { | |
| throw e | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * When the new DateTimeFormatter failed to initialize because of invalid datetime pattern, it | ||
| * will throw IllegalArgumentException. If the pattern can be recognized by the legacy formatter | ||
| * it will raise SparkUpgradeException to tell users to restore the previous behavior via LEGACY | ||
| * policy or follow our guide to correct their pattern. Otherwise, the original | ||
| * IllegalArgumentException will be thrown. | ||
| * | ||
| * @param pattern the date time pattern | ||
| * @param block a func to capture exception, identically which forces a legacy datetime formatter | ||
|
||
| * to be initialized | ||
| */ | ||
|
|
||
| protected def checkLegacyFormatter( | ||
| pattern: String, | ||
| block: => Unit): PartialFunction[Throwable, DateTimeFormatter] = { | ||
| case e: IllegalArgumentException => | ||
| try { | ||
| block | ||
| } catch { | ||
| case _: Throwable => throw e | ||
| } | ||
| throw new SparkUpgradeException("3.0", s"Fail to recognize '$pattern' pattern in the" + | ||
| s" new parser. 1) You can set ${SQLConf.LEGACY_TIME_PARSER_POLICY.key} to LEGACY to" + | ||
|
||
| s" restore the behavior before Spark 3.0. 2) You can form a valid datetime pattern with" + | ||
| s" the guide from https://spark.apache.org/docs/latest/sql-ref-datetime-pattern.html", e) | ||
| } | ||
| } | ||
|
|
||
| private object DateTimeFormatterHelper { | ||
|
|
@@ -163,6 +190,8 @@ private object DateTimeFormatterHelper { | |
| } | ||
|
|
||
| final val unsupportedLetters = Set('A', 'c', 'e', 'n', 'N', 'p') | ||
| final val unsupportedNarrowTextStyle = | ||
| Set("GGGGG", "MMMMM", "LLLLL", "EEEEE", "uuuuu", "QQQQQ", "qqqqq") | ||
|
|
||
| /** | ||
| * In Spark 3.0, we switch to the Proleptic Gregorian calendar and use DateTimeFormatter for | ||
|
|
@@ -184,6 +213,9 @@ private object DateTimeFormatterHelper { | |
| for (c <- patternPart if unsupportedLetters.contains(c)) { | ||
| throw new IllegalArgumentException(s"Illegal pattern character: $c") | ||
| } | ||
| for (style <- unsupportedNarrowTextStyle if patternPart.contains(style)) { | ||
| throw new IllegalArgumentException(s"Too many pattern letters: ${style.head}") | ||
| } | ||
| // The meaning of 'u' was day number of week in SimpleDateFormat, it was changed to year | ||
| // in DateTimeFormatter. Substitute 'u' to 'e' and use DateTimeFormatter to parse the | ||
| // string. If parsable, return the result; otherwise, fall back to 'u', and then use the | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| --SET spark.sql.legacy.timeParserPolicy=LEGACY | ||
| --IMPORT datetime.sql |
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.
AM/PM(a)->am-pm