WEB开发网      婵犵數濮烽弫鍛婄箾閳ь剚绻涙担鍐叉搐绾剧懓鈹戦悩瀹犲闁汇倗鍋撻妵鍕箛閸洘顎嶉梺绋款儑閸犳劙濡甸崟顖氬唨闁靛ě浣插亾閹烘鈷掗柛鏇ㄥ亜椤忣參鏌″畝瀣暠閾伙絽銆掑鐓庣仭缁楁垿姊绘担绛嬪殭婵﹫绠撻、姘愁樄婵犫偓娴g硶鏀介柣妯款嚋瀹搞儱螖閻樺弶鍟炵紒鍌氱Ч瀹曟粏顦寸痪鎯с偢瀵爼宕煎☉妯侯瀳缂備焦顨嗗畝鎼佸蓟閻旈鏆嬮柣妤€鐗嗗▓妤呮⒑鐠団€虫灀闁哄懐濮撮悾鐤亹閹烘繃鏅濋梺闈涚墕濡瑩顢欒箛鏃傜瘈闁汇垽娼ф禒锕傛煕閵娿儳鍩f鐐村姍楠炴﹢顢欓懖鈺嬬幢闂備浇顫夊畷妯肩矓椤旇¥浜归柟鐑樻尭娴滃綊姊虹紒妯虹仸闁挎洍鏅涜灋闁告洦鍨遍埛鎴︽煙閼测晛浠滃┑鈥炽偢閹鈽夐幒鎾寸彇缂備緡鍠栭鍛搭敇閸忕厧绶炴俊顖滅帛濞呭洭姊绘担鐟邦嚋缂佽鍊垮缁樼節閸ャ劍娅囬梺绋挎湰缁嬫捇宕㈤悽鍛婄厽閹兼番鍨婚埊鏇㈡煥濮樿埖鐓熼煫鍥ュ劤缁嬭崵绱掔紒妯肩畺缂佺粯绻堝畷姗€濡歌缁辨繈姊绘担绛嬪殐闁搞劋鍗冲畷顖炲级閹寸姵娈鹃梺缁樻⒒閳峰牓寮崒鐐寸厱闁抽敮鍋撻柡鍛懅濡叉劕螣鐞涒剝鏂€闂佺粯鍔曞Ο濠囧吹閻斿皝鏀芥い鏃囨閸斻倝鎽堕悙鐑樼厱闁哄洢鍔屾晶顖炴煕濞嗗繒绠婚柡灞界Ч瀹曨偊宕熼鈧▍锝囩磽娴f彃浜炬繝銏f硾椤戝洨绮绘ィ鍐╃厵閻庢稒岣跨粻姗€鏌ㄥ☉妯夹fい銊e劦閹瑩顢旈崟顓濈礄闂備浇顕栭崰鏍礊婵犲倻鏆﹂柟顖炲亰濡茶鈹戦埄鍐ㄧ祷妞ゎ厾鍏樺璇测槈閵忕姈鈺呮煏婢跺牆鍔撮柛鏂款槺缁辨挻鎷呯粙搴撳亾閸濄儳鐭撶憸鐗堝笒閺嬩線鏌熼崜褏甯涢柡鍛倐閺屻劑鎮ら崒娑橆伓 ---闂傚倸鍊搁崐鐑芥倿閿旈敮鍋撶粭娑樺幘濞差亜鐓涢柛娑卞幘椤斿棝姊虹捄銊ユ珢闁瑰嚖鎷�
开发学院数据库DB2 在DB2 Universal Database中转换UTC时间戳 阅读

