将时间转换为UTC vbScript

时间:2013-02-19 04:10:24

标签: datetime vbscript asp-classic timezone utc

我有以下功能,可以将当前时间转换为UTC时间。

Function toUtc(byVal dDate)
    Dim oShell : Set oShell = CreateObject("WScript.Shell")
    toUtc = dateadd("n", oShell.RegRead("HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\TimeZoneInformation\ActiveTimeBias"), cDate(dDate))
End Function

但是,我认为这不能充分处理将来或历史日期转换为UTC,因为该函数需要知道转换日期时服务器时区的偏移量,以及是否或不是在白天节省时间。

我怎样才能解决这个问题?

我在带有IIS7.5的Windows服务器上使用vbScript / Classic ASP

澄清一下,这与格式化日期无关。它是关于从服务器时区转换为UTC历史日期的全部内容。在夏令时期间,如果我尝试转换标准时间内发生的日期时间,则偏移量将减少60分钟。

例如:

让我们说今天,2013-02-19(非夏令时),我想把时间戳从2008-06-05(夏令时期间)从PDT(我的服务器时区)转换为UTC 。使用我函数中的方法将给出一个与正确值相差60分钟的值(因为当前时间是PST(不是PDT),该历史日期的偏移量将不正确)。

换句话说,输入日期的时区偏移量可以是UTC-7或UTC-8,具体取决于是否在该特定日期观察到DST。我需要计算输入日期的正确UTC日期,无论是否在当前日期观察到DST,我都需要使用该代码。

4 个答案:

答案 0 :(得分:4)

这是我在@AardVark71的建议下最终实现的解决方案。

我把它放在我的func.asp文件中:

<script language="javascript" runat="server">
    function toUtcString(d) {
        var dDate = new Date(d);
        return Math.round(dDate.getTime() / 1000);
    };
</script>

它输出时间戳值。然后从经典的asp代码中的任何地方,我都可以这样做:

response.Write DateAdd("s", toUtcString(cDate("11/11/2012 06:25 PM")), "01/01/1970 00:00:00") 'expect 11/11/2012 10:25:00 PM gmt/utc time
response.Write DateAdd("s", toUtcString(cDate("06/11/2012 06:25 PM")), "01/01/1970 00:00:00") 'expect  6/11/2012  9:25:00 PM gmt/utc time

这(我相信)很简单,它会在DST中产生预期值和完全因子。

答案 1 :(得分:1)

在ASP classic中,您可以在一个页面内混合使用VBScript和JScript代码。 JScript Date对象可用于本地⇄UTC日期转换。完整的例子:

<%@ language="vbscript" %>
<%
Option Explicit
Dim local_date
Dim utc_date
For Each local_date In Array("11/11/2012 06:25 PM", "06/11/2012 06:25 PM")
    utc_date = local_to_utc(local_date)
    Response.Write "Local: " & local_date & ", UTC: " & utc_date & vbNewLine
Next
For Each utc_date In Array("2012-11-12T02:25:00Z", "2012-06-12T01:25:00+00:00")
    local_date = utc_to_local(utc_date)
    Response.Write "UTC: " & utc_date & ", Local: " & local_date & vbNewLine
Next
%>
<script language="jscript" runat="server">
    function local_to_utc(datestr) {
        // note that this function lets JScript engine parse the date, correctly or otherwise
        var date = new Date(datestr);
        var result = date.getUTCFullYear() + "-" + (date.getUTCMonth() + 1) + "-" + date.getUTCDate() + "T" + date.getUTCHours() + ":" + date.getUTCMinutes() + ":" + date.getUTCSeconds();
        return result.replace(/(\D)(\d)(?!\d)/g, "$10$2") + "Z";
    }
    function utc_to_local(datestr) {
        // note that this function parses only a subset of ISO 8601 date format
        var match = datestr.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{3}))?(?:Z|([-+])(\d{2}):(\d{2}))$/);
        var offset = match[8] ? (match[8] === "+" ? 1 : -1) * (match[9] * 60 + match[10] * 1) : 0;
        var date = new Date(Date.UTC(match[1], match[2] - 1, match[3], match[4], match[5] - offset, match[6], match[7] || 0));
        var result = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate() + " " + date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds();
        return result.replace(/(\D)(\d)(?!\d)/g, "$10$2");
    }
