Merge pull request #10391 from akallabeth/timezone_impro
Timezone improved
This commit is contained in:
commit
1fe61c9432
@ -30,6 +30,7 @@
|
|||||||
#include <winpr/path.h>
|
#include <winpr/path.h>
|
||||||
#include <winpr/ncrypt.h>
|
#include <winpr/ncrypt.h>
|
||||||
#include <winpr/environment.h>
|
#include <winpr/environment.h>
|
||||||
|
#include <winpr/timezone.h>
|
||||||
|
|
||||||
#include <freerdp/freerdp.h>
|
#include <freerdp/freerdp.h>
|
||||||
#include <freerdp/addin.h>
|
#include <freerdp/addin.h>
|
||||||
@ -1666,11 +1667,24 @@ static void freerdp_client_print_keyboard_list(void)
|
|||||||
RDP_KEYBOARD_LAYOUT_TYPE_IME);
|
RDP_KEYBOARD_LAYOUT_TYPE_IME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void freerdp_client_print_timezone_list(void)
|
||||||
|
{
|
||||||
|
DWORD index = 0;
|
||||||
|
DYNAMIC_TIME_ZONE_INFORMATION info = { 0 };
|
||||||
|
while (EnumDynamicTimeZoneInformation(index++, &info) != ERROR_NO_MORE_ITEMS)
|
||||||
|
{
|
||||||
|
char TimeZoneKeyName[ARRAYSIZE(info.TimeZoneKeyName) + 1] = { 0 };
|
||||||
|
|
||||||
|
ConvertWCharNToUtf8(info.TimeZoneKeyName, ARRAYSIZE(info.TimeZoneKeyName), TimeZoneKeyName,
|
||||||
|
ARRAYSIZE(TimeZoneKeyName));
|
||||||
|
printf("%" PRIu32 ": '%s'\n", index, TimeZoneKeyName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void freerdp_client_print_tune_list(const rdpSettings* settings)
|
static void freerdp_client_print_tune_list(const rdpSettings* settings)
|
||||||
{
|
{
|
||||||
SSIZE_T type = 0;
|
SSIZE_T type = 0;
|
||||||
|
|
||||||
printf("%s\t%50s\t%s\t%s", "<index>", "<key>", "<type>", "<default value>\n");
|
|
||||||
for (size_t x = 0; x < FreeRDP_Settings_StableAPI_MAX; x++)
|
for (size_t x = 0; x < FreeRDP_Settings_StableAPI_MAX; x++)
|
||||||
{
|
{
|
||||||
const char* name = freerdp_settings_get_name_for_key(x);
|
const char* name = freerdp_settings_get_name_for_key(x);
|
||||||
@ -1755,7 +1769,9 @@ int freerdp_client_settings_command_line_status_print_ex(rdpSettings* settings,
|
|||||||
|
|
||||||
if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)
|
if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)
|
||||||
{
|
{
|
||||||
if (option_equals("tune", arg->Value))
|
if (option_equals("timezones", arg->Value))
|
||||||
|
freerdp_client_print_timezone_list();
|
||||||
|
else if (option_equals("tune", arg->Value))
|
||||||
freerdp_client_print_tune_list(settings);
|
freerdp_client_print_tune_list(settings);
|
||||||
else if (option_equals("kbd", arg->Value))
|
else if (option_equals("kbd", arg->Value))
|
||||||
freerdp_client_print_keyboard_list();
|
freerdp_client_print_keyboard_list();
|
||||||
@ -4718,6 +4734,43 @@ static int freerdp_client_settings_parse_command_line_arguments_int(
|
|||||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_TcpAckTimeout, (UINT32)val))
|
if (!freerdp_settings_set_uint32(settings, FreeRDP_TcpAckTimeout, (UINT32)val))
|
||||||
return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
|
return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
|
||||||
}
|
}
|
||||||
|
CommandLineSwitchCase(arg, "timezone")
|
||||||
|
{
|
||||||
|
BOOL found = FALSE;
|
||||||
|
DWORD index = 0;
|
||||||
|
DYNAMIC_TIME_ZONE_INFORMATION info = { 0 };
|
||||||
|
char TimeZoneKeyName[ARRAYSIZE(info.TimeZoneKeyName) + 1] = { 0 };
|
||||||
|
while (EnumDynamicTimeZoneInformation(index++, &info) != ERROR_NO_MORE_ITEMS)
|
||||||
|
{
|
||||||
|
ConvertWCharNToUtf8(info.TimeZoneKeyName, ARRAYSIZE(info.TimeZoneKeyName),
|
||||||
|
TimeZoneKeyName, ARRAYSIZE(TimeZoneKeyName));
|
||||||
|
|
||||||
|
if (strncmp(TimeZoneKeyName, arg->Value, ARRAYSIZE(TimeZoneKeyName)) == 0)
|
||||||
|
{
|
||||||
|
found = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
|
||||||
|
|
||||||
|
if (!freerdp_settings_set_string(settings, FreeRDP_DynamicDSTTimeZoneKeyName,
|
||||||
|
TimeZoneKeyName))
|
||||||
|
return fail_at(arg, COMMAND_LINE_ERROR);
|
||||||
|
|
||||||
|
TIME_ZONE_INFORMATION* tz =
|
||||||
|
freerdp_settings_get_pointer_writable(settings, FreeRDP_ClientTimeZone);
|
||||||
|
if (!tz)
|
||||||
|
return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
|
||||||
|
|
||||||
|
tz->Bias = info.Bias;
|
||||||
|
tz->DaylightBias = info.DaylightBias;
|
||||||
|
tz->DaylightDate = info.DaylightDate;
|
||||||
|
memcpy(tz->DaylightName, info.DaylightName, sizeof(tz->DaylightName));
|
||||||
|
tz->StandardBias = info.StandardBias;
|
||||||
|
tz->StandardDate = info.StandardDate;
|
||||||
|
memcpy(tz->StandardName, info.StandardName, sizeof(tz->StandardName));
|
||||||
|
}
|
||||||
CommandLineSwitchCase(arg, "aero")
|
CommandLineSwitchCase(arg, "aero")
|
||||||
{
|
{
|
||||||
if (!freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, enable))
|
if (!freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, enable))
|
||||||
|
@ -297,7 +297,7 @@ static const COMMAND_LINE_ARGUMENT_A global_cmd_args[] = {
|
|||||||
{ "list", COMMAND_LINE_VALUE_REQUIRED | COMMAND_LINE_PRINT,
|
{ "list", COMMAND_LINE_VALUE_REQUIRED | COMMAND_LINE_PRINT,
|
||||||
"[kbd|kbd-scancode|kbd-lang[:<value>]|smartcard[:[pkinit-anchors:<path>][,pkcs11-module:<"
|
"[kbd|kbd-scancode|kbd-lang[:<value>]|smartcard[:[pkinit-anchors:<path>][,pkcs11-module:<"
|
||||||
"name>]]|"
|
"name>]]|"
|
||||||
"monitor|tune]",
|
"monitor|tune|timezones]",
|
||||||
"List available options for subcommand", NULL, -1, NULL,
|
"List available options for subcommand", NULL, -1, NULL,
|
||||||
"List available options for subcommand" },
|
"List available options for subcommand" },
|
||||||
{ "log-filters", COMMAND_LINE_VALUE_REQUIRED, "<tag>:<level>[,<tag>:<level>[,...]]", NULL, NULL,
|
{ "log-filters", COMMAND_LINE_VALUE_REQUIRED, "<tag>:<level>[,<tag>:<level>[,...]]", NULL, NULL,
|
||||||
@ -453,6 +453,9 @@ static const COMMAND_LINE_ARGUMENT_A global_cmd_args[] = {
|
|||||||
{ "timeout", COMMAND_LINE_VALUE_REQUIRED, "<time in ms>", "9000", NULL, -1, "timeout",
|
{ "timeout", COMMAND_LINE_VALUE_REQUIRED, "<time in ms>", "9000", NULL, -1, "timeout",
|
||||||
"Advanced setting for high latency links: Adjust connection timeout, use if you encounter "
|
"Advanced setting for high latency links: Adjust connection timeout, use if you encounter "
|
||||||
"timeout failures with your connection" },
|
"timeout failures with your connection" },
|
||||||
|
{ "timezone", COMMAND_LINE_VALUE_REQUIRED, "<windows timezone>", NULL, NULL, -1, NULL,
|
||||||
|
"Use supplied windows timezone for connection (requires server support), see /list:timezones "
|
||||||
|
"for allowed values" },
|
||||||
{ "tls", COMMAND_LINE_VALUE_REQUIRED, "[ciphers|seclevel|secrets-file|enforce]", NULL, NULL, -1,
|
{ "tls", COMMAND_LINE_VALUE_REQUIRED, "[ciphers|seclevel|secrets-file|enforce]", NULL, NULL, -1,
|
||||||
NULL,
|
NULL,
|
||||||
"TLS configuration options:"
|
"TLS configuration options:"
|
||||||
|
@ -110,6 +110,8 @@ extern "C"
|
|||||||
const PDYNAMIC_TIME_ZONE_INFORMATION lpTimeZoneInformation, LPDWORD FirstYear,
|
const PDYNAMIC_TIME_ZONE_INFORMATION lpTimeZoneInformation, LPDWORD FirstYear,
|
||||||
LPDWORD LastYear);
|
LPDWORD LastYear);
|
||||||
|
|
||||||
|
#else
|
||||||
|
#pragma comment(lib, "advapi32")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -19,12 +19,12 @@ set(SRCS
|
|||||||
TimeZoneNameMap.c
|
TimeZoneNameMap.c
|
||||||
TimeZoneNameMap.h
|
TimeZoneNameMap.h
|
||||||
TimeZoneNameMapUtils.c
|
TimeZoneNameMapUtils.c
|
||||||
|
timezone.c
|
||||||
)
|
)
|
||||||
if (NOT WIN32)
|
if (NOT WIN32)
|
||||||
list(APPEND SRCS
|
list(APPEND SRCS
|
||||||
TimeZoneIanaAbbrevMap.c
|
TimeZoneIanaAbbrevMap.c
|
||||||
TimeZoneIanaAbbrevMap.h
|
TimeZoneIanaAbbrevMap.h
|
||||||
timezone.c
|
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -41,9 +41,7 @@ typedef struct
|
|||||||
const char* Iana;
|
const char* Iana;
|
||||||
} TimeZoneNameMapEntry;
|
} TimeZoneNameMapEntry;
|
||||||
|
|
||||||
extern const TimeZoneNameMapEntry TimeZoneNameMap[];
|
const TimeZoneNameMapEntry* TimeZoneGetAt(size_t index);
|
||||||
extern const size_t TimeZoneNameMapSize;
|
|
||||||
|
|
||||||
const char* TimeZoneIanaToWindows(const char* iana, TimeZoneNameType type);
|
const char* TimeZoneIanaToWindows(const char* iana, TimeZoneNameType type);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <winpr/config.h>
|
#include <winpr/config.h>
|
||||||
#include <winpr/assert.h>
|
#include <winpr/assert.h>
|
||||||
#include <winpr/string.h>
|
#include <winpr/string.h>
|
||||||
|
#include <winpr/synch.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@ -31,6 +32,36 @@
|
|||||||
|
|
||||||
#include "TimeZoneNameMap.h"
|
#include "TimeZoneNameMap.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
size_t count;
|
||||||
|
TimeZoneNameMapEntry* entries;
|
||||||
|
} TimeZoneNameMapContext;
|
||||||
|
|
||||||
|
static BOOL CALLBACK load_timezones(PINIT_ONCE once, PVOID param, PVOID* pvcontext)
|
||||||
|
{
|
||||||
|
// Do not expose these, only used internally.
|
||||||
|
extern const TimeZoneNameMapEntry TimeZoneNameMap[];
|
||||||
|
extern const size_t TimeZoneNameMapSize;
|
||||||
|
|
||||||
|
TimeZoneNameMapContext* context = pvcontext;
|
||||||
|
WINPR_ASSERT(context);
|
||||||
|
|
||||||
|
context->count = TimeZoneNameMapSize;
|
||||||
|
context->entries = TimeZoneNameMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TimeZoneNameMapEntry* TimeZoneGetAt(size_t index)
|
||||||
|
{
|
||||||
|
static INIT_ONCE init_guard = INIT_ONCE_STATIC_INIT;
|
||||||
|
static TimeZoneNameMapContext context = { 0 };
|
||||||
|
|
||||||
|
InitOnceExecuteOnce(&init_guard, load_timezones, NULL, &context);
|
||||||
|
if (index >= context.count)
|
||||||
|
return NULL;
|
||||||
|
return &context.entries[index];
|
||||||
|
}
|
||||||
|
|
||||||
static const char* return_type(const TimeZoneNameMapEntry* entry, TimeZoneNameType type)
|
static const char* return_type(const TimeZoneNameMapEntry* entry, TimeZoneNameType type)
|
||||||
{
|
{
|
||||||
WINPR_ASSERT(entry);
|
WINPR_ASSERT(entry);
|
||||||
@ -51,6 +82,37 @@ static const char* return_type(const TimeZoneNameMapEntry* entry, TimeZoneNameTy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BOOL iana_cmp(const TimeZoneNameMapEntry* entry, const char* iana)
|
||||||
|
{
|
||||||
|
if (!entry || !iana || !entry->Iana)
|
||||||
|
return FALSE;
|
||||||
|
return strcmp(iana, entry->Iana) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL id_cmp(const TimeZoneNameMapEntry* entry, const char* id)
|
||||||
|
{
|
||||||
|
if (!entry || !id || !entry->Id)
|
||||||
|
return FALSE;
|
||||||
|
return strcmp(id, entry->Id) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* get_for_type(const char* val, TimeZoneNameType type,
|
||||||
|
BOOL (*cmp)(const TimeZoneNameMapEntry*, const char*))
|
||||||
|
{
|
||||||
|
WINPR_ASSERT(val);
|
||||||
|
WINPR_ASSERT(cmp);
|
||||||
|
|
||||||
|
size_t index = 0;
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
const TimeZoneNameMapEntry* entry = TimeZoneGetAt(index++);
|
||||||
|
if (!entry)
|
||||||
|
return NULL;
|
||||||
|
if (cmp(entry, val))
|
||||||
|
return return_type(entry, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(WITH_TIMEZONE_ICU)
|
#if defined(WITH_TIMEZONE_ICU)
|
||||||
static char* get_wzid_icu(const UChar* utzid, size_t utzid_len)
|
static char* get_wzid_icu(const UChar* utzid, size_t utzid_len)
|
||||||
{
|
{
|
||||||
@ -88,21 +150,11 @@ static char* get(const char* iana)
|
|||||||
|
|
||||||
static const char* map_fallback(const char* iana, TimeZoneNameType type)
|
static const char* map_fallback(const char* iana, TimeZoneNameType type)
|
||||||
{
|
{
|
||||||
const char* res = NULL;
|
|
||||||
char* wzid = get(iana);
|
char* wzid = get(iana);
|
||||||
if (!wzid)
|
if (!wzid)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (size_t x = 0; x < TimeZoneNameMapSize; x++)
|
const char* res = get_for_type(wzid, type, id_cmp);
|
||||||
{
|
|
||||||
const TimeZoneNameMapEntry* entry = &TimeZoneNameMap[x];
|
|
||||||
if (strcmp(wzid, entry->Id) == 0)
|
|
||||||
{
|
|
||||||
res = return_type(entry, type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(wzid);
|
free(wzid);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -149,22 +201,13 @@ const char* TimeZoneIanaToWindows(const char* iana, TimeZoneNameType type)
|
|||||||
if (!iana)
|
if (!iana)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (size_t x = 0; x < TimeZoneNameMapSize; x++)
|
const char* val = get_for_type(iana, type, iana_cmp);
|
||||||
{
|
if (val)
|
||||||
const TimeZoneNameMapEntry* entry = &TimeZoneNameMap[x];
|
return val;
|
||||||
if (strcmp(iana, entry->Iana) == 0)
|
|
||||||
return return_type(entry, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* wzid = map_fallback(iana, type);
|
const char* wzid = map_fallback(iana, type);
|
||||||
if (!wzid)
|
if (!wzid)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (size_t x = 0; x < TimeZoneNameMapSize; x++)
|
return get_for_type(wzid, type, id_cmp);
|
||||||
{
|
|
||||||
const TimeZoneNameMapEntry* entry = &TimeZoneNameMap[x];
|
|
||||||
if (strcmp(wzid, entry->Id) == 0)
|
|
||||||
return return_type(entry, type);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
@ -710,6 +710,34 @@ BOOL TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformati
|
|||||||
(defined(_WIN32) && (defined(NTDDI_WIN8) && _WIN32_WINNT < 0x0600 || \
|
(defined(_WIN32) && (defined(NTDDI_WIN8) && _WIN32_WINNT < 0x0600 || \
|
||||||
!defined(NTDDI_WIN8) && _WIN32_WINNT < 0x0501)) /* Windows Vista */
|
!defined(NTDDI_WIN8) && _WIN32_WINNT < 0x0501)) /* Windows Vista */
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
HAVE_TRANSITION_DATES = 0,
|
||||||
|
HAVE_NO_STANDARD_TRANSITION_DATE = 1,
|
||||||
|
HAVE_NO_DAYLIGHT_TRANSITION_DATE = 2
|
||||||
|
} dyn_transition_result;
|
||||||
|
|
||||||
|
static int dynamic_time_zone_from_localtime(const struct tm* local_time,
|
||||||
|
PDYNAMIC_TIME_ZONE_INFORMATION tz)
|
||||||
|
{
|
||||||
|
WINPR_ASSERT(local_time);
|
||||||
|
WINPR_ASSERT(tz);
|
||||||
|
int rc = HAVE_TRANSITION_DATES;
|
||||||
|
|
||||||
|
tz->Bias = get_bias(local_time, FALSE);
|
||||||
|
if (local_time->tm_isdst >= 0)
|
||||||
|
{
|
||||||
|
/* DST bias is the difference between standard time and DST in minutes */
|
||||||
|
const LONG d = get_bias(local_time, TRUE);
|
||||||
|
tz->DaylightBias = -1 * labs(tz->Bias - d);
|
||||||
|
if (!get_transition_date(local_time, FALSE, &tz->StandardDate))
|
||||||
|
rc |= HAVE_NO_STANDARD_TRANSITION_DATE;
|
||||||
|
if (!get_transition_date(local_time, TRUE, &tz->DaylightDate))
|
||||||
|
rc |= HAVE_NO_DAYLIGHT_TRANSITION_DATE;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
DWORD GetDynamicTimeZoneInformation(PDYNAMIC_TIME_ZONE_INFORMATION tz)
|
DWORD GetDynamicTimeZoneInformation(PDYNAMIC_TIME_ZONE_INFORMATION tz)
|
||||||
{
|
{
|
||||||
BOOL doesNotHaveStandardDate = FALSE;
|
BOOL doesNotHaveStandardDate = FALSE;
|
||||||
@ -734,12 +762,10 @@ DWORD GetDynamicTimeZoneInformation(PDYNAMIC_TIME_ZONE_INFORMATION tz)
|
|||||||
tz->Bias = get_bias(local_time, FALSE);
|
tz->Bias = get_bias(local_time, FALSE);
|
||||||
if (local_time->tm_isdst >= 0)
|
if (local_time->tm_isdst >= 0)
|
||||||
{
|
{
|
||||||
/* DST bias is the difference between standard time and DST in minutes */
|
const int rc = dynamic_time_zone_from_localtime(local_time, tz);
|
||||||
const LONG d = get_bias(local_time, TRUE);
|
if (rc & HAVE_NO_STANDARD_TRANSITION_DATE)
|
||||||
tz->DaylightBias = -1 * labs(tz->Bias - d);
|
|
||||||
if (!get_transition_date(local_time, FALSE, &tz->StandardDate))
|
|
||||||
doesNotHaveStandardDate = TRUE;
|
doesNotHaveStandardDate = TRUE;
|
||||||
if (!get_transition_date(local_time, TRUE, &tz->DaylightDate))
|
if (rc & HAVE_NO_DAYLIGHT_TRANSITION_DATE)
|
||||||
doesNotHaveDaylightDate = TRUE;
|
doesNotHaveDaylightDate = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -817,14 +843,62 @@ BOOL TzSpecificLocalTimeToSystemTimeEx(const DYNAMIC_TIME_ZONE_INFORMATION* lpTi
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(_WIN32) || (defined(_WIN32) && (_WIN32_WINNT < 0x0602)) /* Windows 8 */
|
#if !defined(_WIN32)
|
||||||
|
|
||||||
DWORD EnumDynamicTimeZoneInformation(const DWORD dwIndex,
|
DWORD EnumDynamicTimeZoneInformation(const DWORD dwIndex,
|
||||||
PDYNAMIC_TIME_ZONE_INFORMATION lpTimeZoneInformation)
|
PDYNAMIC_TIME_ZONE_INFORMATION lpTimeZoneInformation)
|
||||||
{
|
{
|
||||||
WINPR_UNUSED(dwIndex);
|
if (!lpTimeZoneInformation)
|
||||||
WINPR_UNUSED(lpTimeZoneInformation);
|
return ERROR_INVALID_PARAMETER;
|
||||||
return 0;
|
const DYNAMIC_TIME_ZONE_INFORMATION empty = { 0 };
|
||||||
|
*lpTimeZoneInformation = empty;
|
||||||
|
|
||||||
|
const TimeZoneNameMapEntry* entry = TimeZoneGetAt(dwIndex);
|
||||||
|
if (!entry)
|
||||||
|
return ERROR_NO_MORE_ITEMS;
|
||||||
|
|
||||||
|
if (entry->DaylightName)
|
||||||
|
ConvertUtf8ToWChar(entry->DaylightName, lpTimeZoneInformation->DaylightName,
|
||||||
|
ARRAYSIZE(lpTimeZoneInformation->DaylightName));
|
||||||
|
if (entry->StandardName)
|
||||||
|
ConvertUtf8ToWChar(entry->StandardName, lpTimeZoneInformation->StandardName,
|
||||||
|
ARRAYSIZE(lpTimeZoneInformation->StandardName));
|
||||||
|
if (entry->Id)
|
||||||
|
ConvertUtf8ToWChar(entry->Id, lpTimeZoneInformation->TimeZoneKeyName,
|
||||||
|
ARRAYSIZE(lpTimeZoneInformation->TimeZoneKeyName));
|
||||||
|
|
||||||
|
const time_t t = time(NULL);
|
||||||
|
struct tm tres = { 0 };
|
||||||
|
|
||||||
|
const char* tz = getenv("TZ");
|
||||||
|
char* tzcopy = NULL;
|
||||||
|
if (tz)
|
||||||
|
{
|
||||||
|
size_t tzianalen = 0;
|
||||||
|
winpr_asprintf(&tzcopy, &tzianalen, "TZ=%s", tz);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* tziana = NULL;
|
||||||
|
{
|
||||||
|
size_t tzianalen = 0;
|
||||||
|
winpr_asprintf(&tziana, &tzianalen, "TZ=%s", entry->Iana);
|
||||||
|
}
|
||||||
|
if (tziana)
|
||||||
|
putenv(tziana);
|
||||||
|
|
||||||
|
tzset();
|
||||||
|
struct tm* local_time = localtime_r(&t, &tres);
|
||||||
|
free(tziana);
|
||||||
|
if (tzcopy)
|
||||||
|
putenv(tzcopy);
|
||||||
|
else
|
||||||
|
unsetenv("TZ");
|
||||||
|
free(tzcopy);
|
||||||
|
|
||||||
|
if (local_time)
|
||||||
|
dynamic_time_zone_from_localtime(local_time, lpTimeZoneInformation);
|
||||||
|
|
||||||
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD GetDynamicTimeZoneInformationEffectiveYears(
|
DWORD GetDynamicTimeZoneInformationEffectiveYears(
|
||||||
@ -833,7 +907,24 @@ DWORD GetDynamicTimeZoneInformationEffectiveYears(
|
|||||||
WINPR_UNUSED(lpTimeZoneInformation);
|
WINPR_UNUSED(lpTimeZoneInformation);
|
||||||
WINPR_UNUSED(FirstYear);
|
WINPR_UNUSED(FirstYear);
|
||||||
WINPR_UNUSED(LastYear);
|
WINPR_UNUSED(LastYear);
|
||||||
return 0;
|
return ERROR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#elif _WIN32_WINNT < 0x0602 /* Windows 8 */
|
||||||
|
DWORD EnumDynamicTimeZoneInformation(const DWORD dwIndex,
|
||||||
|
PDYNAMIC_TIME_ZONE_INFORMATION lpTimeZoneInformation)
|
||||||
|
{
|
||||||
|
WINPR_UNUSED(dwIndex);
|
||||||
|
WINPR_UNUSED(lpTimeZoneInformation);
|
||||||
|
return ERROR_NO_MORE_ITEMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD GetDynamicTimeZoneInformationEffectiveYears(
|
||||||
|
const PDYNAMIC_TIME_ZONE_INFORMATION lpTimeZoneInformation, LPDWORD FirstYear, LPDWORD LastYear)
|
||||||
|
{
|
||||||
|
WINPR_UNUSED(lpTimeZoneInformation);
|
||||||
|
WINPR_UNUSED(FirstYear);
|
||||||
|
WINPR_UNUSED(LastYear);
|
||||||
|
return ERROR_FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user