common: Add timezone library
Timezone is ported from Chromium.
Tracking /etc/localtime to know region and timezone.
BUG=b:63280507
TEST=emerge-${BOARD} arc-camera3-libcamera_timezone
CQ-DEPEND=CL:664500
Change-Id: I6aca1ee477c5d232145e3d78907d38a438f2b9cf
Reviewed-on: https://chromium-review.googlesource.com/650072
Commit-Ready: Heng-ruey Hsu <henryhsu@chromium.org>
Tested-by: Heng-ruey Hsu <henryhsu@chromium.org>
Reviewed-by: Ricky Liang <jcliang@chromium.org>
diff --git a/Makefile b/Makefile
index 9c07d31..a26fac5 100644
--- a/Makefile
+++ b/Makefile
@@ -49,6 +49,10 @@
.PHONY: libcamera_jpeg
+libcamera_timezone: common/libcamera_timezone
+
+.PHONY: libcamera_timezone
+
libcbm: common/libcbm
.PHONY: libcbm
diff --git a/common/module.mk b/common/module.mk
index 9f2d5c1..5ba1d32 100644
--- a/common/module.mk
+++ b/common/module.mk
@@ -116,6 +116,19 @@
clean: CLEAN(common/libcamera_exif.so)
common/libcamera_exif: CXX_LIBRARY(common/libcamera_exif.so)
+libcamera_timezone_OBJS = common/timezone.o
+libcamera_timezone_PC_DEPS := libchrome-$(BASE_VER)
+libcamera_timezone_CPPFLAGS := \
+ $(call get_pc_cflags,$(libcamera_timezone_PC_DEPS))
+libcamera_timezone_LDLIBS := $(call get_pc_libs,$(libcamera_timezone_PC_DEPS))
+CXX_STATIC_LIBRARY(common/libcamera_timezone.pic.a): \
+ CPPFLAGS += $(libcamera_timezone_CPPFLAGS)
+CXX_STATIC_LIBRARY(common/libcamera_timezone.pic.a): \
+ LDLIBS += $(libcamera_timezone_LDLIBS)
+CXX_STATIC_LIBRARY(common/libcamera_timezone.pic.a): $(libcamera_timezone_OBJS)
+clean: CLEAN(common/libcamera_timezone.pic.a)
+common/libcamera_timezone: CXX_STATIC_LIBRARY(common/libcamera_timezone.pic.a)
+
# To link against object files under common/, add $(COMMON_OBJECTS) to the
# dependency list of your target.
COMMON_OBJECTS := \
diff --git a/common/timezone.cc b/common/timezone.cc
new file mode 100644
index 0000000..58267ad
--- /dev/null
+++ b/common/timezone.cc
@@ -0,0 +1,654 @@
+/*
+ * Copyright 2017 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "arc/timezone.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#include <map>
+
+#include <base/files/file_util.h>
+#include <base/macros.h>
+#include <base/memory/singleton.h>
+#include <base/strings/string16.h>
+#include <base/strings/utf_string_conversions.h>
+
+#include "arc/common.h"
+
+namespace arc {
+
+namespace {
+
+const char kTimeZoneFilePath[] = "/etc/localtime";
+const char kZoneInfoFilePath[] = "/usr/share/zoneinfo/";
+
+class TimezoneMap {
+ public:
+ static TimezoneMap* GetInstance() {
+ return base::Singleton<TimezoneMap>::get();
+ }
+
+ std::string CountryCodeForTimezone(const std::string& olson_code) {
+ std::map<const char*, const char*, CompareCStrings>::iterator iter =
+ map_.find(olson_code.c_str());
+ if (iter != map_.end())
+ return iter->second;
+
+ return std::string();
+ }
+
+ private:
+ TimezoneMap() {
+ // These mappings are adapted from zone.tab, which is available at
+ // <http://www.ietf.org/timezones/data/zone.tab> and is a part of public
+ // domain.
+ struct OlsonCodeData {
+ const char* country_code;
+ const char* olson_code;
+ };
+ static const OlsonCodeData olson_code_data[] = {
+ {"AD", "Europe/Andorra"},
+ {"AE", "Asia/Dubai"},
+ {"AF", "Asia/Kabul"},
+ {"AG", "America/Antigua"},
+ {"AI", "America/Anguilla"},
+ {"AL", "Europe/Tirane"},
+ {"AM", "Asia/Yerevan"},
+ {"AO", "Africa/Luanda"},
+ {"AQ", "Antarctica/McMurdo"},
+ {"AQ", "Antarctica/Rothera"},
+ {"AQ", "Antarctica/Palmer"},
+ {"AQ", "Antarctica/Mawson"},
+ {"AQ", "Antarctica/Davis"},
+ {"AQ", "Antarctica/Casey"},
+ {"AQ", "Antarctica/Vostok"},
+ {"AQ", "Antarctica/DumontDUrville"},
+ {"AQ", "Antarctica/Syowa"},
+ {"AR", "America/Argentina/Buenos_Aires"},
+ {"AR", "America/Argentina/Cordoba"},
+ {"AR", "America/Argentina/Salta"},
+ {"AR", "America/Argentina/Jujuy"},
+ {"AR", "America/Argentina/Tucuman"},
+ {"AR", "America/Argentina/Catamarca"},
+ {"AR", "America/Argentina/La_Rioja"},
+ {"AR", "America/Argentina/San_Juan"},
+ {"AR", "America/Argentina/Mendoza"},
+ {"AR", "America/Argentina/San_Luis"},
+ {"AR", "America/Argentina/Rio_Gallegos"},
+ {"AR", "America/Argentina/Ushuaia"},
+ {"AS", "Pacific/Pago_Pago"},
+ {"AT", "Europe/Vienna"},
+ {"AU", "Australia/Lord_Howe"},
+ {"AU", "Antarctica/Macquarie"},
+ {"AU", "Australia/Hobart"},
+ {"AU", "Australia/Currie"},
+ {"AU", "Australia/Melbourne"},
+ {"AU", "Australia/Sydney"},
+ {"AU", "Australia/Broken_Hill"},
+ {"AU", "Australia/Brisbane"},
+ {"AU", "Australia/Lindeman"},
+ {"AU", "Australia/Adelaide"},
+ {"AU", "Australia/Darwin"},
+ {"AU", "Australia/Perth"},
+ {"AU", "Australia/Eucla"},
+ {"AW", "America/Aruba"},
+ {"AX", "Europe/Mariehamn"},
+ {"AZ", "Asia/Baku"},
+ {"BA", "Europe/Sarajevo"},
+ {"BB", "America/Barbados"},
+ {"BD", "Asia/Dhaka"},
+ {"BE", "Europe/Brussels"},
+ {"BF", "Africa/Ouagadougou"},
+ {"BG", "Europe/Sofia"},
+ {"BH", "Asia/Bahrain"},
+ {"BI", "Africa/Bujumbura"},
+ {"BJ", "Africa/Porto-Novo"},
+ {"BL", "America/St_Barthelemy"},
+ {"BM", "Atlantic/Bermuda"},
+ {"BN", "Asia/Brunei"},
+ {"BO", "America/La_Paz"},
+ {"BQ", "America/Kralendijk"},
+ {"BR", "America/Noronha"},
+ {"BR", "America/Belem"},
+ {"BR", "America/Fortaleza"},
+ {"BR", "America/Recife"},
+ {"BR", "America/Araguaina"},
+ {"BR", "America/Maceio"},
+ {"BR", "America/Bahia"},
+ {"BR", "America/Sao_Paulo"},
+ {"BR", "America/Campo_Grande"},
+ {"BR", "America/Cuiaba"},
+ {"BR", "America/Santarem"},
+ {"BR", "America/Porto_Velho"},
+ {"BR", "America/Boa_Vista"},
+ {"BR", "America/Manaus"},
+ {"BR", "America/Eirunepe"},
+ {"BR", "America/Rio_Branco"},
+ {"BS", "America/Nassau"},
+ {"BT", "Asia/Thimphu"},
+ {"BW", "Africa/Gaborone"},
+ {"BY", "Europe/Minsk"},
+ {"BZ", "America/Belize"},
+ {"CA", "America/St_Johns"},
+ {"CA", "America/Halifax"},
+ {"CA", "America/Glace_Bay"},
+ {"CA", "America/Moncton"},
+ {"CA", "America/Goose_Bay"},
+ {"CA", "America/Blanc-Sablon"},
+ {"CA", "America/Toronto"},
+ {"CA", "America/Nipigon"},
+ {"CA", "America/Thunder_Bay"},
+ {"CA", "America/Iqaluit"},
+ {"CA", "America/Pangnirtung"},
+ {"CA", "America/Resolute"},
+ {"CA", "America/Atikokan"},
+ {"CA", "America/Rankin_Inlet"},
+ {"CA", "America/Winnipeg"},
+ {"CA", "America/Rainy_River"},
+ {"CA", "America/Regina"},
+ {"CA", "America/Swift_Current"},
+ {"CA", "America/Edmonton"},
+ {"CA", "America/Cambridge_Bay"},
+ {"CA", "America/Yellowknife"},
+ {"CA", "America/Inuvik"},
+ {"CA", "America/Creston"},
+ {"CA", "America/Dawson_Creek"},
+ {"CA", "America/Vancouver"},
+ {"CA", "America/Whitehorse"},
+ {"CA", "America/Dawson"},
+ {"CC", "Indian/Cocos"},
+ {"CD", "Africa/Kinshasa"},
+ {"CD", "Africa/Lubumbashi"},
+ {"CF", "Africa/Bangui"},
+ {"CG", "Africa/Brazzaville"},
+ {"CH", "Europe/Zurich"},
+ {"CI", "Africa/Abidjan"},
+ {"CK", "Pacific/Rarotonga"},
+ {"CL", "America/Santiago"},
+ {"CL", "Pacific/Easter"},
+ {"CM", "Africa/Douala"},
+ {"CN", "Asia/Shanghai"},
+ {"CN", "Asia/Harbin"},
+ {"CN", "Asia/Chongqing"},
+ {"CN", "Asia/Urumqi"},
+ {"CN", "Asia/Kashgar"},
+ {"CO", "America/Bogota"},
+ {"CR", "America/Costa_Rica"},
+ {"CU", "America/Havana"},
+ {"CV", "Atlantic/Cape_Verde"},
+ {"CW", "America/Curacao"},
+ {"CX", "Indian/Christmas"},
+ {"CY", "Asia/Nicosia"},
+ {"CZ", "Europe/Prague"},
+ {"DE", "Europe/Berlin"},
+ {"DE", "Europe/Busingen"},
+ {"DJ", "Africa/Djibouti"},
+ {"DK", "Europe/Copenhagen"},
+ {"DM", "America/Dominica"},
+ {"DO", "America/Santo_Domingo"},
+ {"DZ", "Africa/Algiers"},
+ {"EC", "America/Guayaquil"},
+ {"EC", "Pacific/Galapagos"},
+ {"EE", "Europe/Tallinn"},
+ {"EG", "Africa/Cairo"},
+ {"EH", "Africa/El_Aaiun"},
+ {"ER", "Africa/Asmara"},
+ {"ES", "Europe/Madrid"},
+ {"ES", "Africa/Ceuta"},
+ {"ES", "Atlantic/Canary"},
+ {"ET", "Africa/Addis_Ababa"},
+ {"FI", "Europe/Helsinki"},
+ {"FJ", "Pacific/Fiji"},
+ {"FK", "Atlantic/Stanley"},
+ {"FM", "Pacific/Chuuk"},
+ {"FM", "Pacific/Pohnpei"},
+ {"FM", "Pacific/Kosrae"},
+ {"FO", "Atlantic/Faroe"},
+ {"FR", "Europe/Paris"},
+ {"GA", "Africa/Libreville"},
+ {"GB", "Europe/London"},
+ {"GD", "America/Grenada"},
+ {"GE", "Asia/Tbilisi"},
+ {"GF", "America/Cayenne"},
+ {"GG", "Europe/Guernsey"},
+ {"GH", "Africa/Accra"},
+ {"GI", "Europe/Gibraltar"},
+ {"GL", "America/Godthab"},
+ {"GL", "America/Danmarkshavn"},
+ {"GL", "America/Scoresbysund"},
+ {"GL", "America/Thule"},
+ {"GM", "Africa/Banjul"},
+ {"GN", "Africa/Conakry"},
+ {"GP", "America/Guadeloupe"},
+ {"GQ", "Africa/Malabo"},
+ {"GR", "Europe/Athens"},
+ {"GS", "Atlantic/South_Georgia"},
+ {"GT", "America/Guatemala"},
+ {"GU", "Pacific/Guam"},
+ {"GW", "Africa/Bissau"},
+ {"GY", "America/Guyana"},
+ {"HK", "Asia/Hong_Kong"},
+ {"HN", "America/Tegucigalpa"},
+ {"HR", "Europe/Zagreb"},
+ {"HT", "America/Port-au-Prince"},
+ {"HU", "Europe/Budapest"},
+ {"ID", "Asia/Jakarta"},
+ {"ID", "Asia/Pontianak"},
+ {"ID", "Asia/Makassar"},
+ {"ID", "Asia/Jayapura"},
+ {"IE", "Europe/Dublin"},
+ {"IL", "Asia/Jerusalem"},
+ {"IM", "Europe/Isle_of_Man"},
+ {"IN", "Asia/Kolkata"},
+ {"IO", "Indian/Chagos"},
+ {"IQ", "Asia/Baghdad"},
+ {"IR", "Asia/Tehran"},
+ {"IS", "Atlantic/Reykjavik"},
+ {"IT", "Europe/Rome"},
+ {"JE", "Europe/Jersey"},
+ {"JM", "America/Jamaica"},
+ {"JO", "Asia/Amman"},
+ {"JP", "Asia/Tokyo"},
+ {"KE", "Africa/Nairobi"},
+ {"KG", "Asia/Bishkek"},
+ {"KH", "Asia/Phnom_Penh"},
+ {"KI", "Pacific/Tarawa"},
+ {"KI", "Pacific/Enderbury"},
+ {"KI", "Pacific/Kiritimati"},
+ {"KM", "Indian/Comoro"},
+ {"KN", "America/St_Kitts"},
+ {"KP", "Asia/Pyongyang"},
+ {"KR", "Asia/Seoul"},
+ {"KW", "Asia/Kuwait"},
+ {"KY", "America/Cayman"},
+ {"KZ", "Asia/Almaty"},
+ {"KZ", "Asia/Qyzylorda"},
+ {"KZ", "Asia/Aqtobe"},
+ {"KZ", "Asia/Aqtau"},
+ {"KZ", "Asia/Oral"},
+ {"LA", "Asia/Vientiane"},
+ {"LB", "Asia/Beirut"},
+ {"LC", "America/St_Lucia"},
+ {"LI", "Europe/Vaduz"},
+ {"LK", "Asia/Colombo"},
+ {"LR", "Africa/Monrovia"},
+ {"LS", "Africa/Maseru"},
+ {"LT", "Europe/Vilnius"},
+ {"LU", "Europe/Luxembourg"},
+ {"LV", "Europe/Riga"},
+ {"LY", "Africa/Tripoli"},
+ {"MA", "Africa/Casablanca"},
+ {"MC", "Europe/Monaco"},
+ {"MD", "Europe/Chisinau"},
+ {"ME", "Europe/Podgorica"},
+ {"MF", "America/Marigot"},
+ {"MG", "Indian/Antananarivo"},
+ {"MH", "Pacific/Majuro"},
+ {"MH", "Pacific/Kwajalein"},
+ {"MK", "Europe/Skopje"},
+ {"ML", "Africa/Bamako"},
+ {"MM", "Asia/Rangoon"},
+ {"MN", "Asia/Ulaanbaatar"},
+ {"MN", "Asia/Hovd"},
+ {"MN", "Asia/Choibalsan"},
+ {"MO", "Asia/Macau"},
+ {"MP", "Pacific/Saipan"},
+ {"MQ", "America/Martinique"},
+ {"MR", "Africa/Nouakchott"},
+ {"MS", "America/Montserrat"},
+ {"MT", "Europe/Malta"},
+ {"MU", "Indian/Mauritius"},
+ {"MV", "Indian/Maldives"},
+ {"MW", "Africa/Blantyre"},
+ {"MX", "America/Mexico_City"},
+ {"MX", "America/Cancun"},
+ {"MX", "America/Merida"},
+ {"MX", "America/Monterrey"},
+ {"MX", "America/Matamoros"},
+ {"MX", "America/Mazatlan"},
+ {"MX", "America/Chihuahua"},
+ {"MX", "America/Ojinaga"},
+ {"MX", "America/Hermosillo"},
+ {"MX", "America/Tijuana"},
+ {"MX", "America/Santa_Isabel"},
+ {"MX", "America/Bahia_Banderas"},
+ {"MY", "Asia/Kuala_Lumpur"},
+ {"MY", "Asia/Kuching"},
+ {"MZ", "Africa/Maputo"},
+ {"NA", "Africa/Windhoek"},
+ {"NC", "Pacific/Noumea"},
+ {"NE", "Africa/Niamey"},
+ {"NF", "Pacific/Norfolk"},
+ {"NG", "Africa/Lagos"},
+ {"NI", "America/Managua"},
+ {"NL", "Europe/Amsterdam"},
+ {"NO", "Europe/Oslo"},
+ {"NP", "Asia/Kathmandu"},
+ {"NR", "Pacific/Nauru"},
+ {"NU", "Pacific/Niue"},
+ {"NZ", "Pacific/Auckland"},
+ {"NZ", "Pacific/Chatham"},
+ {"OM", "Asia/Muscat"},
+ {"PA", "America/Panama"},
+ {"PE", "America/Lima"},
+ {"PF", "Pacific/Tahiti"},
+ {"PF", "Pacific/Marquesas"},
+ {"PF", "Pacific/Gambier"},
+ {"PG", "Pacific/Port_Moresby"},
+ {"PH", "Asia/Manila"},
+ {"PK", "Asia/Karachi"},
+ {"PL", "Europe/Warsaw"},
+ {"PM", "America/Miquelon"},
+ {"PN", "Pacific/Pitcairn"},
+ {"PR", "America/Puerto_Rico"},
+ {"PS", "Asia/Gaza"},
+ {"PS", "Asia/Hebron"},
+ {"PT", "Europe/Lisbon"},
+ {"PT", "Atlantic/Madeira"},
+ {"PT", "Atlantic/Azores"},
+ {"PW", "Pacific/Palau"},
+ {"PY", "America/Asuncion"},
+ {"QA", "Asia/Qatar"},
+ {"RE", "Indian/Reunion"},
+ {"RO", "Europe/Bucharest"},
+ {"RS", "Europe/Belgrade"},
+ {"RU", "Europe/Kaliningrad"},
+ {"RU", "Europe/Moscow"},
+ {"RU", "Europe/Volgograd"},
+ {"RU", "Europe/Samara"},
+ {"RU", "Asia/Yekaterinburg"},
+ {"RU", "Asia/Omsk"},
+ {"RU", "Asia/Novosibirsk"},
+ {"RU", "Asia/Novokuznetsk"},
+ {"RU", "Asia/Krasnoyarsk"},
+ {"RU", "Asia/Irkutsk"},
+ {"RU", "Asia/Yakutsk"},
+ {"RU", "Asia/Khandyga"},
+ {"RU", "Asia/Vladivostok"},
+ {"RU", "Asia/Sakhalin"},
+ {"RU", "Asia/Ust-Nera"},
+ {"RU", "Asia/Magadan"},
+ {"RU", "Asia/Kamchatka"},
+ {"RU", "Asia/Anadyr"},
+ {"RW", "Africa/Kigali"},
+ {"SA", "Asia/Riyadh"},
+ {"SB", "Pacific/Guadalcanal"},
+ {"SC", "Indian/Mahe"},
+ {"SD", "Africa/Khartoum"},
+ {"SE", "Europe/Stockholm"},
+ {"SG", "Asia/Singapore"},
+ {"SH", "Atlantic/St_Helena"},
+ {"SI", "Europe/Ljubljana"},
+ {"SJ", "Arctic/Longyearbyen"},
+ {"SK", "Europe/Bratislava"},
+ {"SL", "Africa/Freetown"},
+ {"SM", "Europe/San_Marino"},
+ {"SN", "Africa/Dakar"},
+ {"SO", "Africa/Mogadishu"},
+ {"SR", "America/Paramaribo"},
+ {"SS", "Africa/Juba"},
+ {"ST", "Africa/Sao_Tome"},
+ {"SV", "America/El_Salvador"},
+ {"SX", "America/Lower_Princes"},
+ {"SY", "Asia/Damascus"},
+ {"SZ", "Africa/Mbabane"},
+ {"TC", "America/Grand_Turk"},
+ {"TD", "Africa/Ndjamena"},
+ {"TF", "Indian/Kerguelen"},
+ {"TG", "Africa/Lome"},
+ {"TH", "Asia/Bangkok"},
+ {"TJ", "Asia/Dushanbe"},
+ {"TK", "Pacific/Fakaofo"},
+ {"TL", "Asia/Dili"},
+ {"TM", "Asia/Ashgabat"},
+ {"TN", "Africa/Tunis"},
+ {"TO", "Pacific/Tongatapu"},
+ {"TR", "Europe/Istanbul"},
+ {"TT", "America/Port_of_Spain"},
+ {"TV", "Pacific/Funafuti"},
+ {"TW", "Asia/Taipei"},
+ {"TZ", "Africa/Dar_es_Salaam"},
+ {"UA", "Europe/Kiev"},
+ {"UA", "Europe/Uzhgorod"},
+ {"UA", "Europe/Zaporozhye"},
+ {"UA", "Europe/Simferopol"},
+ {"UG", "Africa/Kampala"},
+ {"UM", "Pacific/Johnston"},
+ {"UM", "Pacific/Midway"},
+ {"UM", "Pacific/Wake"},
+ {"US", "America/New_York"},
+ {"US", "America/Detroit"},
+ {"US", "America/Kentucky/Louisville"},
+ {"US", "America/Kentucky/Monticello"},
+ {"US", "America/Indiana/Indianapolis"},
+ {"US", "America/Indiana/Vincennes"},
+ {"US", "America/Indiana/Winamac"},
+ {"US", "America/Indiana/Marengo"},
+ {"US", "America/Indiana/Petersburg"},
+ {"US", "America/Indiana/Vevay"},
+ {"US", "America/Chicago"},
+ {"US", "America/Indiana/Tell_City"},
+ {"US", "America/Indiana/Knox"},
+ {"US", "America/Menominee"},
+ {"US", "America/North_Dakota/Center"},
+ {"US", "America/North_Dakota/New_Salem"},
+ {"US", "America/North_Dakota/Beulah"},
+ {"US", "America/Denver"},
+ {"US", "America/Boise"},
+ {"US", "America/Phoenix"},
+ {"US", "America/Los_Angeles"},
+ {"US", "America/Anchorage"},
+ {"US", "America/Juneau"},
+ {"US", "America/Sitka"},
+ {"US", "America/Yakutat"},
+ {"US", "America/Nome"},
+ {"US", "America/Adak"},
+ {"US", "America/Metlakatla"},
+ {"US", "Pacific/Honolulu"},
+ {"UY", "America/Montevideo"},
+ {"UZ", "Asia/Samarkand"},
+ {"UZ", "Asia/Tashkent"},
+ {"VA", "Europe/Vatican"},
+ {"VC", "America/St_Vincent"},
+ {"VE", "America/Caracas"},
+ {"VG", "America/Tortola"},
+ {"VI", "America/St_Thomas"},
+ {"VN", "Asia/Ho_Chi_Minh"},
+ {"VU", "Pacific/Efate"},
+ {"WF", "Pacific/Wallis"},
+ {"WS", "Pacific/Apia"},
+ {"YE", "Asia/Aden"},
+ {"YT", "Indian/Mayotte"},
+ {"ZA", "Africa/Johannesburg"},
+ {"ZM", "Africa/Lusaka"},
+ {"ZW", "Africa/Harare"},
+ // The mappings below are custom additions to zone.tab.
+ {"GB", "Etc/GMT"},
+ {"GB", "Etc/UTC"},
+ {"GB", "Etc/UCT"},
+ };
+
+ for (size_t i = 0; i < arraysize(olson_code_data); ++i)
+ map_[olson_code_data[i].olson_code] = olson_code_data[i].country_code;
+
+ // These are mapping from old codenames to new codenames. They are also
+ // part of public domain, and available at
+ // <http://www.ietf.org/timezones/data/backward>.
+ struct LinkData {
+ const char* old_code;
+ const char* new_code;
+ };
+ static const LinkData link_data[] = {
+ {"Africa/Asmera", "Africa/Asmara"},
+ {"Africa/Timbuktu", "Africa/Bamako"},
+ {"America/Argentina/ComodRivadavia", "America/Argentina/Catamarca"},
+ {"America/Atka", "America/Adak"},
+ {"America/Buenos_Aires", "America/Argentina/Buenos_Aires"},
+ {"America/Catamarca", "America/Argentina/Catamarca"},
+ {"America/Coral_Harbour", "America/Atikokan"},
+ {"America/Cordoba", "America/Argentina/Cordoba"},
+ {"America/Ensenada", "America/Tijuana"},
+ {"America/Fort_Wayne", "America/Indiana/Indianapolis"},
+ {"America/Indianapolis", "America/Indiana/Indianapolis"},
+ {"America/Jujuy", "America/Argentina/Jujuy"},
+ {"America/Knox_IN", "America/Indiana/Knox"},
+ {"America/Louisville", "America/Kentucky/Louisville"},
+ {"America/Mendoza", "America/Argentina/Mendoza"},
+ {"America/Porto_Acre", "America/Rio_Branco"},
+ {"America/Rosario", "America/Argentina/Cordoba"},
+ {"America/Virgin", "America/St_Thomas"},
+ {"Asia/Ashkhabad", "Asia/Ashgabat"},
+ {"Asia/Chungking", "Asia/Chongqing"},
+ {"Asia/Dacca", "Asia/Dhaka"},
+ {"Asia/Katmandu", "Asia/Kathmandu"},
+ {"Asia/Calcutta", "Asia/Kolkata"},
+ {"Asia/Macao", "Asia/Macau"},
+ {"Asia/Tel_Aviv", "Asia/Jerusalem"},
+ {"Asia/Saigon", "Asia/Ho_Chi_Minh"},
+ {"Asia/Thimbu", "Asia/Thimphu"},
+ {"Asia/Ujung_Pandang", "Asia/Makassar"},
+ {"Asia/Ulan_Bator", "Asia/Ulaanbaatar"},
+ {"Atlantic/Faeroe", "Atlantic/Faroe"},
+ {"Atlantic/Jan_Mayen", "Europe/Oslo"},
+ {"Australia/ACT", "Australia/Sydney"},
+ {"Australia/Canberra", "Australia/Sydney"},
+ {"Australia/LHI", "Australia/Lord_Howe"},
+ {"Australia/NSW", "Australia/Sydney"},
+ {"Australia/North", "Australia/Darwin"},
+ {"Australia/Queensland", "Australia/Brisbane"},
+ {"Australia/South", "Australia/Adelaide"},
+ {"Australia/Tasmania", "Australia/Hobart"},
+ {"Australia/Victoria", "Australia/Melbourne"},
+ {"Australia/West", "Australia/Perth"},
+ {"Australia/Yancowinna", "Australia/Broken_Hill"},
+ {"Brazil/Acre", "America/Rio_Branco"},
+ {"Brazil/DeNoronha", "America/Noronha"},
+ {"Brazil/East", "America/Sao_Paulo"},
+ {"Brazil/West", "America/Manaus"},
+ {"Canada/Atlantic", "America/Halifax"},
+ {"Canada/Central", "America/Winnipeg"},
+ {"Canada/East-Saskatchewan", "America/Regina"},
+ {"Canada/Eastern", "America/Toronto"},
+ {"Canada/Mountain", "America/Edmonton"},
+ {"Canada/Newfoundland", "America/St_Johns"},
+ {"Canada/Pacific", "America/Vancouver"},
+ {"Canada/Saskatchewan", "America/Regina"},
+ {"Canada/Yukon", "America/Whitehorse"},
+ {"Chile/Continental", "America/Santiago"},
+ {"Chile/EasterIsland", "Pacific/Easter"},
+ {"Cuba", "America/Havana"},
+ {"Egypt", "Africa/Cairo"},
+ {"Eire", "Europe/Dublin"},
+ {"Europe/Belfast", "Europe/London"},
+ {"Europe/Tiraspol", "Europe/Chisinau"},
+ {"GB", "Europe/London"},
+ {"GB-Eire", "Europe/London"},
+ {"GMT+0", "Etc/GMT"},
+ {"GMT-0", "Etc/GMT"},
+ {"GMT0", "Etc/GMT"},
+ {"Greenwich", "Etc/GMT"},
+ {"Hongkong", "Asia/Hong_Kong"},
+ {"Iceland", "Atlantic/Reykjavik"},
+ {"Iran", "Asia/Tehran"},
+ {"Israel", "Asia/Jerusalem"},
+ {"Jamaica", "America/Jamaica"},
+ {"Japan", "Asia/Tokyo"},
+ {"Kwajalein", "Pacific/Kwajalein"},
+ {"Libya", "Africa/Tripoli"},
+ {"Mexico/BajaNorte", "America/Tijuana"},
+ {"Mexico/BajaSur", "America/Mazatlan"},
+ {"Mexico/General", "America/Mexico_City"},
+ {"NZ", "Pacific/Auckland"},
+ {"NZ-CHAT", "Pacific/Chatham"},
+ {"Navajo", "America/Denver"},
+ {"PRC", "Asia/Shanghai"},
+ {"Pacific/Samoa", "Pacific/Pago_Pago"},
+ {"Pacific/Yap", "Pacific/Chuuk"},
+ {"Pacific/Truk", "Pacific/Chuuk"},
+ {"Pacific/Ponape", "Pacific/Pohnpei"},
+ {"Poland", "Europe/Warsaw"},
+ {"Portugal", "Europe/Lisbon"},
+ {"ROC", "Asia/Taipei"},
+ {"ROK", "Asia/Seoul"},
+ {"Singapore", "Asia/Singapore"},
+ {"Turkey", "Europe/Istanbul"},
+ {"UCT", "Etc/UCT"},
+ {"US/Alaska", "America/Anchorage"},
+ {"US/Aleutian", "America/Adak"},
+ {"US/Arizona", "America/Phoenix"},
+ {"US/Central", "America/Chicago"},
+ {"US/East-Indiana", "America/Indiana/Indianapolis"},
+ {"US/Eastern", "America/New_York"},
+ {"US/Hawaii", "Pacific/Honolulu"},
+ {"US/Indiana-Starke", "America/Indiana/Knox"},
+ {"US/Michigan", "America/Detroit"},
+ {"US/Mountain", "America/Denver"},
+ {"US/Pacific", "America/Los_Angeles"},
+ {"US/Samoa", "Pacific/Pago_Pago"},
+ {"UTC", "Etc/UTC"},
+ {"Universal", "Etc/UTC"},
+ {"W-SU", "Europe/Moscow"},
+ {"Zulu", "Etc/UTC"},
+ };
+
+ for (size_t i = 0; i < arraysize(link_data); ++i)
+ map_[link_data[i].old_code] = map_[link_data[i].new_code];
+ }
+
+ friend struct base::DefaultSingletonTraits<TimezoneMap>;
+
+ struct CompareCStrings {
+ bool operator()(const char* str1, const char* str2) const {
+ return strcmp(str1, str2) < 0;
+ }
+ };
+ std::map<const char*, const char*, CompareCStrings> map_;
+
+ DISALLOW_COPY_AND_ASSIGN(TimezoneMap);
+};
+
+} // namespace
+
+std::string CountryCodeForCurrentTimezone() {
+ base::FilePath target;
+ base::FilePath timezone_path(kTimeZoneFilePath);
+ while (base::ReadSymbolicLink(timezone_path, &target)) {
+ timezone_path = base::FilePath(target);
+ }
+ if (timezone_path.value().compare(0, strlen(kZoneInfoFilePath),
+ kZoneInfoFilePath)) {
+ LOGF(WARNING) << "Timezone is unknown. Anti banding may be broken.";
+ return std::string();
+ }
+ std::string olson_code = timezone_path.value();
+ olson_code.replace(0, strlen(kZoneInfoFilePath), "");
+ LOGF(INFO) << "Timezone: " << olson_code;
+ return TimezoneMap::GetInstance()->CountryCodeForTimezone(olson_code);
+}
+
+PowerLineFrequency GetPowerLineFrequencyForLocation() {
+ const std::string current_country = CountryCodeForCurrentTimezone();
+ if (current_country.empty())
+ return PowerLineFrequency::FREQ_DEFAULT;
+ LOGF(INFO) << "Country: " << current_country;
+ // Sorted out list of countries with 60Hz power line frequency, from
+ // http://en.wikipedia.org/wiki/Mains_electricity_by_country
+ const char* countries_using_60Hz[] = {
+ "AI", "AO", "AS", "AW", "AZ", "BM", "BR", "BS", "BZ", "CA", "CO",
+ "CR", "CU", "DO", "EC", "FM", "GT", "GU", "GY", "HN", "HT", "JP",
+ "KN", "KR", "KY", "MS", "MX", "NI", "PA", "PE", "PF", "PH", "PR",
+ "PW", "SA", "SR", "SV", "TT", "TW", "UM", "US", "VG", "VI", "VE"};
+ const char** countries_using_60Hz_end =
+ countries_using_60Hz + arraysize(countries_using_60Hz);
+ if (std::find(countries_using_60Hz, countries_using_60Hz_end,
+ current_country) == countries_using_60Hz_end) {
+ return PowerLineFrequency::FREQ_50HZ;
+ }
+ return PowerLineFrequency::FREQ_60HZ;
+}
+
+} // namespace arc
diff --git a/include/arc/timezone.h b/include/arc/timezone.h
new file mode 100644
index 0000000..90f2cce
--- /dev/null
+++ b/include/arc/timezone.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef INCLUDE_ARC_TIMEZONE_H_
+#define INCLUDE_ARC_TIMEZONE_H_
+
+#include <string>
+
+namespace arc {
+
+enum class PowerLineFrequency {
+ FREQ_DEFAULT = 0,
+ FREQ_50HZ = 1,
+ FREQ_60HZ = 2,
+ FREQ_AUTO = 3,
+ FREQ_ERROR = 4,
+};
+
+// Checks the system timezone and turns it into a two-character ASCII country
+// code. This may fail (for example, it will always fail on Android), in which
+// case it will return an empty string.
+std::string CountryCodeForCurrentTimezone();
+
+// Queries timezone to know the country to decide power frequency to do
+// anti-banding.
+PowerLineFrequency GetPowerLineFrequencyForLocation();
+
+} // namespace arc
+
+#endif // INCLUDE_ARC_TIMEZONE_H_