| // 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); | |
| } |