</script>

预期结果:

使用PST / PDT时间在服务器上执行时的输出:

Local: 11/11/2012 06:25 PM,       UTC:   2012-11-12T02:25:00Z
Local: 06/11/2012 06:25 PM,       UTC:   2012-06-12T01:25:00Z
UTC:   2012-11-12T02:25:00Z,      Local: 2012-11-11 18:25:00
UTC:   2012-06-12T01:25:00+00:00, Local: 2012-06-11 18:25:00

答案 2 :(得分:0)

如果我没有错过任何东西,你需要在远程机器上获得当地时间和时区偏移,对吗?

Here我看到基于WMI Win32_TimeZone Bias属性的自我回答。但根据MSDN示例:“Converting Local Time to UTC Time”,引用:

  

使用Win32_ComputerSystem CurrentTimeZone属性,因为它   自动调整夏令时的时区偏差   Win32_TimeZone偏置属性没有。

因此,下一个示例函数获取当前日期时间,我将留给您修改具体的日期时间。

' "." mean local computer
WScript.Echo FormatDateTime(UTCDate("."), 0)

Function UTCDate(strComputer)
    Dim objWMIService, ColDate, ColCS

    On Error Resume Next
    Set objWMIService = _
        GetObject("winmgmts:{impersonationLevel=impersonate}!\\" _
        & strComputer & "\root\cimv2")

    Set ColDate = objWMIService.ExecQuery("Select * From Win32_LocalTime")

    UTCDate = DateSerial(100, 1, 1)
    For Each objDate In ColDate
        UTCDate = DateAdd("yyyy", ObjDate.Year - 100, UTCDate)
        UTCDate = DateAdd("m", ObjDate.Month - 1, UTCDate)
        UTCDate = DateAdd("d", ObjDate.Day - 1, UTCDate)
        UTCDate = DateAdd("h", ObjDate.Hour, UTCDate)
        UTCDate = DateAdd("n", ObjDate.Minute, UTCDate)
        UTCDate = DateAdd("s", ObjDate.Second, UTCDate)
    Next

    ' http://msdn.microsoft.com/en-us/library/windows/desktop/ms696015(v=vs.85).aspx
    Set ColCS = objWMIService.ExecQuery("Select * From Win32_ComputerSystem")

    Dim TimeZoneOffset, LocalTimeZone
    For Each LocalTimeZone In ColCS
        TimeZoneOffset = LocalTimeZone.CurrentTimeZone
    Next

    If TimeZoneOffset < 0 Then
        TimeZoneOffset = Abs(TimeZoneOffset)
    Else
        TimeZoneOffset = -Abs(TimeZoneOffset)
    End If

    UTCDate = DateAdd("n", TimeZoneOffset, UTCDate)
    If Err Then UTCDate = vbNull
    Set objWMIService = Nothing
End Function

[编辑]好吧,看起来不应该信任MSDN(或者这可能仅适用于当前时间)。但是,我发现这不是你要找的答案。如果您没有找到更好的主意,可以自动执行此online calculator

P.S。好的,敲击上面的代码然后尝试另一个“迭代”。

请注意,我制作的代码与我的时区(保加利亚)兼容,PDT从3月的最后一个星期日开始,到10月的最后一个星期日结束。这让我可以轻松设置我的PDT范围。不久,我们的想法是使算法适用于您所在的地区。其余的显然是,我希望。

With New DateDrill
    Debug.WriteLine .UTCDate("2008-6-28")
    Debug.WriteLine .UTCDate("2014-1-21")
