Chuyển đổi mã ngày Excel thành ngày chà


15

Cho mã ngày số nguyên kiểu Excel không âm, trả về "ngày" tương ứng ở bất kỳ dạng hợp lý nào hiển thị rõ ràng năm, tháng và "ngày".

Tầm thường, bạn có thể nghĩ. Bạn có nhận thấy "trích dẫn sợ hãi"? Tôi đã sử dụng chúng vì Excel có một số quirks. Excel đếm ngày với số 1 cho ngày 01 tháng 1 st , năm 1900, nhưng , nếu như năm 1900 đã có một tháng một 0 ngày và một tháng hai 29 ngày , vì vậy phải rất cẩn thận để thử tất cả các trường hợp thử nghiệm:

 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
Có phải mọi năm đều có 0 tháng 1 và 29 tháng 2 hay 1900 là sự bất thường duy nhất?
Shaggy

4
1900 là sự bất thường. Excel xử lý các năm nhuận một cách chính xác ngoại trừ năm 1900 ( không phải là năm nhuận). Nhưng đó là để tương thích với Lotus 1-2-3, nơi lỗi bắt nguồn.
Rick Hitchcock

3
@RickHitchcock Rõ ràng, các nhà phát triển Lotus 1-2-3 đã làm điều đó để tiết kiệm mã năm nhuận, sao cho quy tắc đơn giản trở thành mỗi năm thứ tư. Với lý do chính đáng quá; 1900 là quá khứ, và 2100 là, trong một thời gian.
Adám

3
@RickHitchcock Rất có thể Lotus 1-2-3 ban đầu không thể xử lý Y2K, và vì vậy Microsoft đã quyết định bắt chước một vấn đề đó, nhưng nếu không thì vẫn đúng. Btw, cuộc sống di sản trên: OADate NET của thời đại có 1899-12- 30 để nó sẽ thẳng hàng với Excel trên tất cả ngoại trừ hai tháng đầu năm 1900, tuy nhiên đòi hỏi này, DayOfWeekphương pháp vì kỷ nguyên gốc, 1899/12/30 (hoặc giả tưởng 1900-01-00) đã được chọn sao cho ngày trong tuần chỉ đơn giản là mod-7 của số ngày, nhưng điều đó sẽ không hoạt động với 1899-12-30.
Adám

4
Đây là câu chuyện đằng sau "lý do" về ngày tháng của Excel: Joel trên Phần mềm: Đánh giá BillG đầu tiên của tôi . Thông tin (và giải trí) đọc.
BradC

Câu trả lời:


13

Excel, 3 (+7?)

=A1

với định dạng

yyy/m/d

Cổng tinh khiết


Định dạng đầu ra tất nhiên có thể thay đổi tùy theo ngôn ngữ của bạn.
Adám

2
Điều này chỉ hoạt động trên Excel cho Windows. Excel for Mac có một hệ thống số bắt đầu bằng ngày vào năm 1904, không phải năm 1900. Nó sẽ không báo cáo ngày cho bất kỳ năm nào vào năm 1900, là một phần của các trường hợp thử nghiệm. Bạn có thể muốn xác định rằng đây là Excel cho Windows.
Keeta - phục hồi Monica

1
@Keeta Để điều này hoạt động trên Excel cho Mac, chỉ cần bỏ chọn "Sử dụng hệ thống ngày 1904" trong tùy chọn .
BradC

1
@BradC Mặc dù đúng, mọi thay đổi đối với cấu hình mặc định của chương trình là hoàn toàn tốt NHƯNG phải được đưa vào câu trả lời. Tôi nhận xét đây là một điểm để cải thiện câu trả lời. Tôi có thể nói hoặc chuyển tên của nó thành Excel cho Windows, thêm cảnh báo hoặc chuyển sang OpenOffice Calc (hoặc tương tự, vì chúng cũng cố tình bao gồm cả lỗi). codegolf.meta.stackexchange.com/questions/10037/ trộm
Keeta - phục hồi 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}

để kiểm tra, dán dòng này trong bảng điều khiển 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;

đầu ra phải là

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

{ } là một hàm với đối số x

0 60?xchỉ số trong xsố 0 60hoặc 2 nếu không tìm thấy

ˋ1900.01.00ˋ1900.02.29 một danh sách hai biểu tượng

, nối vào nó

"d"$ chuyển đổi thành một ngày

x-36526 số ngày kể từ năm 1900 (thay vì 2000 mặc định)

- x<60 điều chỉnh cho lỗi nhảy vọt của excel

(ˋ1900.01.00ˋ1900.02.29,"d"$x-36526-x<60)@ 0 60?xjuxtap vị trí có nghĩa là lập chỉ mục - "@" ở giữa là ẩn

$ chuyển đổi thành chuỗi


1
Đối với một phiên bản khác của k (k5 / k6, tôi nghĩ), {$[x;$`d$x-65746;"1900.01.00"]} dường như hoạt động . Tôi giả sử một cái gì đó tràn ra ở đâu đó cho 100000.
zgrep

@zgrep Bạn nên đăng bài vì các phiên bản của K về cơ bản là các ngôn ngữ không giống nhau.
Adám


3

JavaScript (ES6),  89 82  77 byte

Đã lưu  7  12 byte nhờ @tsh

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

Hãy thử trực tuyến!


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

@tsh Điều đó thực sự tốt hơn nhiều. Cảm ơn. (Ngoài ra, tôi tự hỏi liệu cách tiếp cận này bằng cách nào đó có thể được đánh golf.)
Arnauld

Tôi chỉ tìm hiểu new Date(0,0,1)là giống như new Date(1900,0,1). Vì vậy, loại bỏ 190tiết kiệm 3 byte. Và ...
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

Có cần chạy trong GMT0 / -x không?
l4m2

2

Sạch , 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)

Hãy thử trực tuyến!


1
Câu trả lời đầu tiên không sử dụng xử lý ngày tích hợp. Đẹp!
Adám


1

APL (Dyalog Classic) , 31 byte

Chức năng tiền tố ẩn danh. Trả về ngày là[Y,M,D]

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

Hãy thử trực tuyến!

× ký mã ngày

⊢- trừ đi từ đối số (mã ngày)

60∘>+ gia tăng nếu mã ngày trên sáu mươi

2⎕NQ#263, sử dụng đó làm đối số ngay lập tức cho "Sự kiện 263" (IDN cho đến nay)
IDN giống như mã ngày của Excel, nhưng không có ngày 29 tháng 2 năm 1900 và một ngày trước ngày 1 tháng 1 năm 1900 là ngày 31 tháng 12 năm 1899

3↑ lấy ba yếu tố đầu tiên (yếu tố thứ tư là ngày trong tuần)

(Giáo dục)+  thêm những điều sau đây để những người:

60∘≠ 0 nếu mã ngày là 60; 1 nếu mã ngày không phải là 60

×- trừ đi từ dấu của mã ngày

¯3↑ lấy ba phần tử cuối cùng (chỉ có một) phần đệm với (hai) số không

được phát triển cùng với @ Adám trong trò chuyện


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

Hãy thử trực tuyến!


-1 byte bằng cách thay thế toán tử OR (||) bằng toán tử OR nhị phân (|).



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

Ngắt dòng chỉ dành cho khả năng đọc.

Đầu vào được lấy thông qua bảng i có sẵn với số nguyên n , theo tiêu chuẩn IO của chúng tôi .

SQL sử dụng điểm bắt đầu 1-1-1900 tương tự (nhưng đã sửa) cho định dạng ngày bên trong của nó, vì vậy tôi chỉ phải bù lại 1 hoặc 2 ngày trong DATEADD hàm.

SQL không thể xuất ra một cột chứa hỗn hợp các giá trị ngày và ký tự, vì vậy tôi không thể bỏ FORMATlệnh (vì sau đó nó sẽ cố gắng chuyển đổi1/0/1900 thành một ngày, tất nhiên là không hợp lệ).

Điều tuyệt vời ở SQL là tôi có thể tải lên tất cả các giá trị đầu vào vào bảng và chạy tất cả chúng cùng một lúc. Địa phương của tôi (Hoa Kỳ) mặc định ở m/d/yyyyđịnh dạng ngày:

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 : Đã lưu 46 byte bằng cách thay đổi thành lồng nhau IIF()thay vì dài dòng hơn nhiều CASE WHEN.

EDIT 2 : Đã lưu một byte khác bằng cách di chuyển -phía trước IIF.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.