blob: a3273ebe8e7dd8f73b3d56b3f1272ec4e86efe8b [file] [edit]
// Copyright (c) 2014, the timezone project authors. Please see the AUTHORS
// file for details. All rights reserved. Use of this source code is governed
// by a BSD-style license that can be found in the LICENSE file.
import 'dart:collection';
import '../timezone.dart';
import '../tzdata.dart' as tzfile;
const int _maxMillisecondsSinceEpoch = 8640000000000000;
const int _maxSecondsSinceEpoch = 8640000000000;
class FilterReport {
int originalLocationsCount = 0;
int originalTransitionsCount = 0;
int newLocationsCount = 0;
int newTransitionsCount = 0;
}
class FilteredLocationDatabase {
final LocationDatabase db;
final FilterReport report;
FilteredLocationDatabase(this.db, this.report);
}
FilteredLocationDatabase filterTimeZoneData(
LocationDatabase db, {
int dateFrom = TZDateTime.minMillisecondsSinceEpoch,
int dateTo = TZDateTime.maxMillisecondsSinceEpoch,
List<String> locations = const [],
}) {
final report = FilterReport();
final result = LocationDatabase();
final locationsSet = HashSet<String>.from(locations);
report.originalLocationsCount = db.locations.length;
for (final l in db.locations.values) {
if (locationsSet.isNotEmpty && !locationsSet.contains(l.name)) {
continue;
}
final transitionsCount = l.transitionAt.length;
report.originalTransitionsCount += transitionsCount;
final newTransitionAt = <int>[];
final newTransitionZone = <int>[];
if (transitionsCount == 0) {
result.add(Location(l.name, newTransitionAt, newTransitionZone, l.zones));
continue;
}
var i = 0;
while (i < transitionsCount && dateFrom > l.transitionAt[i]) {
i++;
}
if (i < transitionsCount) {
newTransitionAt.add(TZDateTime.minMillisecondsSinceEpoch);
newTransitionZone.add(l.transitionZone[i]);
i++;
report.newTransitionsCount++;
while (i < transitionsCount && l.transitionAt[i] <= dateTo) {
newTransitionAt.add(l.transitionAt[i]);
newTransitionZone.add(l.transitionZone[i]);
i++;
report.newTransitionsCount++;
}
} else {
newTransitionAt.add(TZDateTime.minMillisecondsSinceEpoch);
newTransitionZone.add(l.transitionZone[i - 1]);
}
result.add(Location(l.name, newTransitionAt, newTransitionZone, l.zones));
report.newLocationsCount++;
}
return FilteredLocationDatabase(result, report);
}
/// Convert [tzfile.Location] to [Location]
Location tzfileLocationToNativeLocation(tzfile.Location loc) {
// convert to milliseconds
final transitionAt = loc.transitionAt
.map(
(i) => (i < -_maxSecondsSinceEpoch)
? -_maxMillisecondsSinceEpoch
: i * 1000,
)
.toList();
final zones = <TimeZone>[];
for (final z in loc.zones) {
zones.add(
TimeZone(
Duration(seconds: z.offset),
isDst: z.isDst,
abbreviation: loc.abbreviations[z.abbreviationIndex],
),
);
}
return Location(loc.name, transitionAt, loc.transitionZone, zones);
}