Skip to content

Commit af972cf

Browse files
committed
SNOW-2346552: added testing
1 parent 872f5fa commit af972cf

2 files changed

Lines changed: 223 additions & 9 deletions

File tree

src/snowflake/snowpark/dataframe.py

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -212,11 +212,11 @@
212212
StringType,
213213
StructField,
214214
StructType,
215-
YearMonthIntervalType,
216215
_NumericType,
217216
_FractionalType,
218217
TimestampType,
219218
TimestampTimeZone,
219+
YearMonthIntervalType,
220220
)
221221

222222
# Python 3.8 needs to use typing.Iterable because collections.abc.Iterable is not subscriptable
@@ -5240,24 +5240,65 @@ def format_day_time_interval(total_seconds_float: float) -> str:
52405240
return f"{sign}{days}"
52415241
elif start_field == DayTimeIntervalType.HOUR:
52425242
total_hours = int(abs_total_seconds) // 3600
5243-
return f"{sign}{total_hours:02d}"
5243+
return (
5244+
f"{sign}{total_hours:02d}"
5245+
if total_hours < 10
5246+
else f"{sign}{total_hours}"
5247+
)
52445248
elif start_field == DayTimeIntervalType.MINUTE:
52455249
total_minutes = int(abs_total_seconds) // 60
5246-
return f"{sign}{total_minutes}"
5250+
return (
5251+
f"{sign}{total_minutes:02d}"
5252+
if total_minutes < 10
5253+
else f"{sign}{total_minutes}"
5254+
)
52475255
elif start_field == DayTimeIntervalType.SECOND:
52485256
# Handle fractional seconds - use total seconds, not just remainder
52495257
if abs_total_seconds == int(abs_total_seconds):
5250-
return f"{sign}{int(abs_total_seconds)}"
5258+
total_secs_int = int(abs_total_seconds)
5259+
return (
5260+
f"{sign}{total_secs_int:02d}"
5261+
if total_secs_int < 10
5262+
else f"{sign}{total_secs_int}"
5263+
)
52515264
else:
5252-
return f"{sign}{abs_total_seconds:g}"
5265+
# For fractional seconds, format with leading zero if < 10
5266+
if abs_total_seconds < 10:
5267+
# Format with leading zero: split into integer and fractional parts
5268+
integer_part = int(abs_total_seconds)
5269+
fractional_part = abs_total_seconds - integer_part
5270+
if fractional_part == 0:
5271+
return f"{sign}{integer_part:02d}"
5272+
else:
5273+
# Format fractional part and remove leading '0.'
5274+
frac_str = f"{fractional_part:.6f}"[2:].rstrip(
5275+
"0"
5276+
)
5277+
return f"{sign}{integer_part:02d}.{frac_str}"
5278+
else:
5279+
return f"{sign}{abs_total_seconds:g}"
52535280

52545281
# For multi-field intervals, format based on start/end fields
52555282
if start_field == DayTimeIntervalType.DAY:
5256-
# DAY TO X format: "D HH:MM:SS"
5257-
if seconds == int(seconds):
5258-
return f"{sign}{days} {hours:02d}:{minutes:02d}:{int(seconds):02d}"
5283+
# DAY TO X format: truncate based on end_field
5284+
if end_field == DayTimeIntervalType.HOUR:
5285+
# DAY TO HOUR: "D HH"
5286+
return (
5287+
f"{sign}{days} {hours:02d}"
5288+
if hours < 10
5289+
else f"{sign}{days} {hours}"
5290+
)
5291+
elif end_field == DayTimeIntervalType.MINUTE:
5292+
# DAY TO MINUTE: "D HH:MM"
5293+
hours_str = f"{hours:02d}" if hours < 10 else f"{hours}"
5294+
return f"{sign}{days} {hours_str}:{minutes:02d}"
52595295
else:
5260-
return f"{sign}{days} {hours:02d}:{minutes:02d}:{seconds:06.3f}"
5296+
# DAY TO SECOND: "D HH:MM:SS"
5297+
hours_str = f"{hours:02d}" if hours < 10 else f"{hours}"
5298+
if seconds == int(seconds):
5299+
return f"{sign}{days} {hours_str}:{minutes:02d}:{int(seconds):02d}"
5300+
else:
5301+
return f"{sign}{days} {hours_str}:{minutes:02d}:{seconds:06.3f}"
52615302
elif start_field == DayTimeIntervalType.HOUR:
52625303
# HOUR TO X format: "HH:MM:SS" (no days)
52635304
total_hours = int(abs_total_seconds) // 3600

