Excel tarih kodunu "tarihe" dönüştürme


15

Negatif olmayan bir tamsayı Excel tarzı tarih kodu verildiğinde, karşılık gelen "tarihi" yıl, ay ve "günü" açıkça gösteren herhangi bir makul biçimde döndürün.

Önemsiz, düşünebilirsiniz. "Korkutmak alıntıları" fark ettiniz mi? Bunları kullandım çünkü Excel'in bazı tuhaflıkları var. Excel 1 Ocak için 1 numara ile gün sayar st , 1900, ama 1900 Ocak 0 varmış gibi inci bir 29 Şubat ve inci , bu nedenle tüm test durumları denemek için çok dikkatli olmak:

 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
Does her yıl Şubat ayının bir Ocak 0þ ve 29'da varsa veya sadece anomali 1900?
Shaggy

4
1900 anomalidir. Excel, artık yılları 1900 ( artık yıl değildir ) dışında doğru şekilde ele alır . Ancak bu, hatanın ortaya çıktığı Lotus 1-2-3 ile uyumluluk içindi.
Rick Hitchcock

3
@RickHitchcock Görünüşe göre, Lotus 1-2-3 geliştiricileri artık yıl kodundan tasarruf etmek için yaptı, böylece kural her dört yılda bir oldu. İyi bir sebeple; 1900 geçmişte çok uzundu ve 2100 bir süredir.
Adam

3
@RickHitchcock Orijinal Lotus 1-2-3'ün Y2K ile başa çıkamaması çok iyi olabilir ve bu nedenle Microsoft bu sorunu taklit etmeye karar verdi, aksi takdirde doğru kalmaya karar verdi. Btw, üzerinde eski hayatlar: .NET'in OADate çağı 1899-12- sahiptir 30 o tümü üzerinde Excel ancak 1900 yılının ilk iki ayında ile ancak bu gerektirmektedir hizaya böylece DayOfWeekyöntem orijinal çağ, 1899/12/30 çünkü (ya da kurgusal 1900-01-00), hafta içi gün gününün mod-7'si olacak şekilde seçildi, ancak bu 1899-12-30 ile çalışmaz.
Adam

4
İşte Excel tarihlerinin "neden" in ardındaki hikaye: Yazılımdaki Joel: İlk BillG İncelemem . Bilgilendirici (ve eğlenceli) okuma.
BradC

Yanıtlar:


14

Excel, 3 (+7?)

=A1

formatla

yyy/m/d

Saf liman


Çıktı biçimi elbette bölgenize göre değişebilir.
Adam

2
Bu yalnızca Windows için Excel'de çalışır. Mac için Excel'in 1900 ile değil 1904'te başlayan bir sayı sistemi vardır. 1900'de herhangi bir yıl için test durumlarının bir parçası olan bir tarih bildirmez. Bunun Windows için Excel olduğunu belirtmek isteyebilirsiniz.
Keeta - Monica'yı

1
@Keeta Bunun Mac için Excel'de çalışması için, tercihlerde "1904 tarih sistemini kullan" seçeneğinin işaretini kaldırmanız yeterlidir .
BradC

1
@BradC Her ne kadar doğru olsa da, bir programın varsayılan yapılandırmasında yapılan herhangi bir değişiklik mükemmel derecede iyidir, ancak cevaba dahil edilmelidir. Bunu cevabı geliştirmek için bir nokta olarak yorumluyorum. Ya Windows için Excel'e adını değiştirmek, uyarıyı eklemek ya da OpenOffice Calc (ya da benzer, çünkü onlar da çok amaçlı hata dahil) geçmek için söyleyebilirim. codegolf.meta.stackexchange.com/questions/10037/…
Keeta - Monica'yı eski durumuna döndür

6

k (kdb + 3,5), 55 54 51 50 bayt

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

test etmek için bu satırı q konsoluna yapıştırın:

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;

çıktı olmalı

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

{ } argümanlı bir işlevdir x

0 60?xxarasında 0 60veya 2 bulunmazsa dizini

ˋ1900.01.00ˋ1900.02.29 iki sembolün bir listesi

, ona ekle

"d"$ bir tarihe dönüştürüldü

x-36526 1900'den bu yana geçen gün sayısı (varsayılan 2000 yerine)

