Skip to content

Read zoned datetimes as ZonedDateTime, through a TimeZones.jl extension - #255

Open
Thenewmanator15 wants to merge 2 commits into
JuliaIO:masterfrom
Thenewmanator15:timezones
Open

Thenewmanator15 wants to merge 2 commits into
JuliaIO:masterfrom
Thenewmanator15:timezones

Conversation

@Thenewmanator15

Copy link
Copy Markdown

Builds on #253 (its commit is included here; the new commit is "Read zoned datetimes as ZonedDateTime…").

MATLAB stores a datetime that has a time zone as its UTC instant plus the zone's name. MAT.jl drops the zone with a warning (no timezone conversion yet … ignored), leaving the UTC instant as a DateTime. This reads it as a ZonedDateTime in its own zone when TimeZones.jl is loaded, through a package extension, so MAT.jl gains no required dependency:

using MAT, TimeZones
matread("timezone.mat")["dt_london_summer"]   # 2022-07-20T12:00:00+01:00, Europe/London
  • IANA zones (Europe/London, America/New_York, across daylight saving), UTC, and fixed offsets such as +05:30 — TimeZone() parses all three forms MATLAB writes;
  • without TimeZones.jl, and on Julia < 1.9 (no extensions), the result is unchanged — the UTC instant as a DateTime — with a warning that says so and names the package;
  • a zone TimeZones.jl does not recognise falls back to the UTC instant, with a warning;
  • UTCLeapSeconds counts leap seconds, which neither type can represent: it was returned as a DateTime 26 s off (2016-12-31T23:59:60 read as 2017-01-01T00:00:26) and is now left as the MatlabOpaque, with a warning;
  • timetables: zoned row times follow the same rules, and a regular timetable with a zoned start now works (the start may be any Dates.AbstractDateTime).

I checked the storage against MATLAB R2025a in both formats: for every zone above the stored value is the UTC instant (e.g. 12:00 BST is stored as 11:00 UTC; 12:00 +05:30 as 06:30), and an unzoned datetime stores its wall-clock time.

Tests, and the same request as #253. test/timezone_gen.m writes test/v7/timezone.mat and test/v7.3/timezone.mat. read.jl checks the file before TimeZones.jl is loaded (UTC instants); the new test/timezones.jl, run last in runtests.jl, loads TimeZones.jl and checks ZonedDateTimes (Julia 1.9+). I can't contribute the .mat files, so they are not included — could someone with MATLAB run the script and commit its two files? Until then these testsets skip. Against the files the script writes: the full suite passes (685) on Julia 1.13 and on 1.9; without them, 581 pass, 6 skipped. TimeZones.jl is a weak dependency and a test dependency (compat "1"; 1.22 supports Julia 1.6).

A NaT in a zoned array is handled by #254; the extension maps missing through.

🤖 Generated with Claude Code

A timetable was returned as a MatlabOpaque, its parts decoded but not assembled.
It now becomes a table (MatlabTable by default, or the `table` type) whose first
column holds the row times, named after the row dimension ("Time" unless renamed),
followed by the variables.

Row times are stored one per row (datetime or duration, already converted to
DateTime or Millisecond), or, for a regular timetable, as a start time and a sample
rate or time step; those are generated. A timetable stepped in calendar units has
no fixed rate and is left as the MatlabOpaque, with a warning. `table=Nothing`
keeps the raw object, as for tables.

test/timetable_gen.m writes test/v7 and test/v7.3/timetable.mat: datetime and
duration row times, sample rate, time step from a datetime start, an empty
timetable, a two-column variable, a renamed row dimension, calendar months. The
.mat files are not included; the timetable tests are skipped until they are
generated in MATLAB and committed.
MATLAB stores a datetime with a time zone as its UTC instant plus the zone's name.
The zone was dropped with a warning, leaving the UTC instant as a DateTime. With
TimeZones.jl loaded (Julia 1.9+, package extension MATTimeZonesExt), it is now a
ZonedDateTime in its zone: an IANA name, "UTC", or a fixed offset such as "+05:30".
Without TimeZones.jl, and on older Julia, the result is unchanged (the UTC instant),
with a warning that says so and names the package. A zone TimeZones.jl does not
recognise falls back to the UTC instant, with a warning.

"UTCLeapSeconds" counts leap seconds, which neither DateTime nor ZonedDateTime can
represent; it was returned as a DateTime 26 s off (2016-12-31T23:59:60 read as
2017-01-01T00:00:26) and is now left as the MatlabOpaque, with a warning.

A regular timetable with a zoned start now works too (the start may be any
Dates.AbstractDateTime).

test/timezone_gen.m writes test/v7 and test/v7.3/timezone.mat (Europe/London in summer
and winter, UTC, +05:30, America/New_York across DST, UTCLeapSeconds, a timetable with
zoned row times and a regular one with a zoned start). read.jl checks the file before
TimeZones.jl is loaded, the new test/timezones.jl (run last) after. The .mat files are
not included; both testsets skip until they are generated in MATLAB and committed.
TimeZones.jl is a weak dependency and a test dependency.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant