Преобразовать код даты Excel в «дату»

15

Если задан неотрицательный целочисленный код даты в стиле Excel, верните соответствующую «дату» в любой разумной форме, которая четко показывает год, месяц и «день».

Тривиально, вы можете подумать. Вы заметили "напуганные цитаты"? Я использовал их, потому что в Excel есть некоторые причуды. Excel подсчитывает дни с цифрой 1 на 1 января ст , 1900, но , как если бы 1900 был января 0 - й и 29 февраля - го , так что будьте очень осторожны , чтобы попробовать все тестовые случаи:

 Input → Output (example format)
     0 → 1900-01-00    Note: NOT 1899-12-31
     1 → 1900-01-01
     2 → 1900-01-02
    59 → 1900-02-28
    60 → 1900-02-29    Note: NOT 1900-03-01
    61 → 1900-03-01
   100 → 1900-04-09
  1000 → 1902-09-26
 10000 → 1927-05-18
100000 → 2173-10-14
Адам
источник
1
У каждого года 0 января и 29 февраля или 1900 год - единственная аномалия?
Лохматый
4
1900 год - это аномалия. Excel правильно обрабатывает високосные годы, за исключением 1900 года (который не является високосным годом). Но это было для совместимости с Lotus 1-2-3, где возникла ошибка.
Рик Хичкок
3
@RickHitchcock Очевидно, что разработчики Lotus 1-2-3 сделали это, чтобы сэкономить на коде високосного года, так что правило просто становилось раз в четыре года. С уважением тоже; 1900 год был далеко в прошлом, а 2100 - ну, через некоторое время.
Адам
3
@RickHitchcock Вполне возможно, что оригинальный Lotus 1-2-3 не мог справиться с Y2K, и поэтому Microsoft решила повторить эту проблему, но в остальном осталась верной. Кстати, наследие живет на: OADate .NET имеет эпоху 1899-12- 30 так , что она будет выстраиваться с Excel на всех , кроме первых двух месяцев 1900 года , однако это требует DayOfWeekметод , потому что оригинальная эпоха, 1899-12-30 (или фиктивный 1900-01-00) был выбран таким, чтобы будний день был просто мод-7 числа дня, но это не сработает с 1899-12-30.
Адам
4
Вот история «почему» насчет дат Excel: Джоэл о программном обеспечении: мой первый обзор BillG . Информативное (и занимательное) чтение.
BradC

Ответы:

14

Excel, 3 (+7?)

=A1

с форматом

yyy/m/d

Чистый порт

l4m2
источник
Формат вывода, конечно, может отличаться в зависимости от вашей локали.
Адам
2
Это работает только в Excel для Windows. В Excel для Mac есть система счисления, которая начинается с дат 1904 года, а не 1900 года. Он не будет сообщать дату 1900 года, являющуюся частью контрольных примеров. Вы можете указать, что это Excel для Windows.
Кита - восстановить Монику
1
@Keeta Чтобы это работало в Excel для Mac, просто снимите флажок «Использовать систему дат 1904» в настройках .
BradC
1
@BradC Хотя и верно, любое изменение конфигурации программы по умолчанию совершенно нормально, НО должно быть включено в ответ. Я комментирую это как пункт, чтобы улучшить ответ. Я бы сказал, что либо измените его название на Excel для Windows, добавьте предостережение, либо переключитесь на OpenOffice Calc (или аналогичный, так как они также целенаправленно включали ошибку). codegolf.meta.stackexchange.com/questions/10037/…
Keeta - восстановить Монику
6

к (кдб + 3,5), 55 54 51 50 байт

{$(`1900.01.00`1900.02.29,"d"$x-36526-x<60)0 60?x}

чтобы проверить, вставьте эту строку в консоль q:

k)-1@{$(`1900.01.00`1900.02.29,"d"$x-36526-x<60)0 60?x}'0 1 2 59 60 61 100 1000 10000 100000;

выход должен быть

1900.01.00
1900.01.01
1900.01.02
1900.02.28
1900.02.29
1900.03.01
1900.04.09
1902.09.26
1927.05.18
2173.10.14

{ } это функция с аргументом x

0 60?xиндекс xсреди 0 60или 2, если не найден

ˋ1900.01.00ˋ1900.02.29 список из двух символов

, добавить к нему

"d"$ преобразован в дату

x-36526 количество дней с 1900 года (вместо 2000 по умолчанию)

- x<60 скорректировать ошибку прыжка в Excel

(ˋ1900.01.00ˋ1900.02.29,"d"$x-36526-x<60)@ 0 60?xjuxtaposition означает индексирование - «@» в середине неявно

$ преобразовать в строку

