JuliaTime / TimeZones.jl

IANA time zone database access for the Julia programming language
Other
85 stars 54 forks source link

`ZonedDateTime` can't parse it's own output #83

Open Keno opened 7 years ago

Keno commented 7 years ago

This seems unfortunate:

julia> ZonedDateTime(DateTime(2014,1,1), TimeZone("Europe/Warsaw"))
2014-01-01T00:00:00+01:00

julia> ZonedDateTime("2014-01-01T00:00:00+01:00")
ERROR: ArgumentError: Unable to parse date time. Expected directive Delim(.) at char 20
omus commented 7 years ago

It's definite possible to get it to parse the output.

Unfortunately the output only shows the UTC offset for that specific timestamp which means that parsing it will result a loss of information since we would have to parse the string as a FixedTimeZone("+01:00") rather than TimeZone("Europe/Warsaw"). Maybe I should change the default show to be 2014-01-01T00:00:00 Europe/Warsaw.

Keno commented 7 years ago

The output is actually fine with me. My concern is more the parsing. In Base, we hack the ISODateTime parsing to make the .sss optional, but here we don't. Of course the ISO8601 complete representation doesn't include milliseconds at all.

Keno commented 7 years ago

Although it does say

If necessary for a particular application a decimal fraction of hour, minute or second may be included. If a
decimal fraction is included, lower order time elements (if any) shall be omitted and the decimal fraction shall
be divided from the integer part by the decimal sign specified in ISO 31-0, i.e. the comma [,] or full stop [.]. Of
these, the comma is the preferred sign. If the magnitude of the number is less than unity, the decimal sign
shall be preceded by two zeros in accordance with 3.6. 

so maybe in parsing of various components, we should always allow . and , and treat it as decimal separators?

Keno commented 7 years ago

cc also @quinnj

quinnj commented 7 years ago

I'm following along :)

omus commented 7 years ago

The DateFormat specification could use a re-think. It would be nice if when parsing you could state a section was optional. Something like df"yyyy-mm-dd HH:MM:SS(.sss)zzz". Additionally, I dislike that I'm using zzz for reading in +01:00. It would be better to break up that into multiple components like sign, hour, minutes. Something like ±{zone-hour}:{zone-minute} (I'm not sure what letters would be good here...)

Keno commented 7 years ago

I don't think I actually mind zzz that much, because for UTC, the standard specifies Z, which I'd like to match as well.

Keno commented 7 years ago

As for letters, there's always hᶻ of course.

omus commented 7 years ago

Mostly the optional specifiers for parsing would be useful.

omus commented 6 years ago

@rofinn just ran into this one:

julia> ZonedDateTime("2017-01-28T11:59:59+00:00")
ERROR: ArgumentError: Unable to parse date time. Expected directive Delim(.) at char 20
yakir12 commented 6 years ago

I ran into the same problem as well (I ended up adding a silly Millisecond(1) to everything). But this touches the problem that the string representation of this type is not complete (the location of the time zone is missing). How to save zoned date & time is an issue a lot of people get hit by. It would be great if there was a function that took an instance of ZonedDateTime and output all the necessary parts (local time and location?) as strings so it could get saved correctly.

omus commented 6 years ago

Something related would be to make sure that repr for ZonedDateTime print as parsable Julia code ZonedDateTime(2018, 11, 2, 12, 55, tz"America/Winnipeg") and have print display the current compact representation 2018-11-02T12:55:00-05:00.

omus commented 6 years ago

Related: https://github.com/JuliaLang/julia/issues/29909

yakir12 commented 6 years ago

Excuse my ignorance, but is 2018-11-02T12:55:00-05:00 really enough for correctly saving a zoned date & time...? I thought you'd need the location as well, and not "just" the UTC-offset, à la this example.

iamed2 commented 6 years ago

You correctly save the instant in time but you lose information for, e.g., date math.

galenlynch commented 5 years ago

This is still a problem:

julia> ZonedDateTime("2017-04-14 10:58:40-04", dateformat"YYYY-mm-dd HH:MM:SS.ssszz")
ERROR: ArgumentError: Unable to parse string "2017-04-14 10:58:40-04" using format dateformat"YYYY-mm-dd HH:MM:SS.ssszz". Unable to parse date time. Expected directive Delim(.) at char 20
Stacktrace:
 [1] macro expansion at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.1/Dates/src/parse.jl:104 [inlined]
 [2] tryparsenext_core(::String, ::Int64, ::Int64, ::DateFormat{Symbol("YYYY-mm-dd HH:MM:SS.ssszz"),Tuple{Dates.DatePart{'Y'},Dates.Delim{Char,1},Dates.DatePart{'m'},Dates.Delim{Char,1},Dates.DatePart{'d'},Dates.Delim{Char,1},Dates.DatePart{'H'},Dates.Delim{Char,1},Dates.DatePart{'M'},Dates.Delim{Char,1},Dates.DatePart{'S'},Dates.Delim{Char,1},Dates.DatePart{'s'},Dates.DatePart{'z'}}}, ::Bool) at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.1/Dates/src/parse.jl:40
 [3] macro expansion at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.1/Dates/src/parse.jl:150 [inlined]
 [4] tryparsenext_internal at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.1/Dates/src/parse.jl:127 [inlined]
 [5] parse at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.1/Dates/src/parse.jl:282 [inlined]
 [6] ZonedDateTime(::String, ::DateFormat{Symbol("YYYY-mm-dd HH:MM:SS.ssszz"),Tuple{Dates.DatePart{'Y'},Dates.Delim{Char,1},Dates.DatePart{'m'},Dates.Delim{Char,1},Dates.DatePart{'d'},Dates.Delim{Char,1},Dates.DatePart{'H'},Dates.Delim{Char,1},Dates.DatePart{'M'},Dates.Delim{Char,1},Dates.DatePart{'S'},Dates.Delim{Char,1},Dates.DatePart{'s'},Dates.DatePart{'z'}}}) at /home/glynch/.julia/packages/TimeZones/Z0kpK/src/parse.jl:85
 [7] top-level scope at none:0
