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/ClassicASPを使用しています

明確にするために、これは日付のフォーマットとは何の関係もありません。履歴日付のサーバータイムゾーンからUTCに変換することがすべてです。夏時間の間に、標準時間で発生した日時を変換しようとすると、オフセットが60分ずれます。

例えば:

今日、2013-02-19(夏時間以外の時間)、たとえば2008-06-05(夏時間中)のタイムスタンプをPDT(サーバーのタイムゾーン)からUTCに変換するとします。関数でこのメソッドを使用すると、正しい値から60分ずれた値が得られます(現在の時刻はPST(PDTではない)であるため、その過去の日付のオフセットは正しくありません)。

つまり、入力日のタイムゾーンオフセットは、その特定の日付にDSTが観測されたかどうかに応じて、UTC-7またはUTC-8になる可能性があります。入力日の正しい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クラシックでは、1ページに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_TimeZoneBiasプロパティは調整しません。

したがって、次の例の関数は現在の日時を取得します。具体的な日時の測定のために変更するのはあなたに任せます。

' "." 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 OK、上記のコードを削除して、別の「反復」を試してみましょう。

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

このASPVBScript関数の小さなコレクションは、必要なことを実行する可能性があります。MySQLデータベースからUnixタイムスタンプを描画しています。データベースによってはクエリが少し異なる場合がありますが、ほとんどのDBはUnixタイムスタンプを返すことができます。私のサーバーでは、クエリは1〜2ミリ秒しかかかりません。

注:pqueryはSQLクエリを実行するための私自身の関数です。明らかにあなた自身の方法で代用してください。

実行するたびにオフセットを計算していunixTime()ます。もちろん、「ブートストラップ」ファイルで1回計算し、必要に応じてグローバル変数を設定することもできます。

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 に答える