TZDateTimes at same instant and location from different isolates are not equal
jamesncl opened this issue · 0 comments
Comparing two identical TZDateTimes created in different isolates fails, because Location
uses identity not equality for ==
. For example:
final rootIsolateToken = RootIsolateToken.instance!;
TZDateTime fromRootIsolateA = TZDateTime(getLocation('America/Detroit'), 2023);
TZDateTime fromRootIsolateB = TZDateTime(getLocation('America/Detroit'), 2023);
TZDateTime fromComputeIsolate = await Isolate.run<TZDateTime>(() {
BackgroundIsolateBinaryMessenger.ensureInitialized(rootIsolateToken);
initializeTimeZones();
return TZDateTime(getLocation('America/Detroit'), 2023);
});
print("fromRootIsolateA == fromRootIsolateB ${fromRootIsolateA == fromRootIsolateB}");
print("fromRootIsolateA == fromComputeIsolate ${fromRootIsolateA == fromComputeIsolate}");
Actual results:
I/flutter (24040): fromRootIsolateA == fromRootIsolateB true
I/flutter (24040): fromRootIsolateA == fromComputeIsolate false
I would expect both tests to return true, as per the documentation for the ==
operator on TZDateTime
:
/// Returns true if [other] is a [TZDateTime] at the same moment and in the
/// same [Location].
/// ...
@override
bool operator ==(Object other) {
return identical(this, other) ||
other is TZDateTime &&
_native.isAtSameMomentAs(other._native) &&
location == other.location;
}
I think this is failing when the TZDateTime is created in a different isolate because Location
does not override ==
so falls back on an identity check, which fails because it comes from a different instance of the location which was created inside the second isolate.
I suggest that Location
should implement ==
and return true if the location names are the same?
Minimal reproducible example
import 'dart:isolate';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:timezone/data/latest.dart';
import 'package:timezone/timezone.dart';
void main() {
initializeTimeZones();
runApp(const MaterialApp(
home: Example(),
));
}
class Example extends StatefulWidget {
const Example();
@override
State<Example> createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
@override
void initState() {
_test();
super.initState();
}
Future<void> _test() async {
final rootIsolateToken = RootIsolateToken.instance!;
TZDateTime fromRootIsolateA = TZDateTime(getLocation('America/Detroit'), 2023);
TZDateTime fromRootIsolateB = TZDateTime(getLocation('America/Detroit'), 2023);
TZDateTime fromComputeIsolate = await Isolate.run<TZDateTime>(() {
BackgroundIsolateBinaryMessenger.ensureInitialized(rootIsolateToken);
initializeTimeZones();
return TZDateTime(getLocation('America/Detroit'), 2023);
});
print("fromRootIsolateA == fromRootIsolateB ${fromRootIsolateA == fromRootIsolateB}");
print("fromRootIsolateA == fromComputeIsolate ${fromRootIsolateA == fromComputeIsolate}");
}
@override
Widget build(BuildContext context) {
return Container();
}
}