Repository: JuliaLang/julia
File: stdlib/Dates/src/conversions.jl (Julia)

Code before:

Convert a `Date` to a `DateTime`. The hour, minute, second, and millisecond parts of
the new `DateTime` are assumed to be zero.
"""
DateTime(dt::TimeType) = convert(DateTime, dt)

"""
    Time(dt::DateTime) -> Time

Convert a `DateTime` to a `Time`. The hour, minute, second, and millisecond parts of
the `DateTime` are used to create the new `Time`. Microsecond and nanoseconds are zero by default.
"""
Time(dt::DateTime) = convert(Time, dt)

Base.convert(::Type{DateTime}, dt::Date) = DateTime(UTM(value(dt) * 86400000))
Base.convert(::Type{Date}, dt::DateTime) = Date(UTD(days(dt)))
Base.convert(::Type{Time}, dt::DateTime) = Time(Nanosecond((value(dt) % 86400000) * 1000000))

Base.convert(::Type{DateTime},x::Millisecond)  = DateTime(Dates.UTInstant(x))  # Converts Rata Die milliseconds to a DateTime
Base.convert(::Type{Millisecond},dt::DateTime) = Millisecond(value(dt))        # Converts DateTime to Rata Die milliseconds
Base.convert(::Type{Date},x::Day)  = Date(Dates.UTInstant(x))  # Converts Rata Die days to a Date
Base.convert(::Type{Day},dt::Date) = Day(value(dt))            # Converts Date to Rata Die days

### External Conversions
const UNIXEPOCH = value(DateTime(1970)) #Rata Die milliseconds for 1970-01-01T00:00:00
const LOCALEPOCH = value(DateTime(Libc.TmStruct(0))) #Rata Die for local time at UTC 1970-01-01T00:00:00

"""
    unix2datetime(x::Real; local_time::Bool=false) -> DateTime

Take the number of seconds since unix epoch `1970-01-01T00:00:00` and convert to the
corresponding `DateTime`. If `local_time` is `true`, then the output is in the local
time zone, otherwise it is in UTC/GMT.
"""
function unix2datetime(x::Real; local_time::Bool=false)
    # Rounding should match `now` below
    rata = (local_time ? LOCALEPOCH : UNIXEPOCH) + trunc(Int64, Int64(1000) * x)
    return DateTime(UTM(rata))
end

"""
    datetime2unix(dt::DateTime; local_time::Bool=false) -> Float64

Take the given `DateTime` and return the number of seconds
since the unix epoch `1970-01-01T00:00:00` as a [`Float64`](@ref).

If `local_time` is `true`, then the number of seconds since the local epoch
corresponding to unix epoch `1970-01-01T00:00:00` is returned.
"""
function datetime2unix(dt::DateTime; local_time::Bool=false)
    return (value(dt) - (local_time ? LOCALEPOCH : UNIXEPOCH)) / 1000.0

Review comment (suggestion):
Making this a constant doesn't seem right — what if the local time changes?  (Moreover, won't precompilation then set `LOCALEPOCH` to wherever Julia was built?)

Code after:

Convert a `Date` to a `DateTime`. The hour, minute, second, and millisecond parts of
the new `DateTime` are assumed to be zero.
"""
DateTime(dt::TimeType) = convert(DateTime, dt)

"""
    Time(dt::DateTime)

Convert a `DateTime` to a `Time`. The hour, minute, second, and millisecond parts of
the `DateTime` are used to create the new `Time`. Microsecond and nanoseconds are zero by default.
"""
Time(dt::DateTime) = convert(Time, dt)

Base.convert(::Type{DateTime}, dt::Date) = DateTime(UTM(value(dt) * 86400000))
Base.convert(::Type{Date}, dt::DateTime) = Date(UTD(days(dt)))
Base.convert(::Type{Time}, dt::DateTime) = Time(Nanosecond((value(dt) % 86400000) * 1000000))

Base.convert(::Type{DateTime},x::Millisecond)  = DateTime(Dates.UTInstant(x))  # Converts Rata Die milliseconds to a DateTime
Base.convert(::Type{Millisecond},dt::DateTime) = Millisecond(value(dt))        # Converts DateTime to Rata Die milliseconds
Base.convert(::Type{Date},x::Day)  = Date(Dates.UTInstant(x))  # Converts Rata Die days to a Date
Base.convert(::Type{Day},dt::Date) = Day(value(dt))            # Converts Date to Rata Die days

### External Conversions
const UNIXEPOCH = value(DateTime(1970)) #Rata Die milliseconds for 1970-01-01T00:00:00

"""
    unix2datetime(x::Real; localtime::Bool=false)::DateTime

Take the number of seconds since unix epoch `1970-01-01T00:00:00` (UTC) and convert to the
corresponding `DateTime`. If `localtime` is `true`, then the output is in the host
system's local time zone, otherwise it is in UTC/GMT.
"""
function unix2datetime(x::Real; localtime::Bool=false)
    # Rounding should match `now` below
    ms = trunc(Int64, Int64(1000) * x)
    if localtime
        s, ms = divrem(ms, 1000)
        return DateTime(Libc.TmStruct(s)) + Millisecond(ms)
    else
        rata = UNIXEPOCH + ms
        return DateTime(UTM(rata))
    end
end

"""
    datetime2unix(dt::DateTime)::Float64

Take the given `DateTime` and return the number of seconds
since the unix epoch `1970-01-01T00:00:00` as a [`Float64`](@ref).
"""