如何将hex转换为varchar(date时间)?
我有date时间导出是“CAST(0x0000987C00000000 ASdate时间)”,但是当我想让它回到datetime.It是一个NULL值。 我怎样才能得到它datetime再次。
这看起来像SQL Server datetime
格式。 内部存储为2个整数,前4个字节为自1900年1月1日以来的天数,第二个是自午夜以来(每个时间间隔为1/300秒)的刻度数。
如果你需要在MySQL中使用这个,你可以这样做
SELECT CAST( '1900-01-01 00:00:00' + INTERVAL CAST(CONV(substr(HEX(BinaryData),1,8), 16, 10) AS SIGNED) DAY + INTERVAL CAST(CONV(substr(HEX(BinaryData),9,8), 16, 10) AS SIGNED)* 10000/3 MICROSECOND AS DATETIME) AS converted_datetime FROM ( SELECT 0x0000987C00000000 AS BinaryData UNION ALL SELECT 0x00009E85013711EE AS BinaryData ) d
返回
converted_datetime -------------------------- 2006-11-17 00:00:00 2011-02-09 18:52:34.286667
(感谢Ted Hopp分解二进制数据的解决scheme )
不是真的添加任何没有说明的东西,但我用这个从上面的代码创build一个MySql函数。 然后,我可以使用RegEx查找并replace(在Notepad ++中)以用sp_ConvertSQLServerDate(0xblahblahblah)replaceCAST(0xblahblahblah AS DATETIME)。
create function sp_ConvertSQLServerDate(dttm binary(16)) returns datetime return CAST( '1900-01-01 00:00:00' + INTERVAL CAST(CONV(substr(HEX(dttm),1,8), 16, 10) AS SIGNED) DAY + INTERVAL CAST(CONV(substr(HEX(dttm),9,8), 16, 10) AS SIGNED)* 10000/3 MICROSECOND AS DATETIME);
这与PostgreSQL的 select语句相同:
SELECT '1900-01-01 00:00:00'::date + (('x'||substring(x::text,3,8))::bit(32)::int::text||'days')::interval + ((('x'||substring(x::text,11,8))::bit(32)::int /300)::text||' seconds')::interval FROM (VALUES ('0x00009fff00e24076'), ('0x00009ff10072d366'), ('0x00009ff10072ce3a'), ('0x00009ff10072c5e2'), ('0x00009ff10072bc3c')) as x(x);
PostgreSQL位(32)值必须以“x”值而不是0开始。
这是我做的一个Java程序。
该程序扫描给定的文件(更改下面的代码名称)
CAST(0x... AS DateTime)
并用它们各自的替代它们
CAST('yyyy-MM-dd HH:mm:ss.SSS' AS DateTime)
。
例如,考虑到SELECT CAST (0x00009CEF00A25634 as datetime)
返回2009-12-30 09:51:03.000
,程序扫描CAST(0x00009CEF00A25634 AS DateTime)
文件CAST(0x00009CEF00A25634 AS DateTime)
,并用CAST('2009-12-30 09:51:03.000' AS DateTime)
。
我用它将SQL Server生成的脚本转换成H2embedded式数据库可以理解的内容。
尽pipe它对我来说工作得很好,但我build议你在使用实际数据之前检查它(只是运行一些testing数据并查看)。
import java.io.*; import java.text.*; import java.util.*; import java.util.regex.*; public class ReplaceHexDate { public static void main(String[] args) throws Exception { String inputFile = "C:/input.sql"; String inputEncoding = "UTF-8"; String outputFile = "C:/input-replaced.sql"; String outputEncoding = "UTF-8"; BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(inputFile), inputEncoding)); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFile), outputEncoding)); String line; while ((line = br.readLine()) != null) { if (line.indexOf("CAST(0x") > -1) { bw.write(replaceHexWithDate(line)); } else { bw.write(line); } bw.newLine(); } br.close(); bw.flush(); bw.close(); } private static String replaceHexWithDate(String sqlLine) throws ParseException { Pattern castPattern = Pattern.compile("(CAST\\()(0x[A-Fa-f0-9]{16})( AS DateTime\\))"); Matcher m = castPattern.matcher(sqlLine); while (m.find()) { String s = m.group(2); sqlLine = sqlLine.replace(s, "'"+sqlServerHexToSqlDate(s)+"'"); } return sqlLine; } public static String sqlServerHexToSqlDate(String hexString) throws ParseException { String hexNumber = hexString.substring(2); // removes the leading 0x String dateHex = hexNumber.substring(0, 8); String timeHex = hexNumber.substring(8, 16); long daysToAdd = Long.parseLong(dateHex, 16); long millisToAdd = (long) (Long.parseLong(timeHex, 16) *10/3); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); Calendar startingCal = Calendar.getInstance(); String startingDate = "1900-01-01 00:00:00.000"; startingCal.setTime(sdf.parse(startingDate)); Calendar convertedCal = Calendar.getInstance(); convertedCal.setTime(sdf.parse(startingDate)); convertedCal.add(Calendar.DATE, (int) daysToAdd); convertedCal.setTimeInMillis(convertedCal.getTimeInMillis() + millisToAdd); return sdf.format(convertedCal.getTime()); } }
使用记事本+ +正则expression式replace
cast[(]0x([0-9A-F]{16}) As DateTime[)] CAST('1900-01-01 00:00:00' + INTERVAL CAST(CONV(substr(HEX( 0x\1 ),1,8), 16, 10) AS SIGNED) DAY + INTERVAL CAST(CONV(substr(HEX( 0x\1 ),9,8), 16, 10) AS SIGNED)* 10000/3 MICROSECOND AS DATETIME)
这将取代
CAST(0x0000A26900F939A8 AS DateTime)
至
CAST('1900-01-01 00:00:00' + INTERVAL CAST(CONV(substr(HEX( 0x0000A26900F939A8 ),1,8), 16, 10) AS SIGNED) DAY + INTERVAL CAST(CONV(substr(HEX( 0x0000A26900F939A8 ),9,8), 16, 10) AS SIGNED)* 10000/3 MICROSECOND AS DATETIME),
date和date时间的MSSQLhex代码是不同的。
对于像0x00000000这样的date,你可以使用这个postgres函数:
CREATE FUNCTION convertedata(text) RETURNS timestamp without time zone as $$ SELECT '0001-01-01 00:00:00'::date + (('x'|| (regexp_replace( substring($1::text,3,8)::text, '(\w\w)(\w\w)(\w\w)(\w\w)', '\4\3\2\1'))::text )::bit(32)::int::text||'days')::interval $$ LANGUAGE SQL;
然后尝试
select convertedata('0x0E360B00')
对于那些在C#中寻找解决scheme的人。 例如在读取脚本化的数据库数据时。
string pattern = @"CAST\(0x(\w{8})(\w{8}) AS DateTime\)"; Regex r = new Regex(pattern); Match m = r.Match(hex); int d = System.Convert.ToInt32("0x" + m.Groups[1].Value, 16); int t = System.Convert.ToInt32("0x" + m.Groups[2].Value, 16); DateTime converted = new DateTime(1900, 1, 1).AddDays(d).AddSeconds(t/300);
在这里,我使用正则expression式,因为我的input是在下面的forms“CAST(0x0000A53E00E1A17B AS DateTime)”,但你可以使用SubString()或其他任何获得DateTimestring。