@@ -96,7 +96,7 @@ class TimestampFormatterSuite extends SparkFunSuite with SQLHelper with Matchers
96
96
2177456523456789L ,
97
97
11858049903010203L ).foreach { micros =>
98
98
outstandingZoneIds.foreach { zoneId =>
99
- val timestamp = TimestampFormatter (pattern, zoneId).format(micros)
99
+ val timestamp = TimestampFormatter (pattern, zoneId, isParsing = false ).format(micros)
100
100
val parsed = TimestampFormatter (
101
101
pattern, zoneId, isParsing = true ).parse(timestamp)
102
102
assert(micros === parsed)
@@ -120,14 +120,14 @@ class TimestampFormatterSuite extends SparkFunSuite with SQLHelper with Matchers
120
120
val pattern = " yyyy-MM-dd'T'HH:mm:ss.SSSSSS"
121
121
val micros = TimestampFormatter (
122
122
pattern, zoneId, isParsing = true ).parse(timestamp)
123
- val formatted = TimestampFormatter (pattern, zoneId).format(micros)
123
+ val formatted = TimestampFormatter (pattern, zoneId, isParsing = false ).format(micros)
124
124
assert(timestamp === formatted)
125
125
}
126
126
}
127
127
}
128
128
129
129
test(" case insensitive parsing of am and pm" ) {
130
- val formatter = TimestampFormatter (" yyyy MMM dd hh:mm:ss a" , UTC )
130
+ val formatter = TimestampFormatter (" yyyy MMM dd hh:mm:ss a" , UTC , isParsing = false )
131
131
val micros = formatter.parse(" 2009 Mar 20 11:30:01 am" )
132
132
assert(micros === date(2009 , 3 , 20 , 11 , 30 , 1 ))
133
133
}
@@ -157,8 +157,8 @@ class TimestampFormatterSuite extends SparkFunSuite with SQLHelper with Matchers
157
157
assert(TimestampFormatter (UTC ).format(micros) === " -0099-01-01 00:00:00" )
158
158
assert(TimestampFormatter (UTC ).format(instant) === " -0099-01-01 00:00:00" )
159
159
withDefaultTimeZone(UTC ) { // toJavaTimestamp depends on the default time zone
160
- assert(TimestampFormatter (" yyyy-MM-dd HH:mm:SS G" , UTC ).format(toJavaTimestamp(micros) )
161
- === " 0100-01-01 00:00:00 BC" )
160
+ assert(TimestampFormatter (" yyyy-MM-dd HH:mm:SS G" , UTC , isParsing = false )
161
+ .format(toJavaTimestamp(micros)) === " 0100-01-01 00:00:00 BC" )
162
162
}
163
163
}
164
164
@@ -209,7 +209,7 @@ class TimestampFormatterSuite extends SparkFunSuite with SQLHelper with Matchers
209
209
" 2019-10-14T09:39:07.1" , " 2019-10-14T09:39:07.1" )
210
210
211
211
try {
212
- TimestampFormatter (" yyyy/MM/dd HH_mm_ss.SSSSSS" , zoneId, true )
212
+ TimestampFormatter (" yyyy/MM/dd HH_mm_ss.SSSSSS" , zoneId, isParsing = true )
213
213
.parse(" 2019/11/14 20#25#30.123456" )
214
214
fail(" Expected to throw an exception for the invalid input" )
215
215
} catch {
@@ -222,7 +222,7 @@ class TimestampFormatterSuite extends SparkFunSuite with SQLHelper with Matchers
222
222
test(" formatting timestamp strings up to microsecond precision" ) {
223
223
outstandingZoneIds.foreach { zoneId =>
224
224
def check (pattern : String , input : String , expected : String ): Unit = {
225
- val formatter = TimestampFormatter (pattern, zoneId)
225
+ val formatter = TimestampFormatter (pattern, zoneId, isParsing = false )
226
226
val timestamp = stringToTimestamp(UTF8String .fromString(input), zoneId).get
227
227
val actual = formatter.format(timestamp)
228
228
assert(actual === expected)
@@ -259,7 +259,7 @@ class TimestampFormatterSuite extends SparkFunSuite with SQLHelper with Matchers
259
259
}
260
260
261
261
test(" SPARK-30958: parse timestamp with negative year" ) {
262
- val formatter1 = TimestampFormatter (" yyyy-MM-dd HH:mm:ss" , UTC , true )
262
+ val formatter1 = TimestampFormatter (" yyyy-MM-dd HH:mm:ss" , UTC , isParsing = true )
263
263
assert(formatter1.parse(" -1234-02-22 02:22:22" ) === date(- 1234 , 2 , 22 , 2 , 22 , 22 ))
264
264
265
265
def assertParsingError (f : => Unit ): Unit = {
@@ -272,7 +272,7 @@ class TimestampFormatterSuite extends SparkFunSuite with SQLHelper with Matchers
272
272
}
273
273
274
274
// "yyyy" with "G" can't parse negative year or year 0000.
275
- val formatter2 = TimestampFormatter (" G yyyy-MM-dd HH:mm:ss" , UTC , true )
275
+ val formatter2 = TimestampFormatter (" G yyyy-MM-dd HH:mm:ss" , UTC , isParsing = true )
276
276
assertParsingError(formatter2.parse(" BC -1234-02-22 02:22:22" ))
277
277
assertParsingError(formatter2.parse(" AC 0000-02-22 02:22:22" ))
278
278
@@ -318,7 +318,7 @@ class TimestampFormatterSuite extends SparkFunSuite with SQLHelper with Matchers
318
318
test(" parsing hour with various patterns" ) {
319
319
def createFormatter (pattern : String ): TimestampFormatter = {
320
320
// Use `SIMPLE_DATE_FORMAT`, so that the legacy parser also fails with invalid value range.
321
- TimestampFormatter (pattern, UTC , LegacyDateFormats .SIMPLE_DATE_FORMAT , false )
321
+ TimestampFormatter (pattern, UTC , LegacyDateFormats .SIMPLE_DATE_FORMAT , isParsing = false )
322
322
}
323
323
324
324
withClue(" HH" ) {
@@ -377,38 +377,68 @@ class TimestampFormatterSuite extends SparkFunSuite with SQLHelper with Matchers
377
377
}
378
378
379
379
test(" missing date fields" ) {
380
- val formatter = TimestampFormatter (" HH:mm:ss" , UTC )
380
+ val formatter = TimestampFormatter (" HH:mm:ss" , UTC , isParsing = true )
381
381
val micros = formatter.parse(" 11:30:01" )
382
382
assert(micros === date(1970 , 1 , 1 , 11 , 30 , 1 ))
383
383
}
384
384
385
385
test(" missing year field with invalid date" ) {
386
386
// Use `SIMPLE_DATE_FORMAT`, so that the legacy parser also fails with invalid date.
387
- val formatter = TimestampFormatter (" MM-dd" , UTC , LegacyDateFormats .SIMPLE_DATE_FORMAT , false )
387
+ val formatter =
388
+ TimestampFormatter (" MM-dd" , UTC , LegacyDateFormats .SIMPLE_DATE_FORMAT , isParsing = false )
388
389
withDefaultTimeZone(UTC )(intercept[DateTimeException ](formatter.parse(" 02-29" )))
389
390
}
390
391
391
392
test(" missing am/pm field" ) {
392
- val formatter = TimestampFormatter (" yyyy hh:mm:ss" , UTC )
393
+ val formatter = TimestampFormatter (" yyyy hh:mm:ss" , UTC , isParsing = true )
393
394
val micros = formatter.parse(" 2009 11:30:01" )
394
395
assert(micros === date(2009 , 1 , 1 , 11 , 30 , 1 ))
395
396
}
396
397
397
398
test(" missing time fields" ) {
398
- val formatter = TimestampFormatter (" yyyy HH" , UTC )
399
+ val formatter = TimestampFormatter (" yyyy HH" , UTC , isParsing = true )
399
400
val micros = formatter.parse(" 2009 11" )
400
401
assert(micros === date(2009 , 1 , 1 , 11 ))
401
402
}
402
403
403
404
test(" explicitly forbidden datetime patterns" ) {
404
405
// not support by the legacy one too
405
406
Seq (" QQQQQ" , " qqqqq" , " A" , " c" , " e" , " n" , " N" , " p" ).foreach { pattern =>
406
- intercept[IllegalArgumentException ](TimestampFormatter (pattern, UTC ).format(0 ))
407
+ intercept[IllegalArgumentException ](TimestampFormatter (pattern, UTC , isParsing = false )
408
+ .format(0 ))
407
409
}
408
410
// supported by the legacy one, then we will suggest users with SparkUpgradeException
409
- Seq (" GGGGG" , " MMMMM" , " LLLLL" , " EEEEE" , " uuuuu" , " aa" , " aaa" , " y" * 11 , " y " * 11 )
411
+ Seq (" GGGGG" , " MMMMM" , " LLLLL" , " EEEEE" , " uuuuu" , " aa" , " aaa" , " y" * 11 , " Y " * 11 )
410
412
.foreach { pattern =>
411
- intercept[SparkUpgradeException ](TimestampFormatter (pattern, UTC ).format(0 ))
413
+ intercept[SparkUpgradeException ] {
414
+ TimestampFormatter (pattern, UTC , isParsing = false ).format(0 )
415
+ }
416
+ }
417
+ }
418
+
419
+ test(" Disable week-based date fields and quarter fields for parsing" ) {
420
+
421
+ def checkSparkUpgrade (c : Char ): Unit = {
422
+ intercept[SparkUpgradeException ] {
423
+ TimestampFormatter (c.toString, UTC , isParsing = true )
424
+ }
425
+ assert(TimestampFormatter (c.toString, UTC , isParsing = false ).format(0 ).nonEmpty)
426
+ }
427
+
428
+ def checkIllegalArg (c : Char ): Unit = {
429
+ intercept[IllegalArgumentException ] {
430
+ TimestampFormatter (c.toString, UTC , isParsing = true )
431
+ }
432
+
433
+ assert(TimestampFormatter (c.toString, UTC , isParsing = false ).format(0 ).nonEmpty)
434
+ }
435
+
436
+ Seq ('Y' , 'W' , 'w' , 'E' , 'u' , 'F' ).foreach { l =>
437
+ checkSparkUpgrade(l)
438
+ }
439
+
440
+ Seq ('q' , 'Q' ).foreach { l =>
441
+ checkIllegalArg(l)
412
442
}
413
443
}
414
444
}
0 commit comments