我的日期时间导出是“CAST(0x0000987C00000000 AS DateTime)”但是当我想将它恢复到datetime.It是一个NULL值。我怎样才能再次进入日期时间。
答案 0 :(得分:11)
看起来像SQL Server datetime
格式。在内部,它存储为2个整数,前4个字节是自1900年1月1日以来的天数,第2个字节是自午夜以来的刻度数(每个刻度为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在分割二进制数据时the solution)
答案 1 :(得分:8)
并没有真正添加任何未说明的内容,但我使用它来从上面的代码创建一个MySql函数。然后我可以使用RegEx查找和替换(在Notepad ++中)用sp_ConvertSQLServerDate(0xblahblahblah)替换CAST(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);
答案 2 :(得分:2)
这与 PostgreSQL :
的选择语句相同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开始。
答案 3 :(得分:1)
这是我做过的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('2009-12-30 09:51:03.000' AS DateTime)
。
我用它将SQL Server生成的脚本转换为H2嵌入式数据库可以理解的东西。
尽管它对我来说很好,我建议你在使用实际数据之前检查它(只是运行一些测试数据并查看)。
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());
}
}
答案 4 :(得分:1)
使用notepad ++ regex替换
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),
答案 5 :(得分:0)
日期和日期时间的MSSQL十六进制代码不同。
对于像0x00000000这样的日期,你可以使用这个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')
答案 6 :(得分:0)
对于那些在C#中寻找解决方案的人。例如,在读取脚本化数据库数据时。
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);
这里我使用了正则表达式,因为我的输入采用以下格式" CAST(0x0000A53E00E1A17B AS DateTime)",但您可以使用SubString()或其他任何方法来获取DateTime字符串。