Ubah kode tanggal Excel menjadi "tanggal"

15

Diberikan kode tanggal gaya Excel non-negatif integer, kembalikan "tanggal" yang sesuai dalam bentuk wajar apa pun yang dengan jelas menunjukkan tahun, bulan, dan "hari".

Sepele, Anda mungkin berpikir. Apakah Anda memperhatikan "kutipan menakut-nakuti"? Saya menggunakan itu karena Excel memiliki beberapa kebiasaan. Excel menghitung hari dengan nomor 1 untuk Januari 1 st , 1900, tetapi seolah 1900 memiliki 0 Januari th dan 29 Feb th , jadi sangat berhati-hati untuk mencoba semua kasus uji:

 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
Adm
sumber
1
Apakah setiap tahun memiliki 0 Januari dan 29 Februari atau 1900 adalah satu-satunya anomali?
Shaggy
4
1900 adalah anomali. Excel memperlakukan tahun kabisat dengan benar kecuali untuk tahun 1900 (yang bukan tahun kabisat). Tapi itu untuk kompatibilitas dengan Lotus 1-2-3, di mana bug berasal.
Rick Hitchcock
3
@RickHitchcock Rupanya, Lotus 1-2-3 devs melakukannya untuk menghemat kode tahun kabisat, sehingga aturan hanya menjadi setiap tahun keempat. Dengan alasan yang bagus juga; 1900 jauh di masa lalu, dan 2100, yah, sebentar lagi.
Adám
3
@ RickHitchcock Mungkin sekali Lotus 1-2-3 asli tidak dapat menangani Y2K, dan karenanya Microsoft memutuskan untuk meniru satu masalah itu, tetapi jika tidak, tetaplah benar. Btw, kehidupan warisan pada: NET OADate memiliki zaman 1899-12- 30 sehingga akan berbaris dengan Excel pada semua tapi dua bulan pertama 1900, namun memerlukan ini DayOfWeekmetode karena zaman asli, 1899/12/30 (atau fiktif 1900-01-00) dipilih sedemikian rupa sehingga hari kerja hanyalah mod-7 dari jumlah hari, tetapi itu tidak akan bekerja dengan 1899-12-30.
Adám
4
Inilah kisah di balik "mengapa" tentang tanggal Excel: Joel on Software: My First BillG Review . Informatif (dan menghibur) baca.
BradC

Jawaban:

14

Excel, 3 (+7?)

=A1

dengan format

yyy/m/d

Port murni

l4m2
sumber
Format output tentu saja dapat bervariasi sesuai dengan lokal Anda.
Adám
2
Ini hanya berfungsi di Excel untuk Windows. Excel untuk Mac memiliki sistem angka yang dimulai dengan tanggal pada 1904, bukan 1900. Excel tidak akan melaporkan tanggal untuk tahun apa pun di 1900, yang merupakan bagian dari kasus uji. Anda mungkin ingin menentukan bahwa ini adalah Excel untuk Windows.
Keeta - mengembalikan Monica
1
@Keeta Agar ini berfungsi di Excel untuk Mac, cukup hapus centang "Gunakan sistem tanggal 1904" di preferensi .
BradC
1
@BradC Meskipun benar, setiap perubahan pada konfigurasi default suatu program baik-baik saja TETAPI harus dimasukkan dalam jawaban. Saya berkomentar sebagai titik untuk meningkatkan jawaban. Saya akan mengatakan baik beralih nama itu ke Excel untuk Windows, tambahkan peringatan, atau beralih ke OpenOffice Calc (atau serupa, karena mereka sengaja memasukkan bug juga). codegolf.meta.stackexchange.com/questions/10037/…
Keeta - mengembalikan Monica
6

k (kdb + 3.5), 55 54 51 50 byte

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

untuk menguji, rekatkan baris ini di konsol 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;

output seharusnya

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

{ } adalah fungsi dengan argumen x

0 60?xindeks xantara 0 60atau 2 jika tidak ditemukan

ˋ1900.01.00ˋ1900.02.29 daftar dua simbol

, menambahkannya

"d"$ dikonversi menjadi tanggal

x-36526 jumlah hari sejak tahun 1900 (bukan standar 2000)

- x<60 sesuaikan untuk kesalahan lompatan excel

(ˋ1900.01.00ˋ1900.02.29,"d"$x-36526-x<60)@ 0 60?xjuxtaposition berarti pengindeksan - "@" di tengahnya implisit

$ dikonversi ke string

