我遇到了一个问题,在Snowflake中用JavaScript语言实现的用户定义函数(UDF(返回无效日期,它会增加一天。
为了证明这个问题,这里有一个简单的UDF,它包含三个参数year、month、day,并返回Date对象。
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)
$$
;
调用此过程将返回除1942年至1949年之间的几天之外的所有年份的正确值,
select JDC(1942,02,10);
返回1942-02-11,这是不正确的select JDC(1948,12,31);
返回1949-01-01错误select JDC(2020,02,10);
返回2020-02-10,正确值
如果您注意到1,2,则在javascript日期转换为雪花期间会增加一天。我确认JavaScript能够通过将UDF返回类型更改为VARCHAR并将日期对象返回为类似return new Date(YEAR,MONTH-1,DAY).toString()
的字符串来返回正确的值,因此在转换过程中会发生一些事情。
默认情况下,JavaScript使用UTC时区,而我当前的雪花实例设置为在PST时区运行,所以认为时区方面的转换应该回到前一天,但令人惊讶的是,它却走了另一条路。
作为一种变通方法,您可以使用本机功能:
DATE_FROM_RTS
DATE_FROM_PARTS( <year>, <month>, <day> )
从表示年、月和月中日的各个数字组件中创建日期。
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没有一个";日期";只有构造函数-as-Date((表示日期时间。
来自文档:
JavaScriptDate对象被转换为UDF的结果数据类型,遵循与从TIMESTAMP_LTZ(3(转换为返回数据类型相同的转换语义。https://docs.snowflake.com/en/sql-reference/udf-js.html#dates