在DB2 Universal Database中转换UTC时间戳

 2006-09-04 22:09:13 来源:WEB开发网 闂傚倸鍊搁崐椋庢濮橆兗缂氱憸宥堢亱闂佸湱铏庨崰鏍不椤栫偞鐓ラ柣鏇炲€圭€氾拷闂傚倸鍊搁崐椋庣矆娓氣偓楠炲鏁撻悩鎻掔€梺姹囧灩閻忔艾鐣烽弻銉︾厵闁规鍠栭。濂告煕鎼达紕校闁靛洤瀚伴獮鎺楀箣濠靛啫浜鹃柣銏⑶圭壕濠氭煙閻愵剚鐏辨俊鎻掔墛缁绘盯宕卞Δ鍐冣剝绻涘畝濠佺敖缂佽鲸鎹囧畷鎺戭潩閹典焦鐎搁梻浣烘嚀閸ゆ牠骞忛敓锟�婵犵數濮烽弫鍛婃叏椤撱垹绠柛鎰靛枛瀹告繃銇勯幘瀵哥畼闁硅娲熷缁樼瑹閳ь剙岣胯鐓ら柕鍫濇偪濞差亜惟闁宠桨鑳堕崝锕€顪冮妶鍡楃瑐闁煎啿鐖奸崺濠囧即閵忥紕鍘梺鎼炲劗閺呮稒绂掕缁辨帗娼忛埡浣锋闂佽桨鐒﹂幑鍥极閹剧粯鏅搁柨鐕傛嫹闂傚倸鍊搁崐椋庢濮橆兗缂氱憸宥堢亱闂佸湱铏庨崰鏍不椤栫偞鐓ラ柣鏇炲€圭€氾拷  闂傚倸鍊搁崐鐑芥嚄閼哥數浠氱紓鍌欒兌缁垶銆冮崨鏉戠厺鐎广儱顦崡鎶芥煏韫囨洖校闁诲寒鍓熷铏圭磼濡搫顫岄梺璇茬箲濮樸劑鍩€椤掍礁鍤柛鎾跺枎椤繐煤椤忓嫬鐎銈嗘礀閹冲酣宕滄导瀛樷拺闂侇偆鍋涢懟顖涙櫠椤斿墽纾煎璺猴功缁夎櫣鈧鍠栭…閿嬩繆濮濆矈妲烽梺绋款儐閹瑰洤螞閸愩劉妲堟繛鍡楃箲濞堟﹢姊绘担椋庝覆缂傚秮鍋撴繛瀛樼矤閸撶喖宕洪埀顒併亜閹烘垵鈧綊寮抽鍕厱閻庯綆浜烽煬顒傗偓瑙勬磻閸楀啿顕i崐鐕佹Ь闂佸搫妫寸粻鎾诲蓟閵娾晜鍋嗛柛灞剧☉椤忥拷
核心提示:简介本文展示了一个 DB2 用户定义函数(UDF)的 Java 实现的设计,该函数有两个输入参数:一个 UTC 时间戳(例如 2004-04-04-04.00.00.000000)和一个地区名(例如 "America/Guayaquil"),在DB2 Universal Database中转换UTC

简介

本文展示了一个 DB2 用户定义函数(UDF)的 Java 实现的设计,该函数有两个输入参数:一个 UTC 时间戳(例如 2004-04-04-04.00.00.000000)和一个地区名(例如 "America/Guayaquil"),并返回新地区中对应的时间戳(在这里是 2004-04-03-23.00.00.000000)。

执行这种转换时遇到的两个主要挑战是:

  • 要支持某个地区可能出现的所有不同名称,以及可能作为输入参数传入的所有不同地区。
  • 对于每个地区,要计算出夏令时(daylight savings time)规则。

对于包含来自很多不同应用程序和分布在几个洲的地区的数据的数据仓库项目,经验证明,在转换方面,该函数对于 Extract Transform Load (ETL) 在分析和处理数据时需要用到的过程极其有用。

背景

时间连续区间(time continuum)内的某个惟一时刻可以由那一刻的 日期时间来定义,为了更精确起见,还可以加上 秒后面的小数。这种定义叫做 时间戳,它在 DB2 中的 ISO 表示如下:

2004-07-24-16.18.28.410002

在这种情况下,精确度可以下调为 1 微秒。

在一个与某个事务有关的事件发生时记录下时间戳,这一活动就叫做为该事务“记录时间戳(timestamping)”。在一个事务的整个生命周期内,需要多次记录时间戳,以便记下创建、最后一次修改、最后一次访问某一事务的时间。

对于发生在多个地理位置和多个地区的集中存储事务,常见的设计是用与该地区时间对应的世界协调时间(Universal Time Coordinated,UTC)记下每个时间戳记录。通过同时记录下事务发生时所在的位置,例如存储事务发生时所在的客户号或业务部门号,可以重新构造该事务的本地时间。

当必须处理、分析和报告来自大量不同来源的数据时,我们需要重新构造 UTC 时间戳在事务原始位置的本地时间。常被问到的问题有:

  • 我知道 UTC 时间,但是客户的本地时间是什么呢?
  • 是上午还是下午?
  • 是在我们的地理区域的工作时间之内,还是在该工作时间之外?
  • 其他问题。

挑战

表面上看起来既简单又容易完成的任务,事实上被证明是既不简单也不容易完成。

从本地时间到 UTC 时间的实时转换通常是在应用程序中完成的。它只能用于当前时间(而不能用于过去或将来的任何时间点),并且只能用于应用程序运行时其服务器所在的地区(而不是任何其他地区)。