- x<60 Excel'in sıçrama hatası için ayarlama

(ˋ1900.01.00ˋ1900.02.29,"d"$x-36526-x<60)@ 0 60?xjuxtaposition dizin oluşturma anlamına gelir - ortadaki "@" örtük

$ dizeye dönüştür


1
Farklı bir k sürümü için (k5 / k6, sanırım), {$[x;$`d$x-65746;"1900.01.00"]} işe yarıyor gibi görünüyor . Bir yerde bir şeyin taştığını varsayıyorum 100000.
zgrep

@zgrep K sürümleri temelde birbirinden tamamen farklı diller olduğundan gönderi yapmalısınız.
Adam


3

JavaScript (ES6),  89 82  77 bayt

Kaydedilen  7  12 @tsh sayesinde bayt

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

Çevrimiçi deneyin!


n=>n?n-60?new Date(1900,0,n-(n>60)).toJSON().slice(0,10):'1900-02-29':'1900-01-00'
tsh

@tsh Gerçekten çok daha iyi. Teşekkürler. (Ayrıca, bu yaklaşımın bir şekilde golf oynayabileceğini merak ediyorum .)
Arnauld

Ben sadece new Date(0,0,1)aynı olduğunu öğreniyorum new Date(1900,0,1). Yani kaldır 1903 bayt kaydeder. Ve ...
tsh

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

GMT0 / -x ile çalıştırılması gerekiyor mu?
l4m2

2

Temiz , 205 189 bayt

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)

Çevrimiçi deneyin!


1
Dahili tarih işlemeyi kullanmayan ilk yanıt. Güzel!
Adam


1

APL (Dyalog Klasik) , 31 bayt

Anonim zımni önek fonksiyonu. Tarihi şu şekilde döndürür:[Y,M,D]

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

Çevrimiçi deneyin!

× tarih kodunun işareti

⊢- bunu argümandan çıkartın (tarih kodu)

60∘>+ tarih kodu altmışın üzerindeyse artış

2⎕NQ#263, "Olay 263" (IDN bugüne kadar) için hemen argüman olarak kullanın
IDN, Excel'in tarih kodu gibi, ancak 29 Şubat 1900 olmadan ve 1 Ocak 1900'den önceki gün 31 Aralık 1899

3↑ bunun ilk üç unsurunu al (dördüncüsü haftanın günüdür)

()+ Bunlara aşağıdakileri ekleyin:

60∘≠ Tarih kodu 60 ise 0; 1 tarih kodu 60 değilse

×- bunu tarih kodunun işaretinden çıkarın

¯3↑ (iki) sıfır ile son üç öğeyi (yalnızca bir tane var) doldurun

sohbet içinde @ Adám ile birlikte geliştirildi


1

C # (.NET Çekirdek) , 186 185 bayt

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

Çevrimiçi deneyin!


VEYA işlecini (||) ikili VEYA işleci (|) ile değiştirerek -1 bayt.



0

T-SQL, 141 95 94 bayt

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

Satır sonu yalnızca okunabilirlik içindir.

Girdi önceden var olan tabloya yoluyla alınır i tamsayı alanı ile n , bizim IO standartlarına göre .

SQL, dahili tarih biçimi için benzer (ancak düzeltilmiş) bir 1-1-1900 başlangıç ​​noktası kullanır, bu yüzden işlevde yalnızca 1 veya 2 gün dengelemek zorundayım DATEADD.

SQL, tarih ve karakter değerlerinin bir karışımını içeren bir sütunu çıktılayamaz, bu yüzden FORMATkomutu bırakamam (çünkü daha sonra dönüştürmeyi deneyecekti)1/0/1900 tabii ki geçersiz bir tarihe için .

SQL ile ilgili güzel olan şey, tüm giriş değerlerini tabloya yükleyebilmem ve hepsini bir kerede çalıştırabilmemdir. Konumum varsayılan olarak bir m/d/yyyytarih biçimidir:

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 : IIF()çok daha ayrıntılı yerine bir yuvalanmış değiştirerek 46 bayt kurtardı CASE WHEN.

DÜZENLEME 2 : öğesinin -önüne hareket ettirilerek başka bir bayt kaydedildi IIF.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.