Преобразование JDE юлианской даты в григорианский - PullRequest
2 голосов
/ 12 марта 2012

Я пытаюсь преобразовать даты JDE , собрал большое количество информации и решил, что попробую сделать функцию преобразования SQL, чтобы упростить некоторые задачи.

Вотфункция, которую я придумал, которую я просто называю "ToGregorian"

CREATE FUNCTION [dbo].[ToGregorian](@julian varchar(6))
RETURNS datetime AS BEGIN
    DECLARE @datetime datetime

    SET @datetime = CAST(19+CAST(SUBSTRING(@julian, 1, 1) as int) as varchar(4))+SUBSTRING(@julian, 2,2)+'-01-01'
    SET @datetime = DATEADD(day, CAST(SUBSTRING(@julian, 4,3) as int)-1, @datetime)

    RETURN @datetime
END
  1. Принимает "юлианскую" строку.
  2. Берет первую букву и добавляет ее к веку, начиная с 19-го.
  3. Добавляет десятилетие и годы из следующих 2 символов.
  4. Наконец, добавляются дни, которые являются последними 3 символами, и вычитается 1, поскольку у него уже был 1 день в первой настройке.(например, 2011-01-01)
  5. Результат, например: 111186 => 2011-07-05 00:00:00.000

На мой взгляд, это немного неуклюже и излишне, и янадеясь, что есть лучший способ сделать это.Возможно, я делаю слишком много преобразований или, может быть, мне следует использовать совсем другой метод?

Какой-нибудь совет, как улучшить функцию?
Возможно, другой, лучший метод?
Не противесли бы он мог быть более читабельным ...

У меня также есть встроенная версия, где, например, если у меня есть только права на чтение, и я не могу использовать функции, что также выглядит грязно, не так ли?можно сделать его более читабельным или лучше?

CAST(REPLACE(Convert(VARCHAR, DATEADD(d,CAST(SUBSTRING(CAST([column] AS VARCHAR), 4,3) AS INT)-1, CAST(CAST(19+CAST(SUBSTRING(CAST([column] AS VARCHAR), 1,1) AS INT) AS VARCHAR)+SUBSTRING(CAST([column] AS VARCHAR), 2,2) + '-01-01' AS DATETIME)), 111), '/', '-') AS DATETIME)

Ответы [ 5 ]

4 голосов
/ 12 марта 2012

Я думаю, что более эффективно использовать встроенную математику даты и времени, чем все это переключение назад и вперед к различным форматам строк, дат и чисел.

DECLARE @julian VARCHAR(6) = '111186';

SELECT DATEADD(YEAR, 
  100*CONVERT(INT, LEFT(@julian,1))
  +10*CONVERT(INT, SUBSTRING(@julian, 2,1))
  +CONVERT(INT, SUBSTRING(@julian,3,1)), 
 DATEADD(DAY, CONVERT(INT,SUBSTRING(@julian, 4, 3))-1, 
 0));

Результат:

===================
2011-07-05 00:00:00

Предполагая, что эти данные меняются не часто, может быть гораздо эффективнее фактически хранить дату в виде вычисляемого столбца (именно поэтому я выбрал базовую дату 0 вместо некоторого строкового представления, что может вызвать проблемы детерминизма, предотвращающиестолбец не был сохранен и потенциально проиндексирован).

CREATE TABLE dbo.JDEDates
(
    JDEDate VARCHAR(6),

    GregorianDate AS CONVERT(SMALLDATETIME, 
      DATEADD(YEAR, 
        100*CONVERT(INT, LEFT(RIGHT('0'+JDEDate,6),1))
        +10*CONVERT(INT, SUBSTRING(RIGHT('0'+JDEDate,6), 2,1))
        +CONVERT(INT, SUBSTRING(RIGHT('0'+JDEDate,6),3,1)), 
      DATEADD(DAY, CONVERT(INT, RIGHT(JDEDate, 3))-1, 
      0))
    ) PERSISTED
);

INSERT dbo.JDEDates(JDEDate) SELECT '111186';

SELECT JDEDate, GregorianDate FROM dbo.JDEDates;

Результаты:

