JavaScript returns 错误日期的雪花 UDF
Snowflake UDF with JavaScript returns incorrect dates
我遇到了一个问题,我的用户定义函数 (UDF) 在 Snowflake 中使用 JavaScript 语言实现 return 无效日期,它获得了一天。
为了演示问题,这里是一个简单的 UDF,它采用三个参数年、月、日和 returns 日期对象。
CREATE OR REPLACE FUNCTION JDC(YEAR FLOAT,MONTH FLOAT,DAY FLOAT)
RETURNS DATE
LANGUAGE JAVASCRIPT
AS
$$
// In Java Script months start with 0 so -1
return new Date(YEAR,MONTH-1,DAY)
$$
;
调用此过程 return 所有年份的正确值,除了 1942 年到 1949 年之间的几天,
select JDC(1942,02,10);
returns 1942-02-11 这是不正确的
select JDC(1948,12,31);
returns 1949-01-01 这是不正确的
select JDC(2020,02,10);
returns 2020-02-10,正确值
如果您注意到 1、2,它会在 javascript 日期转换为雪花型期间增加一天。我确认 JavaScript 能够通过将 UDF return 类型更改为 VARCHAR 并将日期对象 return 设置为 return new Date(YEAR,MONTH-1,DAY).toString()
之类的字符串来 return 返回正确的值,所以转换期间继续。
默认情况下 JavaScript 使用 UTC 时区,我当前的 snowflake 实例设置为 PST 时区的 运行,所以考虑时区方面的转换应该回到前一天但令人惊讶的是它以其他方式.
作为解决方法,您可以使用本机功能:
DATE_FROM_PARTS( <year>, <month>, <day> )
Creates a date from individual numeric components that represent the year, month, and day of the month.
SELECT DATE_FROM_PARTS(1942,2,10)
为避免 Snowflake 会话和 JavaScript 之间奇怪的时区转换,请将您自己的时区设置为 GMT:
ALTER SESSION SET TIMEZONE = 'America/New_York';
select JDC(1942,02,10);
# `1942-02-11` wrong
ALTER SESSION SET TIMEZONE = 'GMT';
select JDC(1942,02,10);
# `1942-02-10`, as expected.
Javascript 对于日期、时间和时区很奇怪——正如您所注意到的,月份是基于 0 的,而构造函数中的其余日期不是。另一个问题是 Javascript 没有只有“日期”的构造函数——因为 Date() 代表日期时间。
来自文档:
JavaScript Date objects are converted to the UDF’s result data type, adhering to the same conversion semantics as casts from TIMESTAMP_LTZ(3) to the return data type.
https://docs.snowflake.com/en/sql-reference/udf-js.html#dates
我遇到了一个问题,我的用户定义函数 (UDF) 在 Snowflake 中使用 JavaScript 语言实现 return 无效日期,它获得了一天。
为了演示问题,这里是一个简单的 UDF,它采用三个参数年、月、日和 returns 日期对象。
CREATE OR REPLACE FUNCTION JDC(YEAR FLOAT,MONTH FLOAT,DAY FLOAT)
RETURNS DATE
LANGUAGE JAVASCRIPT
AS
$$
// In Java Script months start with 0 so -1
return new Date(YEAR,MONTH-1,DAY)
$$
;
调用此过程 return 所有年份的正确值,除了 1942 年到 1949 年之间的几天,
select JDC(1942,02,10);
returns 1942-02-11 这是不正确的select JDC(1948,12,31);
returns 1949-01-01 这是不正确的select JDC(2020,02,10);
returns 2020-02-10,正确值
如果您注意到 1、2,它会在 javascript 日期转换为雪花型期间增加一天。我确认 JavaScript 能够通过将 UDF return 类型更改为 VARCHAR 并将日期对象 return 设置为 return new Date(YEAR,MONTH-1,DAY).toString()
之类的字符串来 return 返回正确的值,所以转换期间继续。
默认情况下 JavaScript 使用 UTC 时区,我当前的 snowflake 实例设置为 PST 时区的 运行,所以考虑时区方面的转换应该回到前一天但令人惊讶的是它以其他方式.
作为解决方法,您可以使用本机功能:
DATE_FROM_PARTS( <year>, <month>, <day> )
Creates a date from individual numeric components that represent the year, month, and day of the month.
SELECT DATE_FROM_PARTS(1942,2,10)
为避免 Snowflake 会话和 JavaScript 之间奇怪的时区转换,请将您自己的时区设置为 GMT:
ALTER SESSION SET TIMEZONE = 'America/New_York';
select JDC(1942,02,10);
# `1942-02-11` wrong
ALTER SESSION SET TIMEZONE = 'GMT';
select JDC(1942,02,10);
# `1942-02-10`, as expected.
Javascript 对于日期、时间和时区很奇怪——正如您所注意到的,月份是基于 0 的,而构造函数中的其余日期不是。另一个问题是 Javascript 没有只有“日期”的构造函数——因为 Date() 代表日期时间。
来自文档:
JavaScript Date objects are converted to the UDF’s result data type, adhering to the same conversion semantics as casts from TIMESTAMP_LTZ(3) to the return data type. https://docs.snowflake.com/en/sql-reference/udf-js.html#dates