复制Excel';Julia中日期的表示

复制Excel';Julia中日期的表示,julia,Julia,在Julia中,我需要以与Microsoft Excel相同的方式将数字转换为日期时间 在Excel中,今天2019年9月23日用43731表示,今天下午6点用43731.75表示。我可以忽略一个事实,因为我所有的数据都安全地超出了这一点。毫秒精度就足够了 下面的代码似乎有效,但有更好的方法吗 function exceldatetodate(exceldate::Integer) Dates.Date(1899, 12, 30) + Dates.Day(exceldate) end f

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

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

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

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

您可以重载
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) 
非常重要的一点是,excel将所有数字视为浮点64,而在Julia中,日期是完全不同的类型。在我看来,如果你想让某个特定范围的数字表现得像一个日期,那么最好构造一个反映该行为的类型。 excel日期的一个重要特征是,您可以像数字一样对日期进行操作,但该操作的结果不会格式化为日期。这是Excel决定使用浮点64表示日期的结果。 定义的类型比数字有更多的限制,如果您想将日期作为数字使用,您可以先将
ExcelDate
转换为数字,但只使用julia
Date
类型更有意义,它有更好、更多的方法来处理日期。

离题,但日期是编程中一个尚未解决的问题,所有编程语言的标准都不同。

您是否检查了
XLSX.jl
如何处理它()?我不知道有没有更好的办法。但是如果还没有,这将是添加到
XLSX.jl
的好东西。我会等待一个更好的答案,但如果没有,你应该在那里打开一个问题。这是一个有趣的建议,重载
convert
感觉非常“Julian”,这很好。不过,我认为重载
+
是没有意义的(对于类型
Date
,没有仔细定义)。重载
-
可能不会返回另一个
ExcelDate
,就像减去两个
Date
s会返回一个
期间而不是
日期。是的,在excel中,“行为”是将两个日期的操作格式化为一个数字。我会改正的that@PhilipSwannell请注意,
+(::日期,::日期)
未定义,但
+(::日期,::时间)
未定义。就个人而言,我并不真正喜欢第二种方法——我认为构造函数
DateTime(::Date,::Time)
(也定义了它)是足够的和有意义的。可能值得强调的是,这个答案适用于任何使用
Float64
表示
DateTime
的语言,只要您适当调整纪元日期。例如,Excel使用1899-12-31,Matlab使用0-0-0(但在其他方面都是相同的)。
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