tests/integ/test_dataframe.py

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2536,6 +2536,179 @@ def assert_show_string_equals(actual: str, expected: str):
25362536
)
25372537

25382538

2539+
@pytest.mark.skipif(
2540+
"config.getoption('local_testing_mode', default=False)",
2541+
reason="FEAT: Interval types not fully supported in local testing",
2542+
)
2543+
def test_show_interval_formatting(session):
2544+
df = session.sql("SELECT INTERVAL '1' HOUR as hour_single")
2545+
assert df._show_string_spark(truncate=False) == dedent(
2546+
"""\
2547+
+------------------+
2548+
|"HOUR_SINGLE" |
2549+
+------------------+
2550+
|INTERVAL '01' HOUR|
2551+
+------------------+
2552+
"""
2553+
)
2554+
2555+
df = session.sql("SELECT INTERVAL '5' MINUTE as minute_single")
2556+
assert df._show_string_spark(truncate=False) == dedent(
2557+
"""\
2558+
+--------------------+
2559+
|"MINUTE_SINGLE" |
2560+
+--------------------+
2561+
|INTERVAL '05' MINUTE|
2562+
+--------------------+
2563+
"""
2564+
)
2565+
2566+
df = session.sql("SELECT INTERVAL '5' SECOND as second_integer")
2567+
assert df._show_string_spark(truncate=False) == dedent(
2568+
"""\
2569+
+--------------------+
2570+
|"SECOND_INTEGER" |
2571+
+--------------------+
2572+
|INTERVAL '05' SECOND|
2573+
+--------------------+
2574+
"""
2575+
)
2576+
2577+
df = session.sql("SELECT INTERVAL '1.000001' SECOND as second_microseconds")
2578+
assert df._show_string_spark(truncate=False) == dedent(
2579+
"""\
2580+
+---------------------------+
2581+
|"SECOND_MICROSECONDS" |
2582+
+---------------------------+
2583+
|INTERVAL '01.000001' SECOND|
2584+
+---------------------------+
2585+
"""
2586+
)
2587+
2588+
df = session.sql("SELECT INTERVAL '24' HOUR as hour_full_day")
2589+
assert df._show_string_spark(truncate=False) == dedent(
2590+
"""\
2591+
+------------------+
2592+
|"HOUR_FULL_DAY" |
2593+
+------------------+
2594+
|INTERVAL '24' HOUR|
2595+
+------------------+
2596+
"""
2597+
)
2598+
2599+
df = session.sql("SELECT INTERVAL '90' MINUTE as minute_over_hour")
2600+
assert df._show_string_spark(truncate=False) == dedent(
2601+
"""\
2602+
+--------------------+
2603+
|"MINUTE_OVER_HOUR" |
2604+
+--------------------+
2605+
|INTERVAL '90' MINUTE|
2606+
+--------------------+
2607+
"""
2608+
)
2609+
2610+
df = session.sql("SELECT INTERVAL '0' SECOND as zero_second")
2611+
assert df._show_string_spark(truncate=False) == dedent(
2612+
"""\
2613+
+--------------------+
2614+
|"ZERO_SECOND" |
2615+
+--------------------+
2616+
|INTERVAL '00' SECOND|
2617+
+--------------------+
2618+
"""
2619+
)
2620+
2621+
df = session.sql("SELECT INTERVAL '0.000001' SECOND as microsecond")
2622+
assert df._show_string_spark(truncate=False) == dedent(
2623+
"""\
2624+
+---------------------------+
2625+
|"MICROSECOND" |
2626+
+---------------------------+
2627+
|INTERVAL '00.000001' SECOND|
2628+
+---------------------------+
2629+
"""
2630+
)
2631+
2632+
df = session.sql("SELECT INTERVAL '2 12' DAY TO HOUR as day_to_hour")
2633+
assert df._show_string_spark(truncate=False) == dedent(
2634+
"""\
2635+
+---------------------------+
2636+
|"DAY_TO_HOUR" |
2637+
+---------------------------+
2638+
|INTERVAL '2 12' DAY TO HOUR|
2639+
+---------------------------+
2640+
"""
2641+
)
2642+
2643+
df = session.sql("SELECT INTERVAL '1 08:30' DAY TO MINUTE as day_to_minute")
2644+
assert df._show_string_spark(truncate=False) == dedent(
2645+
"""\
2646+
+--------------------------------+
2647+
|"DAY_TO_MINUTE" |
2648+
+--------------------------------+
2649+
|INTERVAL '1 08:30' DAY TO MINUTE|
2650+
+--------------------------------+
2651+
"""
2652+
)
2653+
2654+
df = session.sql("SELECT INTERVAL '08:30' HOUR TO MINUTE as hour_to_minute")
2655+
assert df._show_string_spark(truncate=False) == dedent(
2656+
"""\
2657+
+-------------------------------+
2658+
|"HOUR_TO_MINUTE" |
2659+
+-------------------------------+
2660+
|INTERVAL '08:30' HOUR TO MINUTE|
2661+
+-------------------------------+
2662+
"""
2663+
)
2664+
2665+
df = session.sql(
2666+
"SELECT INTERVAL '01:00:00.456' HOUR TO SECOND as hour_to_second_fractional"
2667+
)
2668+
assert df._show_string_spark(truncate=False) == dedent(
2669+
"""\
2670+
+--------------------------------------+
2671+
|"HOUR_TO_SECOND_FRACTIONAL" |
2672+
+--------------------------------------+
2673+
|INTERVAL '01:00:00.456' HOUR TO SECOND|
2674+
+--------------------------------------+
2675+
"""
2676+
)
2677+
2678+
df = session.sql("SELECT INTERVAL '-2' HOUR as negative_hour")
2679+
assert df._show_string_spark(truncate=False) == dedent(
2680+
"""\
2681+
+-------------------+
2682+
|"NEGATIVE_HOUR" |
2683+
+-------------------+
2684+
|INTERVAL '-02' HOUR|
2685+
+-------------------+
2686+
"""
2687+
)
2688+
2689+
df = session.sql("SELECT INTERVAL '-15.5' SECOND as negative_second")
2690+
assert df._show_string_spark(truncate=False) == dedent(
2691+
"""\
2692+
+-----------------------+
2693+
|"NEGATIVE_SECOND" |
2694+
+-----------------------+
2695+
|INTERVAL '-15.5' SECOND|
2696+
+-----------------------+
2697+
"""
2698+
)
2699+
2700+
df = session.sql("SELECT INTERVAL '999999' SECOND as large_second")
2701+
assert df._show_string_spark(truncate=False) == dedent(
2702+
"""\
2703+
+------------------------+
2704+
|"LARGE_SECOND" |
2705+
+------------------------+
2706+
|INTERVAL '999999' SECOND|
2707+
+------------------------+
2708+
"""
2709+
)
2710+
2711+
25392712
@pytest.mark.parametrize("data", [[0, 1, 2, 3], ["", "a"], [False, True], [None]])
25402713
def test_create_dataframe_with_single_value(session, data):
25412714
expected_names = ["_1"]

0 commit comments

Comments
 (0)