как привести шестнадцатеричное значение к varchar (datetime)? - PullRequest
8 голосов
/ 09 февраля 2011

У меня есть дата и время экспорта "CAST (0x0000987C00000000 AS DateTime)", но когда я хочу вернуть его в datetime. Это значение NULLкак я могу получить его снова до даты.

Ответы [ 7 ]

11 голосов
/ 09 февраля 2011

Это похоже на формат SQL Server datetime.Внутренне это сохраняется как 2 целых числа, причем первые 4 байта являются днями с 1 января 1900 года, а 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

(Спасибо Теду Хоппу за решение в разбивании двоичных данных)

8 голосов
/ 15 сентября 2011

На самом деле не добавлялось ничего, что не было заявлено, но я использовал это для создания функции MySql из приведенного выше кода. Затем я могу использовать поиск и замену RegEx (в Notepad ++) для замены CAST (0xblahblahblah AS DATETIME) на sp_ConvertSQLServerDate (0xblahblahblah).

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 голосов
/ 25 октября 2013

Это тот же оператор выбора для 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.

1 голос
/ 17 июля 2014

Использование notepad ++ regex 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), 
1 голос
/ 03 февраля 2013

Вот программа на 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());
    }
}
0 голосов
/ 11 мая 2017

Для тех, кто ищет решение в 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.

0 голосов
/ 15 октября 2016

MSSQL шестнадцатеричный код для date и dateTime различаются.

Для даты в fomate, например 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')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...