End With

Class DateDrill

    Public Function UTCDate(ByVal dtDate)
        If Not IsDate(dtDate) Then Err.Raise 5
        dtDate = CDate(dtDate)
        Dim ZoneBias: ZoneBias = TimeZoneBias()
        If IsPDT(Now) <> IsPDT(dtDate) Then
            ZoneBias = ZoneBias - 60
        End If
        UTCDate = DateAdd("n", ZoneBias, dtDate)
    End Function

    Private Function IsPDT(ByVal dtDate)
        If Not IsDate(dtDate) Then Err.Raise 5
        dtDate = CDate(dtDate)
        Dim pdtLow, pdtUpr, nDaysBack

        pdtLow = DateSerial(Year(dtDate),  3, 31)
        pdtUpr = DateSerial(Year(dtDate), 10, 31)
        pdtLow = DateAdd("h", 2, pdtLow)
        pdtUpr = DateAdd("h", 2, pdtUpr)

        nDaysBack = Weekday(pdtLow) - 1
        If nDaysBack <> 0 Then
            pdtLow = DateAdd("d", -nDaysBack, pdtLow)
        End If

        nDaysBack = Weekday(pdtUpr) - 1
        If nDaysBack <> 0 Then
            pdtUpr = DateAdd("d", -nDaysBack, pdtUpr)
        End If

        IsPDT = (dtDate >= pdtLow And dtDate <= pdtUpr)
    End Function

    Private Function TimeZoneBias()
        Dim LTZone
        With GetObject("winmgmts:" & _
                "{impersonationLevel=impersonate}!\\.\root\cimv2")
            For Each LTZone In .ExecQuery(_
                    "Select * From Win32_ComputerSystem")
                TimeZoneBias = LTZone.CurrentTimeZone
            Next
        End With
        TimeZoneBias = TimeZoneBias * -1
    End Function

End Class

答案 3 :(得分:0)

这个少量的ASP VBScript函数可以满足您的需要。我正在从MySQL数据库绘制Unix时间戳。根据您的数据库,查询可能会稍有不同,但是大多数DB可以返回Unix时间戳。在我的服务器上,查询只需要一到两毫秒。

注意:pquery是我自己的用于运行SQL查询的函数。显然可以替代您自己的方法。

每次unixTime()运行时,我都在计算偏移量。当然,您可以在“ bootstrap”文件中计算一次,并根据需要设置全局变量。

Function unixTimestamp()
    ' Unix Timestamp, drawn from MySQL because ASP doesn't natively handle time zones
    rs = pquery( "SELECT unix_timestamp() AS `ts`", null )
    unixTimestamp = cLng( rs("ts") )
End Function

Function utc_offset()
    ' Offset of Server time from UTC, in seconds
    dim unixNow : unixNow = unixTimestamp()
    dim aspNow  : aspNow  = cLng( DateDiff( "s", "01/01/1970 00:00:00", now() ) )
    utc_offset = cLng( ( aspNow - unixNow ))
End Function

Function unixTime( byVal dt )
    dim offset : offset = utc_offset()
    if( VarType( dt ) = vbDate ) then
        unixTime = cLng( DateDiff( "s", "01/01/1970 00:00:00", dt ) - offset )
    else
        if( isDate( dt ) ) then
            dt = cDate( dt )
            unixTime = cLng( DateDiff( "s", "01/01/1970 00:00:00", dt ) - offset )
        else
            unixTime = null
        end if
    end if
End Function

Function datetimeFromUnix( byVal udt, offset )
    datetimeFromUnix = cDate( DateAdd( "s", udt + offset , "01/01/1970 00:00:00" ) )
End Function

现在运行:

utcTimestamp = unixTime( dDate )
utcDate = datetimeFromUnix( utcTimestamp, 0 )   ' UTC
localDate = datetimeFromUnix( utcTimestamp, utc_offset() )  ' back where we started