СПП
источник
1
Для другой версии k (k5 / k6, я думаю), {$[x;$`d$x-65746;"1900.01.00"]} кажется, работает . Я предполагаю, что что-то переполняется где-то 100000.
zgrep
@zgrep Вы должны оставлять сообщения, поскольку версии K в основном совершенно разные языки.
Адам
3

Python 2 , 111 байт

from datetime import*
n=input()
print('1900-0'+'12--0209'[n>9::2],date(1900,1,1)+timedelta(n+~(n>59)))[0<n!=60]

Попробуйте онлайн!

-5 благодаря нгн .

Эрик Outgolfer
источник
Примечание: я почти уверен, что это будет больше, чем лямбда, поскольку формат результата не должен меняться.
Эрик Outgolfer
3

JavaScript (ES6),  89 82  77 байт

Сохранено  7  12 байт благодаря @tsh

n=>(p=n>60?'':19)+new Date(p*400,0,n-!p||1).toJSON().slice(p/9,10-!n)+(n&&'')

Попробуйте онлайн!

Arnauld
источник
n=>n?n-60?new Date(1900,0,n-(n>60)).toJSON().slice(0,10):'1900-02-29':'1900-01-00'
18:00
@tsh Это действительно намного лучше. Благодарю. (Кроме того, мне интересно, можно ли как-нибудь применить этот подход .)
Арно
Я просто узнаю, так new Date(0,0,1)же, как new Date(1900,0,1). Так что удаление 190сохраняет 3 байта. И ...
ТШ
2
77 байт:n=>(p=n>60?'':19)+new Date(p*400,0,n-!p||1).toJSON().slice(p/9,10-!n)+(n&&'')
tsh
Нужно ли его запускать в GMT0 / -x?
l4m2
2

Чистый , 205 189 байт

import StdEnv
a=30;b=31;c=1900;r=rem
@m=sum(take m(?c))
?n=[b,if(n>c&&(r n 4>0||r n 100<1&&r n 400>0))28 29,b,a,b,a,b,b,a,b,a,b: ?(n+1)]
$n#m=while(\m= @m<n)inc 0-1
=(c+m/12,1+r m 12,n- @m)

Попробуйте онлайн!

Οurous
источник
1
Первый ответ, который не использует встроенную обработку даты. Ницца!
Адам
1

APL (Dyalog Classic) , 31 байт

Функция анонимного молчаливого префикса. Возвращает дату как[Y,M,D]

3↑×-60∘≠)+32NQ#263,60∘>+⊢-×

Попробуйте онлайн!

× знак кода даты

⊢- вычесть это из аргумента (код даты)

60∘>+ увеличение, если код даты выше шестидесяти

2⎕NQ#263, используйте это в качестве непосредственного аргумента для «события 263» (IDN на дату).
IDN аналогичен коду даты в Excel, но без 29 февраля 1900 года, а днем ​​ранее 1 января 1900 года является 31 декабря 1899 года.

3↑ возьмите первые три элемента этого (четвертый день недели)

(...)+  Добавьте к ним следующее:

60∘≠ 0, если код даты равен 60; 1, если код даты не 60

×- вычесть это из знака кода даты

¯3↑ возьмите последние три элемента (есть только один), дополняемые (двумя) нулями

разработано вместе с @ Adám в чате

СПП
источник
1

C # (.NET Core) , 186 185 байт

using System;class P{static void Main(){var i=int.Parse(Console.ReadLine());Console.Write((i==0|i==60)?$"1900-{i%59+1}-{i%31}":DateTime.FromOADate(i+(i<60?1:0)).ToString("yyyy-M-d"));}}

Попробуйте онлайн!


-1 байт, заменяя оператор ИЛИ (||) на двоичный оператор ИЛИ (|).

cobaltp
источник
0

T-SQL, 141 95 94 байта

SELECT IIF(n=0,'1/0/1900',IIF(n=60,'2/29/1900',
FORMAT(DATEADD(d,n,-IIF(n<60,1,2)),'d')))FROM i

Разрыв строки предназначен только для удобства чтения.

Ввод берется с помощью уже существующей таблицы я с целочисленным полем п , в соответствии с нашими стандартами IO .

SQL использует аналогичную (но исправленную) начальную точку 1-1-1900 для своего внутреннего формата даты, поэтому мне нужно только сместить ее на 1 или 2 дня в DATEADDфункции.

SQL не может вывести столбец, содержащий сочетание значений даты и символа, поэтому я не могу пропустить FORMATкоманду (так как тогда он попытается преобразовать 1/0/1900в дату, что, конечно, недопустимо).

Что хорошо в SQL, так это то, что я могу загрузить все входные значения в таблицу и запустить их все сразу. В моем (США) районе по умолчанию используется m/d/yyyyформат даты:

n       output
0       1/0/1900
1       1/1/1900
2       1/2/1900
59      2/28/1900
60      2/29/1900
61      3/1/1900
100     4/9/1900
1000    9/26/1902
10000   5/18/1927
43432   11/28/2018
100000  10/14/2173

РЕДАКТИРОВАТЬ : Сохранено 46 байтов путем замены на вложенный IIF()вместо гораздо более многословный CASE WHEN.

РЕДАКТИРОВАТЬ 2 : Сохраненный еще один байт, перемещая -перед IIF.

BradC
источник