JDEDate GregorianDate
======= ===================
111186  2011-07-05 00:00:00

Даже если вы не индексируете столбец, он все равно скрывает от вас уродливые вычисления, будучиПостоянно вы платите только во время записи, так как это не заставляет вас выполнять дорогостоящие функциональные операции во время запроса, когда на этот столбец ссылаются ...

3 голосов
/ 05 февраля 2016

Принят неправильный ответ.Он не даст правильного ответа для 116060, который должен быть 29 февраля 2016 года. Вместо этого он возвращает 1 марта 2016 года.

Кажется, JDE хранит даты как целые числа, поэтому вместо преобразования из строк я всегда иду прямо изцелое число:

DATEADD(DAY, @Julian % 1000, DATEADD(YEAR, @Julian / 1000, '31-dec-1899'))

Для перехода из архива (6) я использую:

DATEADD(DAY, CAST(RIGHT(@Julian,3) AS int), DATEADD(YEAR, CAST(LEFT(@Julian,LEN(@Julian)-3) AS int), '31-dec-1899'))
1 голос
/ 15 декабря 2015

ДАТА (CHAR (1900000 + GLDGJ)), где GLDGJ - значение юлианской даты

0 голосов
/ 01 февраля 2019

Я не думаю, что кто-то упоминал об этом, но JDE имеет таблицу только для этого.

Это таблица данных F00365.Насколько я знаю, это таблица перевода только для этой проблемы.

Чтобы получить григорианскую дату, вы присоединяетесь к таблице F00365 с помощью поля ONDTEJ (которое является юлианской датой) и возвращаете значение ONDATE., который является григорианским.например,

SELECT 
    DateReq.ONDATE 
FROM F00101 NamesData 
INNER JOIN F00365 DateReq 
    ON DateReq.ONDTEJ = NamesData.ABUPMJ

Математика не требуется.Никаких странных проблем с високосными годами.

0 голосов
/ 18 августа 2015
USE [master]
GO
/****** Object:  UserDefinedFunction [dbo].[ToGregorian]    Script Date: 08/18/2015 14:33:17 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[ToGregorian](@julian varchar(6),@time varchar(6))
RETURNS datetime 
AS 
BEGIN
    DECLARE @datetime datetime,@hour int, @minute int, @second int

    set @time = ltrim(rtrim(@time));
    set @julian = ltrim(rtrim(@julian));

    if(LEN(@julian) = 5)
        set @julian = '0' + @julian


    IF(LEN(@time) = 6)
        BEGIN
            SET @hour = Convert(int,LEFT(@time,2));
            SET @minute = CONVERT(int,Substring(@time,3,2));
            SET @second = CONVERT(int,Substring(@time,5,2));
        END
    else IF(LEN(@time) = 5)
        BEGIN
            SET @hour = Convert(int,LEFT(@time,1));
            SET @minute = CONVERT(int,Substring(@time,2,2));
            SET @second = CONVERT(int,Substring(@time,4,2));
        END
    else IF(LEN(@time) = 4)
        BEGIN
            SET @hour = 0;
            SET @minute = CONVERT(int,LEFT(@time,2));
            SET @second = CONVERT(int,Substring(@time,3,2));
        END
    else IF(LEN(@time) = 3)
        BEGIN
            SET @hour = 0;
            SET @minute = CONVERT(int,LEFT(@time,1));
            SET @second = CONVERT(int,Substring(@time,2,2));
        END
    else
        BEGIN
            SET @hour = 0;
            SET @minute = 0;
            SET @second = @time;
        END

    SET @datetime = DATEADD(YEAR,100*CONVERT(INT, LEFT(@julian,1))+10*CONVERT(INT, SUBSTRING(@julian, 2,1))+CONVERT(INT, SUBSTRING(@julian,3,1)),0);                     
    SET @datetime = DATEADD(DAY, CONVERT(INT,SUBSTRING(@julian, 4, 3))-1,@datetime);                   
    SET @datetime = DATEADD(hour,@hour,@datetime)
    SET @datetime = DATEADD(minute,@minute,@datetime);
    SET @datetime = DATEADD(second,@second,@datetime);

    RETURN @datetime
END
...