TrinityCore
Loading...
Searching...
No Matches
Timezone.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "Timezone.h"
19#include "Hash.h"
20#include "Locales.h"
21#include "MapUtils.h"
22#include "StringConvert.h"
23#include "Util.h"
24#include <boost/locale/date_time_facet.hpp>
25#include <chrono>
26#include <memory>
27#include <unordered_map>
28
29namespace
30{
31std::unordered_map<uint32, Minutes, std::identity> InitTimezoneHashDb()
32{
33#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
34
35 // Generate our hash db to match values sent in client authentication packets
36 std::unordered_map<uint32, Minutes, std::identity> hashToOffset;
37 std::chrono::system_clock::time_point dummmy;
38 for (std::chrono::time_zone const& zone : std::chrono::get_tzdb().zones)
39 {
40 std::chrono::sys_info sysInfo = zone.get_info(dummmy);
41 Minutes offsetMinutes = std::chrono::duration_cast<Minutes>(sysInfo.offset);
42 std::string offsetStr = Trinity::ToString(offsetMinutes.count());
43 hashToOffset.emplace(Trinity::HashFnv1a(offsetStr), offsetMinutes);
44 }
45
46#else
47 // Pre-generated list of timezone offsets and their hashes for compilers (and their stl implementations) that dont support timezone api yet
48 std::unordered_map<uint32, Minutes, std::identity> hashToOffset =
49 {
50 { 0xAADC2D37u, -720min },
51 { 0x362F107Bu, -690min },
52 { 0x2C44C70Cu, -660min },
53 { 0xB84A209Eu, -640min },
54 { 0xBA3D57D1u, -630min },
55 { 0x4040695Au, -600min },
56 { 0xB65A75D0u, -570min },
57 { 0xC8614DEBu, -540min },
58 { 0x3A68BD26u, -510min },
59 { 0x51E8096Cu, -480min },
60 { 0x4DD8F896u, -420min },
61 { 0x674B7C0Fu, -360min },
62 { 0x633C6B39u, -300min },
63 { 0x0BAD340Au, -240min },
64 { 0x74B25683u, -225min },
65 { 0x09B9FCD7u, -210min },
66 { 0x150C169Bu, -180min },
67 { 0x191B2771u, -120min },
68 { 0xD7D3B14Eu, -60min },
69 { 0x47CE5170u, -44min },
70 { 0x350CA8AFu, 0min },
71 { 0x15E8E23Bu, 60min },
72 { 0x733864AEu, 120min },
73 { 0xF71F9C94u, 180min },
74 { 0xBDE50F54u, 210min },
75 { 0x2BDD6DB9u, 240min },
76 { 0xB1E07F42u, 270min },
77 { 0x454FF132u, 300min },
78 { 0x3F4DA929u, 330min },
79 { 0xD1554AC4u, 360min },
80 { 0xBB667143u, 390min },
81 { 0x9E2B78C9u, 420min },
82 { 0x1C377816u, 450min },
83 { 0x1A4440E3u, 480min },
84 { 0xB49DF789u, 525min },
85 { 0xC3A28C54u, 540min },
86 { 0x35A9FB8Fu, 570min },
87 { 0x889BD751u, 600min },
88 { 0x8CAAE827u, 660min },
89 { 0x7285EE60u, 690min },
90 { 0x1CC2DEF4u, 720min },
91 { 0x89B8FD2Fu, 765min },
92 { 0x98DBA70Eu, 780min },
93 { 0xC59585BBu, 840min }
94 };
95#endif
96
97 return hashToOffset;
98}
99
100std::unordered_map<uint32, Minutes, std::identity> const& GetTimezoneOffsetsByHash()
101{
102 static std::unordered_map<uint32, Minutes, std::identity> timezoneMap = InitTimezoneHashDb();
103 return timezoneMap;
104}
105
106using ClientSupportedTimezone = std::pair<Minutes, std::string>;
107std::array<ClientSupportedTimezone, 11> const _clientSupportedTimezones =
108{{
109 { -480min, "America/Los_Angeles" },
110 { -420min, "America/Denver" },
111 { -360min, "America/Chicago" },
112 { -300min, "America/New_York" },
113 { -180min, "America/Sao_Paulo" },
114 { 0min, "Etc/UTC" },
115 { 60min, "Europe/Paris" },
116 { 480min, "Asia/Shanghai" },
117 { 480min, "Asia/Taipei" },
118 { 540min, "Asia/Seoul" },
119 { 600min, "Australia/Melbourne" },
120}};
121}
122
124{
126{
127 if (Minutes const* offset = Containers::MapGetValuePtr(GetTimezoneOffsetsByHash(), hash))
128 return *offset;
129
130 return 0min;
131}
132
134{
135 Seconds offset;
136#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
137 offset = std::chrono::current_zone()->get_info(date).offset;
138#else
139 tm buf = TimeBreakdown(std::chrono::system_clock::to_time_t(date));
140 offset = Seconds(buf.tm_gmtoff);
141#endif
142 return std::chrono::duration_cast<Minutes>(offset);
143}
144
145Minutes GetSystemZoneOffset(bool applyDst /*= true*/)
146{
147 std::chrono::system_clock::time_point date = std::chrono::system_clock::from_time_t(std::time_t(0));
148 if (applyDst)
149 date = std::chrono::system_clock::now();
150
151 return GetSystemZoneOffsetAt(date);
152}
153
154std::string GetSystemZoneName()
155{
156#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
157 return std::string(std::chrono::current_zone()->name());
158#else
159 std::unique_ptr<boost::locale::abstract_calendar> p(std::use_facet<class boost::locale::calendar_facet>(Locale::GetCalendarLocale()).create_calendar());
160 return p->get_timezone();
161#endif
162}
163
164std::string_view FindClosestClientSupportedTimezone(std::string_view currentTimezone, Minutes currentTimezoneOffset)
165{
166 // try exact match
167 auto itr = std::find_if(_clientSupportedTimezones.begin(), _clientSupportedTimezones.end(), [currentTimezone](ClientSupportedTimezone const& tz)
168 {
169 return tz.second == currentTimezone;
170 });
171 if (itr != _clientSupportedTimezones.end())
172 return itr->second;
173
174 // try closest offset
175 itr = std::min_element(_clientSupportedTimezones.begin(), _clientSupportedTimezones.end(), [currentTimezoneOffset](ClientSupportedTimezone const& left, ClientSupportedTimezone const& right)
176 {
177 Minutes leftDiff = left.first - currentTimezoneOffset;
178 Minutes rightDiff = right.first - currentTimezoneOffset;
179 return std::abs(leftDiff.count()) < std::abs(rightDiff.count());
180 });
181
182 return itr->second;
183}
184}
uint32_t uint32
Definition Define.h:133
std::chrono::system_clock::time_point SystemTimePoint
Definition Duration.h:37
std::chrono::seconds Seconds
Seconds shorthand typedef.
Definition Duration.h:27
std::chrono::minutes Minutes
Minutes shorthand typedef.
Definition Duration.h:30
tm TimeBreakdown(time_t time)
Definition Util.cpp:93
auto MapGetValuePtr(M &map, typename M::key_type const &key)
Definition MapUtils.h:29
TC_COMMON_API std::locale const & GetCalendarLocale()
Definition Locales.cpp:47
Minutes GetOffsetByHash(uint32 hash)
Definition Timezone.cpp:125
std::string_view FindClosestClientSupportedTimezone(std::string_view currentTimezone, Minutes currentTimezoneOffset)
Definition Timezone.cpp:164
Minutes GetSystemZoneOffset(bool applyDst)
Definition Timezone.cpp:145
std::string GetSystemZoneName()
Definition Timezone.cpp:154
Minutes GetSystemZoneOffsetAt(SystemTimePoint date)
Definition Timezone.cpp:133
std::string ToString(Type &&val, Params &&... params)
std::uint32_t HashFnv1a(std::string_view data)
Definition Hash.h:33
STL namespace.