sdk
sdk copied to clipboard
Microseconds are lost when creating DateTime.parse or DateTime.fromMicrosecondsSinceEpoch
As mentioned in the title and as shown in the example below:
main() {
final datetimeParsed = DateTime.parse('2021-02-05T22:37:12.933232+00:00');
final datetimeMS = DateTime.fromMicrosecondsSinceEpoch(1612564632933232);
print(datetimeParsed.toIso8601String()); // prints 2021-02-05T22:37:12.933Z
print(datetimeMS.toUtc().toIso8601String()); // prints 2021-02-05T22:37:12.933Z
print(datetimeParsed.microsecondsSinceEpoch); // prints 1612564632933000
print(datetimeMS.microsecondsSinceEpoch); // prints 1612564632933000
}
Dart SDK on 2.10.4 (example on DartPad)
The web Date
object doesn't support microseconds. It's implemented using the JavaScript Date
object which only supports millisecond precision. So, working as well as possible.
Since Flutter Web is probably going mainstream very soon, it would be helpful to devs if the Flutter and Dart teams could collaborate and create an overview list of APIs with different behavior in VM and WEB builds. Since more and many devs new to Dart, will probably start to build cross platforms apps, more devs are likely to stumble on such issues from time to time. It would be good to preempt it a bit at least, and provide a consolidated source for already known such potential pitfalls.
Perhaps there already is such an overview in the Dart lang docs site? In that case it would be good to promote it better and reference it from the Flutter site as well.
Yes this particular case is of course documented at least in the doc comments for the getter in question, so it is in API docs, IDE tooling and when you drill into the source: https://api.dart.dev/stable/2.10.5/dart-core/DateTime/microsecondsSinceEpoch.html
But can be easy to miss, especially if you just build something that was originally built just for Flutter VM apps to run on Flutter Web as well.
On that note, would it be possible to create a lint rule that could be enabled to detect these kind of issues, and it would warn you when you might have an issue due to differences in VM and WEB implementations?
Assigning to lib to improve the doc on this API to at least say what @lrhn says above. As written, it looks like it could return anything. The implementation uses millisecond precision and multiplies by 1000 here:
https://github.com/dart-lang/sdk/blob/30ba97bb1b0717f70545cc98050be823a25757de/sdk/lib/_internal/js_runtime/lib/core_patch.dart#L333
A general VM vs Web lint would be difficult ( any API uses int
might behave different, but it's usually not likely to matter ). We might consider flagging certain APIs more likely to be misused though. ( @pq @rakudrama @ferhatb ?)
A lint rule that can catch and warn about certain APIs, that you might stumble on in Flutter Web and VM cross platform dev, would already imo be very useful and helpful, definitely better than nothing and relaying on memory to remember them.
Would you like a separate submission of a suggestion/issue for such a lint rule? Just to have it as its own actionable topic instead of the comment I just threw up in the air here to see if it might stick... 😃
@rydmike - please do - you can file it here and reference this issue:
https://github.com/dart-lang/linter/issues
thanks!
Yes, thank you @rydmike. Issues would be greatly appreciated!
Added: https://github.com/dart-lang/linter/issues/2447
I think I currently have the same issue, here's a quick demo on dartpad.
@Roms1383
By the way, this is only an issue for dart in the Web (e.g. DartPad or Flutter Web).
Running your script on other platforms than web would produce expected results.
This was ran on macOS:
equivalent in Rust: 1970-01-01 00:02:30.151152 UTC (ms 150151152)
ms: 150151152
date: 1970-01-01 00:02:30.151152Z
ms since epoch: 150151152
----------------
equivalent in Rust: 1970-01-02 17:42:31.152153 UTC (ms 150151152153)
ms: 150151152153
date: 1970-01-02 17:42:31.152153Z
ms since epoch: 150151152153
----------------
equivalent in Rust: 1974-10-04 20:39:12.153154 UTC (ms 150151152153154)
ms: 150151152153154
ms multiplied by 1000: 150151152153154000
date: 1974-10-04 20:39:12.153154Z
date with multiplied ms: 6728-02-07 13:22:33.154Z
ms since epoch: 150151152153154
ms since epoch date with multiplied ms: 150151152153154000
@osaxma Oh nice, thanks ! My bad I thought DartPad produced a result equivalent to e.g. desktop, this is actually a good news for me too!
I think this problem is very serious.
for example Parsing 1999-12-31T23:59:59.999500 on the web It will be rounded off to 2000-1-1-T0:0:0.000.
I don't think there is any particular problem when generating with DateTime.now(). However, if the server side handles date and time down to micro seconds or nano seconds, if these are rounded off by the client, the timestamp of the data will be different between the server and the client. (If this was truncated, it might still be usable...)
I don't think it would be acceptable to have these differences between platforms.
I think this problem will cause a very troublesome problem.
There are several ideas to work around this problem, but I think these ideas are pretty stupid.
- Truncate micro seconds system-wide when providing system for the web
- Prepare your own class that can handle up to micro seconds instead of DateTime
I understand that Dart is a language developed to replace JS. I don't think we should be held back by old technology.
What do you think, guys?
Fixed via https://github.com/dart-lang/sdk/commit/20316bcc5bf1a801c0344eb01d90587a1c1f97f0, https://github.com/dart-lang/sdk/commit/b42bd24b782c6cc31672dc3e994a4faf53ce300d