ngn
sumber
1
Untuk versi k yang berbeda (k5 / k6, saya pikir), {$[x;$`d$x-65746;"1900.01.00"]} sepertinya berfungsi . Saya berasumsi sesuatu meluap ke suatu tempat 100000.
zgrep
@zgrep Anda harus memposting karena versi K pada dasarnya adalah bahasa yang sama sekali berbeda.
Adám
3

Python 2 , 111 byte

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

Cobalah online!

-5 Terima kasih kepada ngn .

Erik the Outgolfer
sumber
Catatan: Saya cukup yakin ini akan menjadi lebih lama dari lambda, karena format hasilnya tidak akan bervariasi.
Erik the Outgolfer
3

JavaScript (ES6),  89 82  77 byte

Disimpan  7  12 byte berkat @tsh

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

Cobalah online!

Arnauld
sumber
n=>n?n-60?new Date(1900,0,n-(n>60)).toJSON().slice(0,10):'1900-02-29':'1900-01-00'
tsh
@ tsh Itu memang jauh lebih baik. Terima kasih. (Juga, saya ingin tahu apakah pendekatan ini entah bagaimana bisa golf.)
Arnauld
Saya baru tahu new Date(0,0,1)sama saja new Date(1900,0,1). Jadi hapus 190save 3 byte. Dan ...
tsh
2
77 byte:n=>(p=n>60?'':19)+new Date(p*400,0,n-!p||1).toJSON().slice(p/9,10-!n)+(n&&'')
tsh
Apakah harus dijalankan dalam GMT0 / -x?
14m2
2

Bersih , 205 189 byte

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)

Cobalah online!

Suram
sumber
1
Jawaban pertama yang tidak menggunakan penanganan tanggal bawaan. Bagus!
Adám
1

Japt, 43 byte

Berakhir dengan port bagian dari solusi Arnauld .

Output dalam yyyy-m-dformat.

?U-#<?Ð#¾0TUaU>#<)s7:"1900-2-29":"1900-1-0"

Cobalah online atau uji 0-100

Shaggy
sumber
1

APL (Dyalog Classic) , 31 byte

Fungsi awalan diam-diam anonim. Tanggal pengembalian sebagai[Y,M,D]

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

Cobalah online!

× tanda kode tanggal

⊢- kurangi itu dari argumen (kode tanggal)

60∘>+ increment jika kode tanggal di atas enam puluh

2⎕NQ#263, gunakan itu sebagai argumen langsung untuk "Event 263" (IDN to date)
IDN sama seperti kode tanggal Excel, tetapi tanpa 29 Februari 1900, dan sehari sebelum 1 Januari 1900 adalah 31 Desember 1899

3↑ ambil tiga elemen pertama dari itu (yang keempat adalah hari dalam seminggu)

(... )+ tambahkan yang berikut ke yang berikut:

60∘≠ 0 jika kode tanggal adalah 60; 1 jika kode tanggal bukan 60

×- kurangi itu dari tanda kode tanggal

¯3↑ ambil tiga elemen terakhir (hanya ada satu) padding dengan (dua) nol

dikembangkan bersama dengan @Adám dalam obrolan

ngn
sumber
1

C # (.NET Core) , 186 185 byte

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"));}}

Cobalah online!


-1 byte dengan mengganti operator OR (||) dengan operator biner OR (|).

cobaltp
sumber
0

Perl 6 , 81 byte

{$_??$_-60??Date.new-from-daycount($_+15018+(60>$_))!!'1900-02-29'!!'1900-01-00'}

Cobalah online!

nwellnhof
sumber
0

T-SQL, 141 95 94 byte

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

Line break hanya untuk keterbacaan.

Input diambil melalui tabel i yang sudah ada sebelumnya dengan bidang bilangan bulat n , sesuai standar IO kami .

SQL menggunakan titik awal 1-1-1900 yang sama (tetapi diperbaiki) untuk format tanggal internal, jadi saya hanya perlu mengimbanginya dengan 1 atau 2 hari dalam DATEADDfungsi.

SQL tidak dapat menampilkan kolom yang berisi campuran nilai tanggal dan karakter, jadi saya tidak bisa mengabaikan FORMATperintah (karena itu akan mencoba untuk mengkonversi 1/0/1900ke tanggal, yang tentu saja tidak valid).

Apa yang baik tentang SQL adalah bahwa saya dapat memuat semua nilai input ke dalam tabel dan menjalankan semuanya sekaligus. Lokalitas (AS) saya default ke m/d/yyyyformat tanggal:

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

EDIT : Disimpan 46 byte dengan mengubah menjadi bersarang IIF()alih-alih lebih banyak verbose CASE WHEN.

EDIT 2 : Menyimpan byte lain dengan menggerakkan bagian -depan IIF.

BradC
sumber