6

我有以下函数可以很好地将当前时间转换为 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

4 回答 4

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 中的预期值和全部因素。

于 2013-02-20T00:10:10.300 回答
1

在 ASP 经典中,您可以在一页内混合 VBScript 和 JScript 代码。JScriptDate对象可用于本地⇄ 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
于 2018-05-08T21:07:20.543 回答
0

如果我没有错过什么,你需要在远程机器上获取本地时间和时区偏移,对吧?

在这里,我看到了基于WMI Win32_TimeZone Bias属性的自我回答。但根据这个 MSDN 示例:“将本地时间转换为 UTC 时间”,引用:

使用 Win32_ComputerSystem CurrentTimeZone 属性,因为它会自动调整夏令时的时区偏差 Win32_TimeZone Bias 属性不会。

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

' "." 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(或者也许这仅适用于当前时间)。但是,我认为这不是您要寻找的答案。如果你没有找到更好的主意,你可以自动化这个在线计算器

PS 好的,删除上面的代码,让我们尝试另一个“迭代”。

请注意,我制作的代码与我的时区(保加利亚)兼容,其中 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
于 2013-02-19T17:14:28.267 回答
0

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

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

我正在计算每次unixTime()运行的偏移量。如果您愿意,您当然可以在“引导”文件中计算一次并设置一个全局变量。

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
于 2019-08-23T01:09:00.283 回答