VB. Как узнать свой часовой пояс (смещение относительно UTC)
Задача:
Необходимо узнать свой часовой пояс - смещение своего времени относительно времени UTC в Visual Basic или в Visual Basic for Applications, то есть получить циферку с плюсом или минусом означающую на сколько местные часы сдвинуты относительно универсального координированного времени UTC (всемирного времени).
Решение:
Основной проблемой является то, что, как ни странно, ни в VB, ни в VBA нет такой функции, чтобы узнать свой часовой пояс. Поэтому приходится пользоваться Windows API функцией GetTimeZoneInformation.
Visual Basic код взят отсюда. Полный модуль bas, включающий в себя еще несколько функций для работы с часовыми поясами можно скачать здесь или прямо отсюда:
Итак, приступим (для примера будем работать в MS Excel Visual Basic for Applications):
-
Создаем в рабочей книге MS Excel модуль (если его еще нет)
-
Вставляем в этот модуль
VBA код:
Код: Выделить всё
Option Explicit Option Compare Text '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' modTimeZones ' By Chip Pearson, chip@cpearson.com, www.cpearson.com ' Date: 2-April-2008 ' Page Specific URL: www.cpearson.com/Excel/TimeZoneAndDaylightTime.aspx ' ' This module contains functions related to time zones and GMT times. ' Terms: ' ------------------------- ' GMT = Greenwich Mean Time. Many applications use the term ' UTC (Universal Coordinated Time). GMT and UTC are ' interchangable in meaning, ' Local Time = The local "wall clock" time of day, that time that ' you would set a clock to. ' DST = Daylight Savings Time ' Functions In This Module: ' ------------------------- ' LocalOffsetFromGMT ' Returns the number of minutes or hours that are to be added to ' the local time to get GMT. Optionally adjusts for DST. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Private Type SYSTEMTIME wYear As Integer wMonth As Integer wDayOfWeek As Integer wDay As Integer wHour As Integer wMinute As Integer wSecond As Integer wMilliseconds As Integer End Type Private Type TIME_ZONE_INFORMATION Bias As Long StandardName(0 To 31) As Integer StandardDate As SYSTEMTIME StandardBias As Long DaylightName(0 To 31) As Integer DaylightDate As SYSTEMTIME DaylightBias As Long End Type Public Enum TIME_ZONE TIME_ZONE_ID_INVALID = 0 TIME_ZONE_STANDARD = 1 TIME_ZONE_DAYLIGHT = 2 End Enum ''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Required Windows API Declares ''''''''''''''''''''''''''''''''''''''''''''''''''''' #If Win64 Then #If VBA7 Then ' Windows x64, Office 2010 Private Declare PtrSafe Function GetTimeZoneInformation Lib "kernel32" _ (lpTimeZoneInformation As TIME_ZONE_INFORMATION) As Long Private Declare PtrSafe Sub GetSystemTime Lib "kernel32" _ (lpSystemTime As SYSTEMTIME) #Else ' Windows x64,Office 2003-2007 Private Declare Function GetTimeZoneInformation Lib "kernel32" _ (lpTimeZoneInformation As TIME_ZONE_INFORMATION) As Long Private Declare Sub GetSystemTime Lib "kernel32" _ (lpSystemTime As SYSTEMTIME) #End If #Else #If VBA7 Then ' Windows x86, Office 2010 Private Declare PtrSafe Function GetTimeZoneInformation Lib "kernel32" _ (lpTimeZoneInformation As TIME_ZONE_INFORMATION) As Long Private Declare PtrSafe Sub GetSystemTime Lib "kernel32" _ (lpSystemTime As SYSTEMTIME) #Else ' Windows x86, Office 2003-2007 Private Declare Function GetTimeZoneInformation Lib "kernel32" _ (lpTimeZoneInformation As TIME_ZONE_INFORMATION) As Long Private Declare Sub GetSystemTime Lib "kernel32" _ (lpSystemTime As SYSTEMTIME) #End If #End If Public Function LocalOffsetFromGMT(Optional AsHours As Boolean = False, _ Optional AdjustForDST As Boolean = False) As Long ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' LocalOffsetFromGMT ' This returns the amount of time in minutes (if AsHours is omitted or ' false) or hours (if AsHours is True) that should be added to the ' local time to get GMT. If AdjustForDST is missing or false, ' the unmodified difference is returned. (e.g., Kansas City to London ' is 6 hours normally, 5 hours during DST. If AdjustForDST is False, ' the resultif 6 hours. If AdjustForDST is True, the result is 5 hours ' if DST is in effect.) ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Dim TBias As Long Dim TZI As TIME_ZONE_INFORMATION Dim DST As TIME_ZONE DST = GetTimeZoneInformation(TZI) If DST = TIME_ZONE_DAYLIGHT Then If AdjustForDST = True Then TBias = -(TZI.Bias + TZI.DaylightBias) Else TBias = -TZI.Bias End If Else TBias = -TZI.Bias End If If AsHours = True Then TBias = TBias / 60 End If LocalOffsetFromGMT = TBias End Function
-
Пользуемся созданной нами функцией LocalOffsetFromGMT() в любом месте этой рабочей книги MS Excel (или вообще из любой рабочей книги MS Excel, если модуль сохранен в личной книге макросов).
Пример:
Необходимо конвертировать дату и время (в формате Unix Datestamp) установки MS Windows, полученное из реестра HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\InstallDate и помещенное в ячейку «A2» в обычный удобочитаемый формат, при этом учесть часовой пояс системы.
О том, как конвертировать из Unix Datestamp в формат MS Excel читаем здесь.
Остается только добавить в формулу поправку на наш часовой пояс. Но, поскольку функция LocalOffsetFromGMT() возвращает значение в минутах, а расчет в формуле в ячейке ведется в днях, то мы должны конвертировать это значение в дни, для чего используем коэффициент 60*24=1440.
Итак, окончательная формула в ячейке «A4» будет выглядеть так:
Код: Выделить всё
=A2/86400+LocalOffsetFromGMT()/1440+ДАТА(1970;1;1)
где:
-
A2 - адрес ячейки с временем в формате Unix Timestamp
-
86400 - коэффициент, равный количеству секунд в одних сутках
-
ДАТА(1970;1;1) - дата 01 января 1970 года, с которой ведется отсчет Unix Timestamp