omus commented 5 years ago

This is still a problem

Your particular example will always be an issue. If you are passing in a DateFormat explicitly where you are trying to parse milliseconds the parsing will fail.

As a stop gap measure I'm planning on supporting:

parse(ZonedDateTime, str)

which would handle both dateformat"YYYY-mm-dd HH:MM:SSzzz" and dateformat"YYYY-mm-dd HH:MM:SS.ssszzz" as a special case.

I'm also doing so research into different date parsing/formatting syntaxes to see what alternatives I can find and introduce into the Dates stdlib.

dehann commented 4 years ago

Hi @omus , we just came across this too:

julia> str = string(ZonedDateTime("2020-08-12T12:00:00.000+00:00"))
"2020-08-12T12:00:00+00:00"

julia> parse(ZonedDateTime, str)
ERROR: ArgumentError: Unable to parse date time. Expected directive Delim(.) at char 20
Stacktrace:
 [1] macro expansion at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.5/Dates/src/parse.jl:104 [inlined]
 [2] tryparsenext_core(::String, ::Int64, ::Int64, ::DateFormat{Symbol("yyyy-mm-ddTHH:MM:SS.ssszzz"),Tuple{Dates.DatePart{'y'},Dates.Delim{Char,1},Dates.DatePart{'m'},Dates.Delim{Char,1},Dates.DatePart{'d'},Dates.Delim{Char,1},Dates.DatePart{'H'},Dates.Delim{Char,1},Dates.DatePart{'M'},Dates.Delim{Char,1},Dates.DatePart{'S'},Dates.Delim{Char,1},Dates.DatePart{'s'},Dates.DatePart{'z'}}}, ::Bool) at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.5/Dates/src/parse.jl:38
 [3] macro expansion at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.5/Dates/src/parse.jl:150 [inlined]
 [4] tryparsenext_internal at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.5/Dates/src/parse.jl:125 [inlined]
 [5] parse(::Type{ZonedDateTime}, ::String, ::DateFormat{Symbol("yyyy-mm-ddTHH:MM:SS.ssszzz"),Tuple{Dates.DatePart{'y'},Dates.Delim{Char,1},Dates.DatePart{'m'},Dates.Delim{Char,1},Dates.DatePart{'d'},Dates.Delim{Char,1},Dates.DatePart{'H'},Dates.Delim{Char,1},Dates.DatePart{'M'},Dates.Delim{Char,1},Dates.DatePart{'S'},Dates.Delim{Char,1},Dates.DatePart{'s'},Dates.DatePart{'z'}}}) at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.5/Dates/src/parse.jl:282
 [6] parse(::Type{ZonedDateTime}, ::String) at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.5/Dates/src/parse.jl:281
 [7] top-level scope at REPL[13]:1

Ref the Time Standard: https://en.wikipedia.org/wiki/ISO_8601

acdupont commented 2 years ago

This seems unfortunate:

julia> ZonedDateTime(DateTime(2014,1,1), TimeZone("Europe/Warsaw"))
2014-01-01T00:00:00+01:00

julia> ZonedDateTime("2014-01-01T00:00:00+01:00")
ERROR: ArgumentError: Unable to parse date time. Expected directive Delim(.) at char 20

Is there plans to fix this? I was going to open an issue as I ran to this exact problem. Shouldn't ZonedDateTime be able to parse an valid ISO 8601 string?

acdupont commented 2 years ago

It's definite possible to get it to parse the output.

Unfortunately the output only shows the UTC offset for that specific timestamp which means that parsing it will result a loss of information since we would have to parse the string as a FixedTimeZone("+01:00") rather than TimeZone("Europe/Warsaw"). Maybe I should change the default show to be 2014-01-01T00:00:00 Europe/Warsaw.

The loss of information did not occur at parse time, it occured when converting the ZonedDateTime to a String

acdupont commented 2 years ago

Also note that while this 2014-01-01T00:00:00+01:00 fails, this 2014-01-01T00:00:00.000+01:00 can be parsed (added .000 milliseconds).