Add date and time utilities
- [x] Move getTime from System to Internal package and introduce a new package Time with function getTime returning a record, see https://github.com/modelica/ModelicaStandardLibrary/issues/3143#issuecomment-540957856.
- [x] Add leap year utility functions.
- [x] Add date-time to string conversion (using strftime), see https://github.com/modelica/ModelicaSpecification/issues/2245.
- [x] Add string to date-time conversion (using strptime (to be added to C-Sources since not available on all systems)), see https://github.com/modelica/ModelicaSpecification/issues/2245.
Summary by CodeRabbit
-
New Features
- Introduced comprehensive date and time utilities with improved formatting, parsing (including millisecond support), and conversion capabilities.
- Added a conversion tool to assist in upgrading libraries between versions.
- Updated real number rounding for cleaner integer conversion.
-
Improvements
- Enhanced graphical icons for clarity in operator representations.
- Refined documentation and contributor acknowledgments within the library.
-
Tests
- Expanded test suite to validate new time, date, and duration functionalities as well as rounding behavior.
The general idea is good, but:
- I don't like the abbreviations in the record (and as outputs): min, mon, ms, even if consistent with "struct tm". (As far as I understand the names should be singular: second, minute, hour, year.)
- I am unsure if we should have leap-year utilities. The reason is that it leads to people doing their own leap-year-calculations and that can lead to annoying bugs. Having a full set of utilities to avoid the need for that might be a better solution (that includes conversions between date-time and number, and handling of date-time-differences).
I tried to look at the Buildings-library. It uses full names in the records, but unfortunately it contains its own leap-year handling (hopefully correct): https://github.com/lbl-srg/modelica-buildings/blob/master/Buildings/Utilities/Time/CalendarTime.mo
I started with an operator record for TimeType to also allow addition, subtraction etc. That meant, we also would need to consider a TimeDeltaType and conversion to absolute time, which is not straight-forward. Therefore, I rejected this first idea and went for the TimeType record as absolute point in time and without numerical conversion. (String conversion is still to do, but without handling of leap-seconds).
I don't like the abbreviations in the record (and as outputs): min, mon, ms, even if consistent with "struct tm". (As far as I understand the names should be singular: second, minute, hour, year.)
OK, will rename.
I am unsure if we should have leap-year utilities.
Hm, @GallLeo what do you think? @mwetter considers leap years only in range [2020, 2030] which might not be sufficient in a general purpose library.
If you want to consider leap years, daylight savings, etc... You need to work on some absolute unit of s/etc relative from 1970... I think that's the only sane way of dealing with any kind of delta and ambiguity... Just convert between tm and time_t if you want to use that (and run the calculation in external C).
Here is a first (and incomplete) draft for conversion of date/time to string. Not sure if it is good enough ❔ . Any feedback is appreciated.
@HansOlsson @DagBruck @t-sommer @StephanZiegler Yesterday, I noticed by chance that there are Testing.Utilities.Time.{DateTime, Duration} available in Dymola as operator records. This is exactly the way I wanted to go here for MSL, too. I believe these utilities came up as necessary side-product when meaasuring time in Modelica. Now, that I am aware of this library, I am also biased with the further development. My question is, if you could think of contributing or sharing Modelica code for further development as OSS, such that I am sure, no copyright will be violated?
We would be happy to move the operator records from the Testing library to the MSL. @beutlich How shall we proceed? My recommendation would be, that I first push a purely MSL-based version of the operator records to this pull request. Then we can review the code and merge it with your work.
@m-kessler Thank you for the generous offer. I rebased the commits of this PR on master and resolved the merge conficts. This PR branch is now ready to be used. I added you as contributor (with access role = Triage) such that you can directly push to this branch (hopefully).
I already created a TimeType record. This can be now enhanced by using the two different operator records from the Testing package. It would be good if we can use the exsting names of the TimeType record components (which are different than the Testing package.)
The new external function ModelicaTime_strftime is nice and definitely the way to go (using the existing C functions to format time, instead of rewriting it in Modelica). However, currently it has troubles with summertime:
String(DateTime.now()) // = 2020-04-14 15:09:41, should be 2020-04-14 14:09:41
String(DateTime(2020, 4, 1, 0, 0, 0, 0)); // = 2020-04-01 01:00:00, should be 2020-04-01 00:00:00
String(DateTime(2020, 3, 1, 0, 0, 0, 0)); // = 2020-03-01 00:00:00, as expected
There seem to be conflicts in the Duration constructors.
When calling Duration(1), it is not clear if Modelica.Utilities.Time.Duration.'constructor'.fromInput or Modelica.Utilities.Time.Duration.'constructor'.fromSeconds should be used. The specification says in 14.2 that:
there shall not exist any potential call that lead to multiple matches
There seem to be conflicts in the
Durationconstructors.
@maltelenz true. This commit would fix it https://github.com/m-kessler/ModelicaStandardLibrary/commit/e5477009808b5801560402c8652f3c8486e3c6d5 - making fromSeconds the new default constructor. @beutlich shall we merge it?
@beutlich shall we merge it?
Sure, please go ahead. Push directly to this PR branch as you already did.
I'll answer the other issues you observed later.
The new external function ModelicaTime_strftime is nice and definitely the way to go (using the existing C functions to format time, instead of rewriting it in Modelica). However, currently it has troubles with summertime:
String(DateTime.now()) // = 2020-04-14 15:09:41, should be 2020-04-14 14:09:41 String(DateTime(2020, 4, 1, 0, 0, 0, 0)); // = 2020-04-01 01:00:00, should be 2020-04-01 00:00:00 String(DateTime(2020, 3, 1, 0, 0, 0, 0)); // = 2020-03-01 00:00:00, as expected
Confirmed. ba9d075443ccc7a157a188b1182a5f285e9af818 should fix it, but only could test on Windows.
Unfortunately this pull request exposed some shortcomings on operator records in our tool, so I'm not in a good position to do a thorough review. Apart from the issue I mentioned in the previous comment (which is now fixed), all issues I'm seeing so far are issues in the tool, not with the changes in the pull request.
Oh, and ModelicaTest.Utilities.DateTime fails due to dates before 1970 (for 1901, 1910, 1912). The first failure seems to be for:
ref_dt:= DateTime(1901, 12, 13, 20, 45, 53, 0);
ref_r := -2147483647;
act_dt:= DateTime(ref_r);
act_r := DateTime.epoch(ref_dt);
It's slightly complicated to investigate this in Dymola since we normally pretty-print operator records and thus even Modelica.Utilities.Time.DateTime(1901,12,13,20,45,53,0) will fail.
Either we have to work around that - or just document it and don't test it.
It should -2d -5min, right?
Correct. Fixed by ca583ce273096856d65c7964b216d33c0bb375eb.
Here an operator record is extended, but the specification says in the beginning of Chapter 14:
It is not legal to extend from an operator record, except as a short class definition
This seems like invalid Modelica?
Hm, I only looked at section 7.1.3 where it reads:
The specialized classes [...] operator record [...] can only be derived from their own kind [...] and from class.
We could make it a class then.
I usually declare icon-only-classes as class, as everyone can inherit from that. Should also work here, right? The pedantic check in Dymola 2021 does not complain.
I usually declare icon-only-classes as class, as everyone can inherit from that. Should also work here, right? The pedantic check in Dymola 2021 does not complain.
The checking in development versions of SystemModeler agrees class is fine.
We could make it a class then.
Also works in SimulationX without warnings.
- I spent many hours to work around the 1970 restriction that is in current code. The solution is not yet ready and not that nice. My proposal would be to accept the current implementation and refine once we got the requirement to support dates before 1970.
- Currently, ConvertModelica_from_3.2.3_to_4.0.0.mos is used for the conversion. This needs to be changed of course as MSL v4.00 is already released.
- The PR is more than 7 months old and has not seen reviews from @sjoelund (as library officer for C sources) or @GallLeo (who raised the idea initially). Would be very good to see some feedback from you, too. Thanks.
@GallLeo @DagBruck @sjoelund @HansOlsson Your feedback will be appreciated.