แปลงรหัสวันที่ของ Excel เป็น“ date”


15

รับรหัสวันที่ในรูปแบบ Excel ที่ไม่เป็นลบจำนวนเต็มคืนค่า "วันที่" ที่สอดคล้องกันในรูปแบบที่สมเหตุสมผลซึ่งแสดงปีเดือนและ "วัน" อย่างชัดเจน

เล็กน้อยคุณอาจคิดว่า คุณสังเกตเห็น "คำพูดที่ทำให้ตกใจ" หรือไม่? ฉันใช้สิ่งเหล่านี้เพราะ Excel มีข้อผิดพลาดบางอย่าง Excel นับวันที่มีจำนวน 1 มกราคม 1 ST 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 เพียงความผิดปกติ?
Shaggy

4
1900 คือความผิดปกติ Excel ถือว่าการก้าวกระโดดอย่างถูกต้องยกเว้นปี 1900 (ซึ่งไม่ใช่ปีอธิกสุรทิน) แต่นั่นก็เพื่อความเข้ากันได้กับ Lotus 1-2-3 ซึ่งข้อผิดพลาดเกิดขึ้น
Rick Hitchcock

3
@ RickHitchcock เห็นได้ชัดว่า Lotus 1-2-3 devs ทำเพื่อประหยัดรหัสปีอธิกสุรทินเช่นนี้กฎก็กลายเป็นทุก ๆ ปีที่สี่ ด้วยเหตุผลที่ดีเช่นกัน 1900 เคยผ่านมานานแล้วและ 2100 ก็อยู่ในระยะเวลาหนึ่ง
Adám

3
@ RickHitchcock มันอาจเป็นไปได้ว่า Lotus 1-2-3 ดั้งเดิมไม่สามารถจัดการกับ Y2K ได้ดังนั้น Microsoft จึงตัดสินใจที่จะเลียนแบบปัญหานั้น แต่ก็ไม่ผิด Btw, ชีวิตมรดกเมื่อ: .NET ของ OADate มียุค 1899-12- 30เพื่อที่จะสอดคล้องกับ Excel ในทั้งหมด แต่สองเดือนแรกของปี 1900 อย่างไรก็ตามความจำเป็นนี้DayOfWeekวิธีเพราะยุคเดิม 1899/12/30 (หรือนวนิยายที่ 1900-01-00) ได้รับเลือกเช่นว่าวันธรรมดาเป็น mod-7 ของหมายเลขวัน แต่นั่นไม่สามารถใช้ได้กับ 1899-12-30
Adám

4
นี่คือเรื่องราวที่อยู่เบื้องหลัง "ทำไม" เกี่ยวกับวันที่ Excel: โจเอลซอฟแวร์: My First รีวิว ข้อมูล (และความบันเทิง) อ่าน
BradC

คำตอบ:


14

Excel, 3 (+7?)

=A1

ด้วยรูปแบบ

yyy/m/d

พอร์ตบริสุทธิ์


รูปแบบผลลัพธ์อาจแตกต่างกันไปตามสถานที่ของคุณ
Adám

2
ใช้ได้กับ Excel สำหรับ Windows เท่านั้น Excel สำหรับ Mac มีระบบตัวเลขที่เริ่มต้นด้วยวันที่ในปี 1904 ไม่ใช่ 1900 มันจะไม่รายงานวันที่สำหรับปีใด ๆ ในปี 1900 ซึ่งเป็นส่วนหนึ่งของกรณีทดสอบ คุณอาจต้องการระบุว่านี่คือ Excel สำหรับ Windows
Keeta - คืนสถานะโมนิก้า

1
@Keeta นี้จะทำงานใน Excel สำหรับ Mac เพียงยกเลิกการเลือก "ใช้ระบบวัน 1904" ในการตั้งค่า
BradC

1
@BradC แม้ว่าจะเป็นความจริงการเปลี่ยนแปลงใด ๆ ในการกำหนดค่าเริ่มต้นของโปรแกรมนั้นดีมาก แต่ต้องรวมอยู่ในคำตอบ ฉันแสดงความคิดเห็นนี้เป็นจุดเพื่อปรับปรุงคำตอบ ฉันจะบอกว่าเปลี่ยนชื่อเป็น Excel สำหรับ Windows เพิ่ม caveat หรือเปลี่ยนเป็น OpenOffice Calc (หรือคล้ายกันเนื่องจากพวกเขาตั้งใจรวมข้อบกพร่องด้วย) codegolf.meta.stackexchange.com/questions/10037/ …
Keeta - คืนสถานะโมนิก้า

6

k (kdb + 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 นั้นเป็นภาษาที่แตกต่างกันโดยสิ้นเชิง
58

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 ขอบคุณที่NGN


หมายเหตุ: ฉันค่อนข้างแน่ใจว่านี่จะกลายเป็นแลมบ์ดาอีกต่อไปเนื่องจากรูปแบบของผลลัพธ์ไม่ควรเปลี่ยนแปลง
Erik the 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&&'')

ลองออนไลน์!


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

@tsh นั่นดีกว่ามากแน่นอน ขอบคุณ (นอกจากนี้ฉันสงสัยว่าวิธีการนี้จะสามารถเล่นกอล์ฟได้หรือไม่)
Arnauld

ฉันเพียงแค่หาเป็นเช่นเดียวกับnew Date(0,0,1) new Date(1900,0,1)ดังนั้นลบ190บันทึก 3 ไบต์ และ ...
TSH

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



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 ไบต์โดยแทนที่ตัวดำเนินการ OR (||) ด้วยตัวดำเนินการแบบไบนารีหรือ (|)



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

การขึ้นบรรทัดใหม่มีไว้เพื่อให้สามารถอ่านได้เท่านั้น

การป้อนข้อมูลจะได้รับการผ่านทางที่มีอยู่ก่อนตารางฉันมีเขตจำนวนเต็มn , ตามมาตรฐาน 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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.