云服务器价格_云数据库_云主机【优惠】最新活动-搜集站云资讯

MySQL数据库_qq邮箱服务器_怎么样

小七 141 0

全面了解apachespark中的日期和时间戳™ 3

apachespark是一个非常流行的处理结构化和非结构化数据的工具。在处理结构化数据时,它支持许多基本数据类型,如integer、long、double、string等。Spark还支持更复杂的数据类型,如日期和时间戳,这些数据类型往往令开发人员难以理解。在这篇博文中,我们将深入研究日期和时间戳类型,以帮助您全面了解它们的行为以及如何避免一些常见问题。综上所述,本博客包括四个部分:日期类型和关联日历的定义。它还涵盖了Spark 3.0中的日历开关。时间戳类型的定义及其与时区的关系。它还解释了时区偏移解析的细节,以及Spark 3.0使用的Java8中新的TimeAPI中细微的行为变化。在Spark中构造日期和时间戳值的常用API。在Spark驱动程序上收集日期和时间戳对象的常见陷阱和最佳实践。日期和日历日期的定义非常简单:它是年、月和日字段的组合,例如(year=2012,month=12,day=31)。但是,年、月和日字段的值有限制,因此日期值在现实世界中是有效的一天。例如,month的值必须在1到12之间,day的值必须在1到28/29/30/31之间(取决于年份和月份),依此类推。这些约束由许多可能的日历之一定义。有些只在特定地区使用,比如农历。其中有些只在历史上使用,比如儒略历。在这一点上,公历是事实上的国际标准,几乎在世界各地都被用于民事目的。它于1582年引入,并扩展到1582年之前的日期。这种扩展的日历被称为前公历。从3.0版开始,Spark使用的是Proleptic Gregorian calendar,它已经被pandas、R和ApacheArrow等其他数据系统使用。在Spark 3.0之前,它使用儒略历和公历的组合:1582年以前的日期使用儒略历,1582年以后的日期使用公历。这是从遗产继承下来的java.sql.Date在Java8中被java.time.LocalDate,也使用了公历。值得注意的是,日期类型不考虑时区。时间戳和时区Timestamp类型使用新字段扩展了Date类型:hour、minute、second(可以有小数部分)以及一个全局(会话范围)时区。它定义了地球上一个具体的时间瞬间。例如,(年=2012,月=12,日=31,时=23,分=59,秒=59.123456),会话时区为UTC+01:00。当将时间戳值写入Parquet等非文本数据源时,这些值只是没有时区信息的瞬间(如UTC中的时间戳)。如果使用不同的会话时区写入和读取时间戳值,则可能会看到小时/分钟/秒字段的不同值,但它们实际上是相同的具体时间瞬间。小时、分钟和秒字段的标准范围是:0–23表示小时,0–59表示分钟和秒。Spark支持分数秒,精度高达微秒。分数的有效范围是0到999999微秒。在任何一个具体的时刻,我们都可以观察到挂钟的许多不同值,这取决于时区。相反地,墙上的时钟可以代表许多不同的时间瞬间。时区偏移允许我们明确地将本地时间戳绑定到时间瞬间。通常,时区偏移被定义为从格林威治标准时间(GMT)或UTC+0(协调世界时)以小时为单位的偏移量。这种时区信息的表示消除了歧义,但对最终用户来说不方便。用户喜欢指出全球各地的位置,如美国/洛杉矶或欧洲/巴黎。这种从区域偏移的额外抽象级别使生活更轻松,但也带来了自身的问题。例如,我们现在必须维护一个特殊的时区数据库来将时区名称映射到偏移量。由于Spark运行在JVM上,它将映射委托给Java标准库,Java标准库从Internet分配的号码权威时区数据库(ianatzdb)加载数据。此外,Java标准库中的映射机制有一些细微差别,影响Spark的行为。下面我们重点讨论这些细微差别。自从java8以来,JDK已经公开了一个用于日期-时间操作和时区偏移解析的新API,Spark在3.0版中迁移到了这个新API。尽管时区名称到偏移量的映射具有相同的源IANA TZDB,但它在Java8和更高版本中的实现方式与Java7不同。例如,让我们看一下1883年之前美国/洛杉矶时区的时间戳:1883-11-10 00:00:00。今年之所以与众不同,是因为1883年11月18日,北美所有的铁路公司都改用了一种新的标准时间系统,从此以后这些铁路公司的时刻表都由它来管理。使用Java 7 time API,我们可以获得本地时间戳的时区偏移量为-08:00:斯卡拉>java.time.ZoneId.System默认值回复0:java.time.ZoneId=美国/洛杉矶斯卡拉>java.sql.Timestamp.valueOf("1883-11-10 00:00:00").getTimezoneOffset/60.0res1:双精度=8.0Java 8 API函数返回不同的结果:斯卡拉>java.time.ZoneId.of("美国/洛杉矶").getRules.getOffset(java.time.LocalDateTime.parse("1883-11-10T00:00:00"))答案2:java.time.ZoneOffset=-07时52分58秒在1883年11月18日之前,一天中的时间是当地的事情,大多数城市和城镇都使用某种形式的当地太阳时,由一个著名的时钟来维持(例如教堂尖塔上,或珠宝商的橱窗里)。这就是为什么我们看到如此奇怪的时区偏移。该示例演示了Java8函数更精确,并考虑了来自IANA TZDB的历史数据。在切换到Java8TimeAPI之后,Spark 3.0自动受益于改进,并在如何解决时区偏移方面变得更加精确。如前所述,spark3.0还将日期类型转换为prepreptic Gregorian calendar。时间戳类型也是如此。国际标准化组织SQL:2016标准声明时间戳的有效范围是从0001-01-01 00:00:00到9999-12-31 23:59:59.999999。Spark 3.0完全符合标准,并支持此范围内的所有时间戳。与Spark 2.4及更早版本相比,我们应该强调以下子范围:0001-01-01 00:00:00..1582-10-03 23:59:59.999999。Spark 2.4使用儒略历,不符合标准。Spark 3.0解决了这个问题,并在内部操作中应用了Proleptic Gregorian calendar,例如获取年、月、日等时间戳。由于日历不同,Spark 2.4中存在的一些日期在Spark 3.0中不存在。例如,1000-02-29不是有效日期,因为1000不是公历中的闰年。另外,spark2.4错误地将时区名称解析为该时间戳范围的区域偏移量。1582-10-04 00:00:00..1582-10-14 23:59:59.999999。这是Spark 3.0中本地时间戳的有效范围,而Spark 2.4中没有这样的时间戳。1582-10-15 00:00:00..1899-12-31 23:59:59.999999。Spark 3.0使用来自IANA TZDB的历史数据正确解析时区偏移。与spark3.0相比,spark2.4在某些情况下可能会错误地解析来自时区名称的区域偏移量,正如我们上面的示例所示。1900-01-01 00:00:00..2036-12-31 23:59:59.999999。spark3.0和spark2.4都符合ansisql标准,并在日期时间操作中使用公历,例如获取月的哪一天。2037-01-01 00:00:00..9999-12-31 23:59:59.999999。Spark 2.4可以错误地解决时区偏移,特别是夏令时偏移,因为JDK bug#8073446。Spark 3.0不存在此缺陷。将时区名称映射到偏移量的另一个方面是由于夏时制(DST)或切换到另一个标准时区偏移量而可能发生的本地时间戳重叠。例如,2019年11月3日,02:00:00时钟向后拨1小时至01:00:00。本地时间戳2019-11-03 01:30:00美国/洛杉矶可以映射到2019-11-03 01:30:00 UTC-08:00或2019-11-03 01:30:00 UTC-07:00。如果不指定偏移量,而只设置时区名称(例如'2019-11-03 01:30:00 America/Los峎Angeles'),则Spark 3.0将采用较早的偏移量,通常对应于"夏季"。该行为与Spark 2.4不同,后者采用"冬季"偏移量。在时间间隔的情况下,时钟向前跳,没有有效的偏移。对于一个典型的一小时夏令时更改,Spark会将这些时间戳移动到下一个与"夏季"时间对应的有效时间戳。从上面的例子中我们可以看到,时区名称到偏移量的映射是不明确的,并且不是一对一。在可能的情况下,我们建议在制作时间戳时指定准确的时区偏移量,例如时间戳"2019-11-03 01:30:00 UTC-07:00"。让我们从区域名到偏移映射转移到偏移量映射,看看ANSI-SQL标准。它定义了两种类型的时间戳:不带时区或时间戳的时间戳–本地时间戳为(年、月、日、小时、分钟、秒)。这些时间戳不绑定到任何时区,实际上是挂钟时间戳。带时区的时间戳–分区时间戳为(年、月、日、小时、分钟、秒、时区_小时、时区分钟)。时间戳表示UTC时区中的一个瞬间+与每个值关联的时区偏移量(以小时和分钟为单位)。带有时区的时间戳的时区偏移量不影响时间戳所表示的物理时间点,因为它由其他时间戳组件给出的UTC时间即时完全表示。相反,时区偏移量只影响显示、日期/时间组件提取(例如提取)和其他操作的时间戳值的默认行为