2009-04-07 6 views

Trả lời

53

Trường hợp 39938 là số ngày kể từ ngày 1/1/1900?

Trong trường hợp đó, sử dụng chức năng này (C#):

public static DateTime FromExcelSerialDate(int SerialDate) 
{ 
    if (SerialDate > 59) SerialDate -= 1; //Excel/Lotus 2/29/1900 bug 
    return new DateTime(1899, 12, 31).AddDays(SerialDate); 
} 

VB:

Public Shared Function FromExcelSerialDate(ByVal SerialDate As Integer) As DateTime 
    If SerialDate > 59 Then SerialDate -= 1 ''// Excel/Lotus 2/29/1900 bug 
    Return New DateTime(1899, 12, 31).AddDays(SerialDate) 
End Function 

[Cập nhật]:
Hmm ... Một thử nghiệm nhanh của cho thấy nó thực sự là hai ngày nghỉ. Không chắc chắn sự khác biệt là ở đâu.

OK: sự cố đã được khắc phục ngay bây giờ. Xem nhận xét để biết chi tiết. Đặc biệt, hãy xem đề xuất sử dụng DateTime.FromOADate() để thay thế.

+1

Tôi biết 1 ngày là cho Lotus có một lỗi về ngày 29/2/1900, nó có nó như một ngày không tồn tại. Tôi không biết ngày hôm kia là gì. –

+0

Ngày VBA (Excel) bắt đầu lúc 12/30/1899 –

+0

Nó hoạt động nếu bạn trừ 2, nhưng nó không thành công cho các ngày nối tiếp ít nhất là dưới 60 (02/29/1900) và ngày lén thứ hai ở đó. –

1
void ExcelSerialDateToDMY(int nSerialDate, int &nDay, 
          int &nMonth, int &nYear) 
{ 
    // Excel/Lotus 123 have a bug with 29-02-1900. 1900 is not a 
    // leap year, but Excel/Lotus 123 think it is... 
    if (nSerialDate == 60) 
    { 
     nDay = 29; 
     nMonth = 2; 
     nYear = 1900; 

     return; 
    } 
    else if (nSerialDate < 60) 
    { 
     // Because of the 29-02-1900 bug, any serial date 
     // under 60 is one off... Compensate. 
     nSerialDate++; 
    } 

    // Modified Julian to DMY calculation with an addition of 2415019 
    int l = nSerialDate + 68569 + 2415019; 
    int n = int((4 * l)/146097); 
      l = l - int((146097 * n + 3)/4); 
    int i = int((4000 * (l + 1))/1461001); 
     l = l - int((1461 * i)/4) + 31; 
    int j = int((80 * l)/2447); 
    nDay = l - int((2447 * j)/80); 
     l = int(j/11); 
     nMonth = j + 2 - (12 * l); 
    nYear = 100 * (n - 49) + i + l; 
} 

Cut và Paste nhân tài elses ai đó ...

Ian Brown

133

tôi thấy nó đơn giản hơn sử dụng FromOADate method, ví dụ:

DateTime dt = DateTime.FromOADate(39938); 

Sử dụng mã này dt là "05/05/2009".

+4

+1 Điều này có vẻ thanh lịch hơn nhiều so với các câu trả lời khác ... –

+2

Điều này cũng xử lý các ngày có giá trị thời gian (dấu phẩy động trong định dạng dữ liệu cơ bản), mà giải pháp được chấp nhận thì không. –

+0

@nullptr Tuy nhiên, nó có độ chính xác chỉ 1 mili giây. Bạn có thể có được độ chính xác cao hơn nhiều nếu bạn quan tâm. Xem [câu trả lời của tôi ở nơi khác] (http://stackoverflow.com/a/13922172/1336654). –

1

Đối với 39.938 làm điều này: 39938 * 864000000000 + 599264352000000000

864000000000 đại diện cho số của bọ ve trong một ngày 599264352000000000 đại diện cho số tick từ năm 0001 đến năm 1900