Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
ad37564
SNOW-2246517: update docstrings and changelog
sfc-gh-fhe Aug 19, 2025
cfd23dc
SNOW-2246517: update changelog
sfc-gh-fhe Sep 3, 2025
9b3d66a
SNOW-2246517: add to test_types.py
sfc-gh-fhe Aug 6, 2025
7926ee3
SNOW-2246517: update docstrings and changelog
sfc-gh-fhe Aug 19, 2025
817b3d5
SNOW-2272863: remove extra change:
sfc-gh-fhe Aug 25, 2025
65abe59
SNOW-2272863: updated datatype mapper
sfc-gh-fhe Sep 8, 2025
8eaa504
SNOW-2272863: re-enable parameter
sfc-gh-fhe Sep 8, 2025
9a185cb
SNOW-2246517: Support YearMonthIntervalType
sfc-gh-fhe Aug 4, 2025
8d3a8ec
SNOW-2246517: update tests
sfc-gh-fhe Aug 6, 2025
e095a53
SNOW-2246517: add to test_types.py
sfc-gh-fhe Aug 6, 2025
745a6ba
SNOW-2246517: add tests to test_datatype_suite
sfc-gh-fhe Aug 7, 2025
4e65fc9
SNOW-2246517: revert change for start_field and end_field and determi…
sfc-gh-fhe Aug 7, 2025
46904d2
SNOW-2246517: add tests and xfail
sfc-gh-fhe Aug 13, 2025
092376b
SNOW-2246517: disable parameter
sfc-gh-fhe Aug 13, 2025
71de9a8
SNOW-2246517: remove xfails
sfc-gh-fhe Aug 14, 2025
fae094b
SNOW-2246517: update docstrings and changelog
sfc-gh-fhe Aug 19, 2025
1f05b88
SNOW-2246517: address comments, update tests, add comments
sfc-gh-fhe Aug 19, 2025
f2c9e47
SNOW-2246517: updated
sfc-gh-fhe Aug 22, 2025
a9d803b
SNOW-2246517: address nits
sfc-gh-fhe Sep 3, 2025
4f7d1ea
SNOW-2246517: remove redundant changes
sfc-gh-fhe Sep 4, 2025
82a1267
SNOW-2272863: add more tests
sfc-gh-fhe Aug 20, 2025
b03c6ba
SNOW-2272863: add more tests
sfc-gh-fhe Aug 21, 2025
0f7f0a8
SNOW-2272863: add skipifs
sfc-gh-fhe Aug 25, 2025
ff34b48
SNOW-2272863: Add DayTimeInterval support
sfc-gh-fhe Aug 19, 2025
f8ce1ca
SNOW-2296280: Add make_dt_interval function
sfc-gh-fhe Aug 25, 2025
bf31efe
SNOW-2296280: update tests and column name handling
sfc-gh-fhe Aug 26, 2025
4fb4e9e
SNOW-2296280: updated column name getter
sfc-gh-fhe Aug 26, 2025
9908689
SNOW-2296280: updated function name
sfc-gh-fhe Sep 3, 2025
75aa70a
SNOW-2296280: fix rebase and address comments
sfc-gh-fhe Sep 4, 2025
ac67608
SNOW-2296280: added emit ast handling
sfc-gh-fhe Sep 4, 2025
c8a073f
SNOW-2296280: update changelog
sfc-gh-fhe Sep 11, 2025
6cc144a
SNOW-2296280: remove redundant emit asts
sfc-gh-fhe Sep 11, 2025
02e801b
SNOW-2296280: added ast test
sfc-gh-fhe Sep 11, 2025
5739af1
SNOW-2296280: update
sfc-gh-fhe Sep 11, 2025
6ed919f
SNOW-2296280: updated again for graphite comment
sfc-gh-fhe Sep 11, 2025
425443c
SNOW-2296280: update dataframe
sfc-gh-fhe Sep 11, 2025
f24d9fe
SNOW-2296280: update show print
sfc-gh-fhe Sep 15, 2025
4e6f82e
SNOW-2296280: accept graphite change
sfc-gh-fhe Sep 15, 2025
062e602
SNOW-2296280: remove extra parameter
sfc-gh-fhe Sep 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- Added a new datatype `YearMonthIntervalType` that allows users to create intervals for datetime operations.
- Added a new function `interval_year_month_from_parts` that allows users to easily create `YearMonthIntervalType` without using SQL.
- Added a new datatype `DayTimeIntervalType` that allows users to create intervals for datetime operations.
- Added a new function `interval_day_time_from_parts` that allows users to easily create `DayTimeIntervalType` without using SQL.
- Added support for `FileOperation.list` to list files in a stage with metadata.
- Added support for `FileOperation.remove` to remove files in a stage.
- Added a new function `snowflake.snowpark.functions.vectorized` that allows users to mark a function as vectorized UDF.
Expand Down
1 change: 1 addition & 0 deletions docs/source/snowpark/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ Functions
initcap
insert
instr
interval_day_time_from_parts
interval_year_month_from_parts
invoker_role
invoker_share
Expand Down
154 changes: 150 additions & 4 deletions src/snowflake/snowpark/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -11000,11 +11000,10 @@ def interval_year_month_from_parts(
"""
ast = None
if _emit_ast:
# Always include both parameters to match the actual function execution
args = []
if years is not None:
args.append(years)
if months is not None:
args.append(months)
args.append(years if years is not None else lit(0))
args.append(months if months is not None else lit(0))
ast = build_function_expr("interval_year_month_from_parts", args)

years_col = (
Expand Down Expand Up @@ -11042,6 +11041,153 @@ def get_col_name(col):
return res


@private_preview(
version="1.38.0",
extra_doc_string="Type DayTimeIntervalType is currently in private preview and needs to be enabled by setting parameter `FEATURE_INTERVAL_TYPES` to `ENABLED`.",
)
@publicapi
def interval_day_time_from_parts(
Comment thread
sfc-gh-fhe marked this conversation as resolved.
Outdated
days: Optional[ColumnOrName] = None,
hours: Optional[ColumnOrName] = None,
mins: Optional[ColumnOrName] = None,
secs: Optional[ColumnOrName] = None,
_emit_ast: bool = True,
Comment thread
sfc-gh-fhe marked this conversation as resolved.
) -> Column:
"""
Creates a day-time interval expression using with specified days, hours, mins and seconds.

This DayTime is not to be confused with the interval created by make_interval.
You can define a table column to be of data type DayTimeIntervalType.

Args:
days: The number of days, positive or negative
hours: The number of hours, positive or negative
mins: The number of minutes, positive or negative
secs: The number of seconds, positive or negative

Returns:
A Column representing a day-time interval

Example::

>>> from snowflake.snowpark.functions import interval_day_time_from_parts
>>>
>>> _ = session.sql("ALTER SESSION SET FEATURE_INTERVAL_TYPES=ENABLED;").collect()
>>> df = session.create_dataframe([[1, 12, 30, 01.001001]], ['day', 'hour', 'min', 'sec'])
>>> df.select(interval_day_time_from_parts(col("day"), col("hour"), col("min"), col("sec")).alias("interval")).show()
--------------------------
|"INTERVAL" |
--------------------------
|1 day, 12:30:01.001000 |
--------------------------
<BLANKLINE>

"""
# Handle AST emission
ast = None
if _emit_ast:
# Create AST for this custom function using build_function_expr
# Always include all 4 parameters to match the actual function execution
args = []
args.append(days if days is not None else lit(0))
args.append(hours if hours is not None else lit(0))
args.append(mins if mins is not None else lit(0))
args.append(secs if secs is not None else lit(0))
ast = build_function_expr("interval_day_time_from_parts", args)

days_col = (
lit(0) if days is None else _to_col_if_str(days, "interval_day_time_from_parts")
)
hours_col = (
lit(0)
if hours is None
else _to_col_if_str(hours, "interval_day_time_from_parts")
)
mins_col = (
lit(0) if mins is None else _to_col_if_str(mins, "interval_day_time_from_parts")
)
secs_col = (
lit(0) if secs is None else _to_col_if_str(secs, "interval_day_time_from_parts")
)

total_seconds = (
days_col * lit(86400) + hours_col * lit(3600) + mins_col * lit(60) + secs_col
)

is_negative = total_seconds < lit(0)
abs_total_seconds = abs(total_seconds)

days_part = cast(floor(abs_total_seconds / lit(86400)), "int")
remaining_after_days = abs_total_seconds % lit(86400)

hours_part = cast(floor(remaining_after_days / lit(3600)), "int")
remaining_after_hours = remaining_after_days % lit(3600)

mins_part = cast(floor(remaining_after_hours / lit(60)), "int")
secs_part = remaining_after_hours % lit(60)

hours_str = iff(
hours_part < lit(10),
concat(lit("0"), cast(hours_part, "str")),
cast(hours_part, "str"),
)

mins_str = iff(
mins_part < lit(10),
concat(lit("0"), cast(mins_part, "str")),
cast(mins_part, "str"),
)

secs_int = cast(floor(secs_part), "int")
secs_str = iff(
secs_int < lit(10),
concat(lit("0"), cast(secs_int, "str")),
cast(secs_int, "str"),
)

has_fraction = abs(secs_part - cast(secs_int, "double")) > 1e-10
fractional_part = secs_part - cast(secs_int, "double")

fraction_str = iff(
has_fraction,
concat(
lit("."),
lpad(
cast(round(fractional_part * lit(1000), 0), "str"),
3,
lit("0"),
),
),
lit(""),
)

secs_formatted = concat(secs_str, fraction_str)

sign_prefix = iff(is_negative, lit("-"), lit(""))
interval_value = concat(
sign_prefix,
cast(days_part, "str"),
lit(" "),
hours_str,
lit(":"),
mins_str,
lit(":"),
secs_formatted,
)

def get_col_name(col):
if isinstance(col._expr1, Literal):
return str(col._expr1.value)
else:
return str(col._expr1)
Comment thread
sfc-gh-fhe marked this conversation as resolved.
Outdated

alias_name = f"interval_day_time_from_parts({get_col_name(days_col)}, {get_col_name(hours_col)}, {get_col_name(mins_col)}, {get_col_name(secs_col)})"

res = cast(interval_value, "INTERVAL DAY TO SECOND").alias(alias_name)
res._ast = ast
return res


@publicapi
@deprecated(
version="1.28.0",
Expand Down
102 changes: 102 additions & 0 deletions tests/ast/data/functions2.test
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,8 @@ df351 = df.select(function("avg")("B"))

df352 = df.select(interval_year_month_from_parts("A", "B"))

df353 = df.select(interval_day_time_from_parts("A", "B", "C", "D"))

## EXPECTED UNPARSER OUTPUT

df = session.table("table1")
Expand Down Expand Up @@ -900,6 +902,8 @@ df351 = df.select(call_function("avg", "B"))

df352 = df.select(interval_year_month_from_parts("A", "B"))

df353 = df.select(interval_day_time_from_parts("A", "B", "C", "D"))

## EXPECTED ENCODED AST

interned_value_table {
Expand Down Expand Up @@ -29253,6 +29257,104 @@ body {
uid: 224
}
}
body {
bind {
expr {
dataframe_select {
cols {
args {
apply_expr {
fn {
builtin_fn {
name {
name {
name_flat {
name: "interval_day_time_from_parts"
}
}
}
}
}
pos_args {
string_val {
src {
end_column: 74
end_line: 475
file: 2
start_column: 26
start_line: 475
}
v: "A"
}
}
pos_args {
string_val {
src {
end_column: 74
end_line: 475
file: 2
start_column: 26
start_line: 475
}
v: "B"
}
}
pos_args {
string_val {
src {
end_column: 74
end_line: 475
file: 2
start_column: 26
start_line: 475
}
v: "C"
}
}
pos_args {
string_val {
src {
end_column: 74
end_line: 475
file: 2
start_column: 26
start_line: 475
}
v: "D"
}
}
src {
end_column: 74
end_line: 475
file: 2
start_column: 26
start_line: 475
}
}
}
variadic: true
}
df {
dataframe_ref {
id: 1
}
}
src {
end_column: 75
end_line: 475
file: 2
start_column: 16
start_line: 475
}
}
}
first_request_id: "\003U\"\366q\366P\346\260\261?\234\303\254\316\353"
symbol {
value: "df353"
}
uid: 225
}
}
client_ast_version: 1
client_language {
python_language {
Expand Down
2 changes: 1 addition & 1 deletion tests/integ/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ def session(
.config("local_testing", local_testing_mode)
.config(
"session_parameters",
{"feature_interval_types": "ENABLED", "enable_interval_subtypes": "true"},
{"feature_interval_types": "ENABLED"},
)
.create()
)
Expand Down
Loading
Loading