странная проблема с датой эпохи

Я работаю с набором данных, в котором есть поле даты с датами, которые выглядят следующим образом:

42437.4261290278
42437.5460402431
42437.5478825116

причем большее из чисел является самым последним. Один из нас считает, что это связано с эпохой Unix и альтернативными представлениями времени. Проблема, с которой мы сталкиваемся сейчас, заключается в чтении этих дат в стандартном формате MM-DD-YYYY. У кого-нибудь есть идеи о том, как преобразовать эти альтернативные формы даты в стандартные даты?

Я пытаюсь сделать это на С#. И для справки, я ожидаю, что последние две указанные даты будут где-то 8 марта 2016 года, а первая — незадолго до этого.


person RunFranks525    schedule 10.03.2016    source источник
comment
Возможно, вы захотите указать, откуда взялся набор данных. Это из другого приложения, базы данных или электронной таблицы? Лучше всего предположить, что это количество целых и неполных дней после некоторого базового уровня, но без знания базовой даты или единиц преобразование будет догадкой. 42437 дней назад — это где-то 1900 или 1901 год.   -  person Phil DD    schedule 10.03.2016
comment
Я думаю, что IBM может использовать базовую линию 1900-01-01 для некоторых расчетов дат...   -  person Phil DD    schedule 10.03.2016
comment
Это из базы данных Oracle. На самом деле единственная информация, к которой у меня есть доступ, это сами цифры.   -  person RunFranks525    schedule 10.03.2016
comment
Как вы получаете значения из базы данных? Из какого столбца берутся значения?   -  person Andrew Morton    schedule 10.03.2016
comment
тип столбца - номер Oracle   -  person RunFranks525    schedule 10.03.2016
comment
@ RunFranks525 1) Вы абсолютно уверены в том, какими, по вашему мнению, должны быть эти даты? Когда дата-время хранится как число с плавающей запятой, обычно дни, прошедшие с эпохи, сохраняются как целая часть, а доля дня — как дробная часть. Это говорит о том, что все ваши примеры относятся к одному и тому же дню. 2) Есть ли у вас способ найти код, в котором хранятся эти значения, и попытаться выяснить, что происходит?   -  person Andrew Morton    schedule 10.03.2016
comment
@AndrewMorton Я уверен, что 2-е и 3-е свидания приходятся на 8-е, первое вполне может быть и 8-го, но незадолго до 2-го и 3-го. К сожалению, эти данные вводятся через другое программное обеспечение, поэтому мы не видим, как они вводятся на самом деле.   -  person RunFranks525    schedule 11.03.2016
comment
@ RunFranks525 Можете ли вы убедиться, что система, которая вводит даты, правильно установила системную дату, и каким-то образом заставить ее создать запись, которая будет представлять сегодняшний день? И засеките время. Очень странно, что, кажется, прошло несколько дней с 1970-01-01 00:00:00, а вы говорите, что это было два дня назад.   -  person Andrew Morton    schedule 11.03.2016


Ответы (2)


Следуя вашему утверждению о том, что представлены даты 08.03.2016, я предполагаю, что начало эпохи - 30.12.1899:

static string UnixTimeStampToDateAsString(double ts)
{
    DateTime epoch = new DateTime(1899, 12, 30);
    DateTime d = epoch.AddDays(ts);
    return (d.ToString("yyyy-MM-dd HH:mm:ss"));
}

static void Main(string[] args)
{
    foreach (double dateNumber in new double[] { 42437.4261290278, 42437.5460402431, 42437.5478825116 })
    {
        Console.WriteLine(UnixTimeStampToDateAsString(dateNumber));
    }
    Console.ReadLine();

}

Выходы:

2016-03-08 10:13:37
2016-03-08 13:06:17
2016-03-08 13:08:57

Я должен заявить, что 30 декабря 1899 года — довольно маловероятное значение, но я полагаю, что у кого-то могла быть «причина» использовать это.

Изменить Благодаря @EricLippert я могу предложить это:

Console.WriteLine(DateTime.FromOADate(dateNumber).ToString("yyyy-MM-dd HH:mm:ss"));
person Andrew Morton    schedule 10.03.2016
comment
На самом деле не только есть причина, основатель этого сайта может сказать вам, что это за причина. Смотрите мой ответ. - person Eric Lippert; 11.03.2016
comment
@EricLippert Спасибо! Это напомнило мне о функциях OADate. Вы или Джоэл написали метод DateTime.FromOADate? Я вижу, что Рэймонд Чен говорит использовать их в статье, связанной с вашей. - person Andrew Morton; 11.03.2016
comment
Я не. Однако я написал эту функцию в среде выполнения JScript и большую часть библиотеки дат VBScript. Хорошие времена. Джоэл ушел из MSFT в 1994 году, и я никогда не встречался с ним, когда был стажером. - person Eric Lippert; 11.03.2016

Это значения OLE Automation VT_DATE. Это система дат, используемая продуктами Microsoft, такими как Excel и версии Visual Basic до .NET. Это несколько странный формат даты.

Формат таков: считайте, что число double состоит из двух частей: целого числа со знаком и дроби без знака. Целое число со знаком — это количество дней, прошедших с 30 декабря 1899 года. Обратите внимание: НЕ 31 декабря 1899 года и НЕ 1 января 1900 года. Дробь — это часть 24-часового (всегда!) прошедшего дня. Никаких поправок на 23- или 25-часовой рабочий день, который у нас бывает два раза в год, не делается.

У этого формата интересная (для меня) история; вы можете прочитать об этом в моей статье в блоге от 2003 года:

https://blogs.msdn.microsoft.com/ericlippert/2003/09/16/erics-complete-guide-to-vt_date/

И статья основателя Stack Overflow Джоэла Спольски от 2006 года:

http://www.joelonsoftware.com/items/2006/06/16.html

Обратите внимание: если у вас есть отрицательные значения VT_DATE, вы должны быть очень осторожны, чтобы получить правильное преобразование. Код не сложный; это всего лишь пара строк, но вы должны тщательно обдумать это. Раньше я спрашивал «возьмите разницу между двумя VT_DATE» в качестве вопроса на собеседовании, и удивительное количество кандидатов на самом деле не могут выполнять вычитание.

person Eric Lippert    schedule 11.03.2016
comment
Люди могут возненавидеть вас в далеком будущем за все ваши признания :D Умные люди не будут :) - person leppie; 11.03.2016
comment
ОТ: Я бы хотел, чтобы вы были более активны в дискуссиях о C# на Github, хотя бы ради исторического обзора. Вы знаете больше, чем большинство в этой области. - person leppie; 11.03.2016
comment
@leppie: я собирался это сделать. Не хватает часов в сутках! - person Eric Lippert; 11.03.2016
comment
@Eric: я упустил тот факт, что последние две метки времени в вопросе должны представлять 8 марта .. Так что вы были правы, это не может быть эпоха NTP (1 января 1900 г.), я удалил свой ответ. - person Sandman; 11.03.2016