我们遇到的一个挑战是理解我们所接收到的地区名:

  • 对于同一个地区,我们数据仓库的每个数据源都为我们提供了不同的名称,例如 Eastern Daylight、Eastern Standard Time、America/New_York、EST 等 —— 其实意思都是一样。
  • 每个数据源都处理一组不同的地区。例如,某个数据源只有 North American 地区,而其他数据源在欧洲也有办事处,因而就需要一个更大的地区列表。

另一个挑战是实现我们处理的所有地区的夏令时(Daylight Savings Time,DST)规则 —— 这些规则我们还不能轻松地使用。

还有一个需求就是能够很容易地使用用来调用转换函数的 API。

例如,为了得到一个 UTC 时间戳在 "America/Nassau" 的本地时间,一家虚构的 Acme Intl. 公司使用的 SELECT 语句就必须像下面这样简单:

SELECT ACME.F_CONVERT_TIMEZONE(TRANSACTION_TIMESTAMP, "America/Nassau")FROM ACME.TRANSACTION_TABLE;

解决方案

有些数据源是由 Java 应用程序填充的,因此每个应用程序用于这些数据源的名称可以是不同 Java JDK 版本(1.1.8、1.4 等)的名称。由于 Java JDK 已经为一组相当全面的地区的所有 DST 规则编写了代码,因此我们选择用 Java 编写转换函数,并在 DB2 的 Java JDK 上运行该函数。

为了便于使用,我们将 Java 类包装在了另一个 DB2 UDF 中。

解决方案细节

Java 类有一个用来存储查找字典的类变量,其中包含了可能作为输入的每个地区所有可能的拼写和命名。

tz_map = new Hashtable();… tz_map.put("Eastern Daylight", "EST");tz_map.put("Eastern Standard Time", "EST");tz_map.put("America/New_York", "EST");… 

例如,上面所有的键都对应于值 “EST"。这就是类方法为了进行时间戳转换而在内部使用的值。

注意:这里鼓励为时区使用长名,例如 "America/New_York"。但是在这个特定的实现中,我们使用了短名称,因为 UDB DB2 version 7.2 使用的是 JDK 1.1.8,该版本只能使用短名称。

查找表的填充是手动完成的。我们花了很大的精力查找每个地区的内部 Java 设置,并将具有相同 DST 规则和时区的长名与短名进行组对。

我们这样映射了 250 多个地区。如果需要的话,还可以添加新的映射。这样,在将新数据源与新的地区一起添加到数据仓库时,我们便有了所需的灵活性。

对于实际的时间戳转换,我们使用了下面的类方法:

public static java.lang.String J_CONVERT_TIMEZONE(java.lang.String ivc_UTCtimestamp, java.lang.String ivc_timezone)

首先将输入的时间戳字符串解析成它的各个组成部分,并从那些值例化出一个 Java 日历,然后通过格式转换器(formatter)产生一个新的转换后的时间戳。细微部分没有进行转换,直接变成输出,因为 Java Calendar 没有精确到那个程度。

可以用下面的语句将该 Java 类方法注册成一个 UDF 函数:

  public static java.lang.String J_CONVERT_TIMEZONE(java.lang.String ivc_UTCtimestamp,  java.lang.String ivc_timezone) throws Exception    {        // get the short name equivalent of the input        ivc_timezone = (String)tz_map.get(ivc_timezone);        if (ivc_timezone == null)            ivc_timezone = "GMT"; // default to UTC if entry not found        // replace the . with - so that we only have one token separator instead of two        String ivc_UTCtimestamp_new = ivc_UTCtimestamp.replace('.', '-' );        // parse, validate and convert the TS string to integers, based on the one separator        StringTokenizer st = new StringTokenizer(ivc_UTCtimestamp_new, "-");        int year = Integer.parseInt(st.nextToken());        int month = Integer.parseInt(st.nextToken());        int day = Integer.parseInt(st.nextToken());        int hour = Integer.parseInt(st.nextToken());        int min = Integer.parseInt(st.nextToken());        int sec = Integer.parseInt(st.nextToken());        String micro = st.nextToken(); // just carried over from the input        // create with the above a calendar in UTC        Calendar calUTC = Calendar.getInstance();        calUTC.clear();        calUTC.setTimeZone(TimeZone.getTimeZone("GMT"));        calUTC.set(year, month-1, day, hour, min, sec );        // prepare the formatter for the specified timezone        DateFormat formatter = new SimpleDateFormat("yyyy'-'MM'-'dd'-'HH.mm.ss", Locale.US);        TimeZone tz = TimeZone.getTimeZone(ivc_timezone);
		  

Tags:DB Universal Database

编辑录入:coldstar [复制链接] [打 印]
赞助商链接