在Julia中复制Excel的日期表示形式

时间:2019-09-23 13:15:12

标签: julia

在Julia中,我需要以与Microsoft Excel相同的方式将数字转换为DateTime

在Excel中,今天的日期为2019年9月23日,表示为43731,今天下午6点为43731.75。我可以忽略Excel incorrectly assumes that 1900 is a leap year的事实,因为我的所有数据都安全地超出了这一点。毫秒精度就足够了。

下面的代码似乎有效,但是有更好的方法吗?

function exceldatetodate(exceldate::Integer)
    Dates.Date(1899, 12, 30) + Dates.Day(exceldate)
end
function exceldatetodate(exceldate::Real)
    t,d = modf(exceldate)
    Dates.Date(1899, 12, 30) + Dates.Day(d) + Dates.Millisecond(floor(t * 86400000))
end

julia> exceldatetodate(43731)
2019-09-23

julia> exceldatetodate(43731.75)
2019-09-23T18:00:00

1 个答案:

答案 0 :(得分:1)

您可以重载convert方法,并创建一个保存该值的自定义类型。

using Dates

struct ExcelDate{T<:Real}  
   val::T
end

function exceldatetodate(exceldate::Integer)
   Dates.DateTime(1899, 12, 30) + Dates.Day(exceldate)
end
function exceldatetodate(exceldate::Real)
   t,d = modf(exceldate)
   return Dates.DateTime(1899, 12, 30) + Dates.Day(d) + Dates.Millisecond((floor(t * 86400000)))
end

function exceldatetodate(exceldate::ExcelDate)
   exceldatetodate(exceldate.val)
end

function exceldatetodate(exceldate::ExcelDate)
   exceldatetodate(exceldate.val)
end

function toexceldate(date::Date)
   datetime = Dates.value(DateTime(date) - Dates.DateTime(1899, 12, 30))
   datetime = round(datetime/86400000,digits = 3)
   return ExcelDate(datetime)
end

function toexceldate(date::DateTime)
   datetime = Dates.value(date - Dates.DateTime(1899, 12, 30))
   datetime = round(datetime/86400000,digits = 3)
   return ExcelDate(datetime)
end


Base.convert(d::Type{Dates.DateTime},n::ExcelDate) = exceldatetodate(n) 
Base.convert(d::Type{Dates.Date},n::ExcelDate) = convert(Date,exceldatetodate(n))
Base.convert(d::Type{T},n::ExcelDate) where T<: Real = convert(d,n.val)
Base.convert(d::Type{ExcelDate},n::Dates.DateTime) = toexceldate(n) 
Base.convert(d::Type{ExcelDate},n::Dates.Date) = toexceldate(n) 

然后,您可以使用以下值:

original_numbers = 40000.01:41000.01 #test numbers
excel_dates = convert.(ExcelDate,original_numbers)
dates = convert.(Date,excel_dates) #just days
datetimes = convert.(DateTime,excel_dates) #days and miliseconds
orig2 = convert.(ExcelDate,datetimes) #this preserves the original number
orig3 = convert.(ExcelDate,dates) #this does not preserve the original number

非常重要的一点是,excel将所有数字都视为float64,在Julia中,日期是一种完全不同的类型。我认为,如果您希望一定范围的数字表现得像Date,则最好构造一个反映该行为的类型。 Excel日期的一个重要特征是您可以像数字一样操作日期,但是该操作的结果未格式化为日期。这是Excel决定使用Float64表示日期的结果。 定义的类型比数字具有更多的限制,如果要将日期作为数字使用,可以先将ExcelDate转换为数字,但是仅使用julia {{1 }}类型,可以使用更多更好的方法来处理日期。
topic琐,但是日期并不是编程问题,所有编程语言的标准都不同。