Spark和数据库时间戳相差14小时

在PySpark处理ETL过程中遇到Spark与MySQL时间戳相差14小时的问题,原因是Spark默认时区为GMT,而MySQL默认为CST。尽管设置时区可使时间格式相同,但在转换为时间戳时仍存在差异。尝试多种Spark设置未果,可能由于CST在不同环境中有不同解释。目前解决方案是调整MySQL时区,但这在生产环境中可能不可行。另外,发现Spark 2.4版本不支持偏移量时区设置,3.0版本才开始支持,且对'上海'这样的时区设置无效。

最近在用PySpark做ETL,然后发现了Spark存在的时区问题。

Mysql的时区默认是CST格式, 但是Spark默认的是GMT格式,因此直接使用Spark读取Mysql的时间时,会被转为GMT格式,对于这个问题,只需要设置spark.sql.session.timeZoneCST就可以解决了,但由此由引发了一个新的问题。

当两者都是CST的时候,将时间转为yyyy-MM-dd hh:mm:ss来看时,两者是相同的,问题在于分别使用unix_timestamp转为时间戳的时候,两个时间戳之间会相差14 * 3600 秒!并且我尝试了在Spark各种设置都没办法达到两者一致,最终确定出来,当Mysql是CST时,Spark展示出来的数据,要么时间戳跟时间格式都跟Mysql对不上,要么就是时间格式对上了,但是时间戳对不上。。。要解决这个问题,目前已知的唯一办法是将Mysql的时区设置为其它格式,但是,生产中不一定能采用此种方法。

个人猜测是因为CST本身含有4个含义导致的,其中一个是美国标准时间,即UTC-06:00,一个是中国标准时间,即UTC+08:00,两者相差刚好14小时,Mysql解读为中国标准时间,而Spark解读为美国标准时间。

顺便说明一下在捣鼓这个问题时发现的其它点:

  1. Spark在2.4版本,传入时区时,只能传"UTC","GMT"等,不能传(+|-) hh:mm这种偏移量,偏移量我已知的是在3.0版本才能生效。3.0版本虽说可以传入"area/city"这种作为时区,但对于上海并不生效。
  2. PySpark DataFrame的DSL风格的date_format在功能上远比Mysql的要少;

顺带一下area/city的数据:

Etc/GMT+12   
Etc/GMT+11   
MIT   
Pacific/Apia   
Pacific/Midway   
Pacific/Niue   
Pacific/Pago_Pago   
Pacific/Samoa   
US/Samoa   
America/Adak   
America/Atka   
Etc/GMT+10   
HST   
Pacific/Fakaofo   
Pacific/Honolulu   
Pacific/Johnston   
Pacific/Rarotonga   
Pacific/Tahiti   
SystemV/HST10   
US/Aleutian   
US/Hawaii  
Pacific/Marquesas  
AST  
America/Anchorage  
America/Juneau  
America/Nome  
America/Yakutat  
Etc/GMT+9  
Pacific/Gambier  
SystemV/YST9  
SystemV/YST9YDT  
US/Alaska  
America/Dawson  
America/Ensenada  
America/Los_Angeles  
America/Tijuana  
America/Vancouver  
America/Whitehorse  
Canada/Pacific  
Canada/Yukon  
Etc/GMT+8  
Mexico/BajaNorte  
PST  
PST8PDT  
Pacific/Pitcairn  
SystemV/PST8  
SystemV/PST8PDT  
US/Pacific  
US/Pacific-New  
America/Boise  
America/Cambridge_Bay  
America/Chihuahua  
America/Dawson_Creek  
America/Denver  
America/Edmonton  
America/Hermosillo  
America/Inuvik  
America/Mazatlan  
America/Phoenix  
America/Shiprock  
America/Yellowknife  
Canada/Mountain  
Etc/GMT+7  
MST  
MST7MDT  
Mexico/BajaSur  
Navajo  
PNT  
SystemV/MST7  
SystemV/MST7MDT  
US/Arizona  
US/Mountain  
America/Belize  
America/Cancun  
America/Chicago  
America/Costa_Rica  
America/El_
### 时间戳数据类型的使用方法 #### 定义与特性 时间戳timestamp)是一种自动生成的唯一二进制数字的数据类型,通常用于给表行加版本戳的机制。其存储大小为8个字节,仅作为递增的数字使用,不保留具体的日期或时间信息。若需要记录日期或时间,应使用`datetime`数据类型[^1]。 #### 获取当前时间戳数据库中,可以使用`now()`函数来获取当前的时间戳。此函数获取的时间与数据库后台时间一致,相较于前端获取的时间更为准确[^2]。 #### 时间戳与日期时间的别 - **DATE** **DATETIME** 类型:这些类型可以存储具体的日期时间信息,如年、月、日、时、分、秒。它们适用于表示具体的时间点。 - **TIME** 类型:用于存储时间值,而不包含日期部分。 - **YEAR** 类型:用于存储年份信息,相比DATE类型占用更少的空间。 #### 时间戳的应用场景 时间戳主要用于需要追踪数据变更的场景,例如: - 记录数据行的创建时间最后修改时间。 - 在分布式系统中确保数据的一致性同步。 - 作为版本控制的一种手段,防止并发更新冲突。 #### 时间戳的转换 在某些情况下,可能需要将时间戳转换为可读性更好的字符串格式。例如,在Oracle数据库中,可以通过以下SQL语句将时间戳转换为字符串: ```sql -- 时间戳转字符串 select cast(to_timestamp(to_char(sysdate,'yyyy-mm-dd hh24:mi:ss')||'.123456789','yyyy-mm-dd hh24:mi:ss.ff') as varchar2(100)) from dual ``` 这段代码首先使用`to_char`函数将当前系统日期时间转换为字符串格式,然后通过`to_timestamp`函数将其转换为时间戳,并最终转换为VARCHAR2类型的字符串[^4]。 #### 时间戳的零值 时间戳的零值表示为`00000000000000`,并且与时相关。这意味着在不同的时下,时间戳的表示可能会有所不同。 #### 日期类型的局限性 虽然`DATE`类型非常常用,但它在表示两个事件之间的时间间隔时,其度量粒度只能达到秒级别。而`timestamp`类型则可以提供更高的精度,适用于需要更细粒度的时间间隔度量的场景[^3]。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值